AndreiM
AndreiM

Reputation: 876

When to use parentheses on method declaration?

If I declare a method with no parameters and then call it (in F#-interactive), then I get the expected behaviour: "test" is displayed on screen.

let somefn() = 
    printfn "test"
> 
val somefn : unit -> unit

> somefn();;
test
val it : unit = ()

However, If I declare the method without parentheses, then I get some different behavior:

let somefn = 
    printfn "test"
> 
test
val somefn : unit = ()

> somefn;;
val it : unit = ()

> somefn();;

  somefn();;
  ^^^^^^

C:\...\Local\Temp\stdin(4,1): error FS0003: This value is not a function and cannot be applied.

So what I don't understand:

  1. Why is method declaration without parameters so different than with parameters?
  2. When I declare without parentheses, I got the message: val somefn : unit = (). What does it mean unit = ()? What exactly did I declared now? What sort of entity is somefn now?
  3. It is obviously that now there's an entity called somefn, which points to some executable code. How can I execute that code? can I declare somefn as member of a struct or something and execute it from there?

Upvotes: 2

Views: 256

Answers (1)

TheQuickBrownFox
TheQuickBrownFox

Reputation: 10624

The comments above answer this question but I'll add some detail.

When you define a function, each parameter is actually a pattern match with only one case. For example you could write:

let somefn 0 = 1

The type of this function is int -> int. The first parameter is inferred to be an int, but this generates a warning because there are other ints that are not being matched on. somefn 0 returns 1, but somefn 1 throws an exception "The match cases were incomplete".

The type unit has only one value: (). It's effectively as a "nothing" value for the input or an output of a function. It has a pattern match that looks exactly like the value (just like [] for an empty list), which is why you can add a unit parameter to any function using (). These functions are all exactly the same:

let somefn () = ()
let somefn (x:unit) = ()
let somefn (_:unit) = ()

When you write a function that doesn't take any parameters, you just add a single unit parameter so that it's a function and not a value, and therefore you delay its execution. Just to drive the point home, you could even add more than one unit parameter, although you would never need to do this:

let somefn () () = ()
// unit -> unit -> unit

Upvotes: 7

Related Questions