Consider the following code:
type Test () =
member o.fn1 (?bo) = 1
member o.fn2 (?bo) = o.fn1 bo
member o.fn3 (?bo) = 1 + bo.Value
member o.fn4 (?bo) = o.fn3 bo
While fn1
and fn2
work just fine, fn4
produces the following error:
init.fsx(6,30): error FS0001: This expression was expected to have type int but here has type 'a option
MSDN states:
Optional parameters are interpreted as the F# option type, so you can query them in the regular way that option types are queried, by using a match expression with Some and None.
To me, optional parameters are not interpreted as the F# option type otherwise the code would compile. Moreover I do not understand why, when I hover over ?bo
in fn3
the tooltip says val bo: int option
but from outside expects only int
. I would expect a behavior of accepting nothing, int, Some int and None. And as the last note, I do not understand why fn2
works but fn4
does not.
Thanks for clarification
I have to reconsider the correct answer. Based on this question (and answer):
Propagating optional arguments
it seams that the correct answer is the following:
type Test () =
member o.fn1 (?bo) = 1
member o.fn2 (?bo) = o.fn1 bo
member o.fn3 (?bo) = 1 + bo.Value
member o.fn4 (?bo) = o.fn3 (?bo = bo)
It is a neat feature and credits for the answer go to desco!
fn2
works because fn1
does not use its parameter, which is thus generic 'b option
.
type Test () =
member o.fn1 (?bo1) = 1 --> bo1: 'b option, here 'b = 'a option
member o.fn2 (?bo) = o.fn1 bo -->bo: 'a option
fn4
complains that the parameter passed to fn3
should be an int, but not int option
because when you specify the parameter, you of course need to pass in a specific one. But you have the option to omit the parameter. The definition/type signature of fn3
does not know whether you have specify bo
or not, so it is a int option
. Notice that you may have the following usage:
type Test () =
member o.fn1 (?bo) = 1
member o.fn2 (?bo) = o.fn1 bo
member o.fn3 (?bo) =
match bo with
| Some v -> 1 + bo.Value
| None -> 1
member o.fn4 (?bo) = o.fn3()
where you don't specify the parameter for fn3
, but when you specify it, it is a concrete int
, not int option
.
Think about a plotting function with three parameters:
let plot(?x,?y,?color)
because the parameters are optional, you can have the following usage:
plot(data)
plot(y=data)
plot(x=data, color='r')
But not:
plot(Some data)
plot(y=Some data)
plot(x=Some data, color=Some 'r')