What's the type of an optional parameter?

Functions in the language I'm building may have optional parameters, i.e. parameters that may or may not be supplied by the caller.

In Common Lisp, unsupplied optional parameters receive NIL as their value. I want to avoid NIL, because I'd like to add an optional type system to the language later, and I don't want to have NIL as a value that's "in every type".

So I've thought of making the type of optional parameters be like Haskell's Maybe: when the parameter is supplied with a value X, the function body receives it as Just X, and when the parameter is not supplied, it's Nothing (this means that for optional parameters, matching against Just or Nothing is always required in the function body).

Thoughts?

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

This is...

...basically what Ocaml does:

# let optfun ?foo () =
    match foo with
    | None -> 5
    | Some n -> n;;

val optfun : ?foo:int -> unit -> int = 

Alternately, you can supply a default:

# let optfun ?(foo=5) () = foo;;

val optfun : ?foo:int -> unit -> int = 

Personally, I'm not a big fan of optional or named arguments. First, it makes typechecking significantly more complicated. Second, it is both redundant with, and less flexible than, a good record system. In particular, if you support functional record update then named arguments are redundant.

type args = {foo:int; bar:int option}
let default = {foo = 5; bar = None}

let recfun args =
  match args.bar with
  | None -> args.foo + 5
  | Some n -> args.foo + n 

(* Now you can just pass in the default record, updating just the
   fields you want a different value in: *)

# recfun {default with foo = 15};;
- : int = 20

(* You can also create other default records! *)

let default' = {foo = 11; bar = Some 8}

# recfun default'
- : int = 19

Only if your argument defaulting is weak

Second, it is both redundant with, and less flexible than, a good record system. In particular, if you support functional record update then named arguments are redundant.

Certainly this is not the case with Common Lisp's keyword arguments. The default values for omitted arguments (optional or keyword) are computed at function-call time, and may depend on the value of other (supplied or defaulted) arguments. You can't do that (just) with a functional record update.

Common Lisp also allows a function to detect (using `supplied-p' arguments) whether an argument was omitted, which is also not possible using records (though a `maybe' type allows this).

The Lisp approach

In Common Lisp, unsupplied optional parameters receive NIL as their value. I want to avoid NIL, because I'd like to add an optional type system to the language later, and I don't want to have NIL as a value that's "in every type".

Optional parameters are only filled in as NIL if you don't provide an explicit default -- which may be any form and is evaluated in an environment containing all the parameters leftward of this one.

Common Lisp already has an optional type system which doesn't include NIL in every type. If you want to allow a variable to contain NIL, you have to give it a type (OR mumble NULL) unless `mumble' already includes NIL, because it's BOOLEAN, LIST, SYMBOL, or something like that).