Reputation: 4758
I am just starting with F#, and I found the behavior displayed below puzzling. Any explanations?
let bg = bigint 1;;
(* val bg : System.Numerics.BigInteger = 1 *)
let bg = (bigint) 1;;
(* error FS0041: A unique overload for method 'BigInteger' could not be determined based on type information prior to this program point. A type annotation may be needed. Candidates: System.Numerics.BigInteger(value: byte []) : unit, System.Numerics.BigInteger(value: decimal) : unit, System.Numerics.BigInteger(value: float) : unit, System.Numerics.BigInteger(value: float32) : unit, System.Numerics.BigInteger(value: int) : unit, System.Numerics.BigInteger(value: int64) : unit, System.Numerics.BigInteger(value: uint32) : unit, System.Numerics.BigInteger(value: uint64) : unit *)
Upvotes: 4
Views: 110
Reputation: 80805
That's because of overloading. See, bigint
is actually a synonym for the BigInteger
class, and applying it like a function translates into calling a constructor, but which one of the several constructors depends on the type of the argument.
This works fine when you're applying it like a function: the type of the argument is known, and the compiler can select the appropriate overload. But if you're trying to treat it as a function-value, the argument is absent, and the compiler doesn't know which overload to take.
Here's a simpler repro:
type T() =
member static f (s: string) = s
member static f (i: int) = I
let a = T.f 1 // works
let b = T.f "abc" // works
let c = T.f // doesn't work: which `f` do you mean?
// possible workaround: create non-overloaded wrappers
let fStr (s: string) = T.f s
let fInt (i: int) = T.f i
let a = fStr // works fine
let b = fInt // works fine, too
Conclusion: overloading is bad, don't use it. But if you're stuck using it, just stuck it up. Or use a workaround.
(in response to comment)
The parentheses tell the compiler: "first thing, calculate this expression inside the parentheses, then take the result and do the rest with it". So that putting a thing in parentheses is semantically equivalent to giving it a name, e.g.:
// Original repro:
let a = (bigint) 5
// Same thing:
let f = bigint
let a = f 5
Or another way to phrase the same idea: because the function argument is not present inside the parentheses, it cannot be used to evaluate the expression inside the parentheses; and because there is no argument, there is no way to resolve the overload.
Upvotes: 6