Consider the following sample code where I have a generic type and 2 static member constructors that create a specialized instance of the said type.
type Cell<'T> = { slot: 'T }
with
static member CreateInt x : IntCell = { slot = x }
static member CreateString x : StringCell = { slot = x}
and IntCell = Cell<int>
and StringCell = Cell<string>
// Warnings on the next 2 lines
let x = Cell.CreateInt 123
let y = Cell.CreateString "testing"
I think I have the necessary type annotations in place and yet F# gives me warnings. E.g:
Warning 2 The instantiation of the generic type 'Cell' is missing and can't be inferred from the arguments or return type of this member. Consider providing a type instantiation when accessing this type, e.g. 'Cell<_>'.
How can I make the warning go away?
As hinted by @ildjarn, Cell
is a generic type and the compiler wants to know the type 'T
when calling the static member.
// Two ways to fix the compiler warning
let x = Cell<int>.CreateInt 123
let y = StringCell.CreateString "testing"
A way to avoid specifying 'T
is to move the create functions into a module.
type Cell<'T> = { slot: 'T }
type IntCell = Cell<int>
type StringCell = Cell<string>
module Cell =
let createInt x : IntCell = { slot = x }
let createString x : StringCell = { slot = x }
let x = Cell.createInt 123
let y = Cell.createString "testing"
However, since you specify the desired type in the function name anyway, the following syntax may be preferred.
type Cell<'T> = { slot: 'T }
with
static member Create (x : 'T) = { slot = x }
type IntCell = Cell<int>
type StringCell = Cell<string>
let x = IntCell.Create 123
let y = StringCell.Create "testing"
// or simply
let z = Cell<float>.Create 1.0
Thanks to @Vandroiy for pointing out the missing type constraint in my Create
method and for his answer that shows how the compiler can infer 'T
for the generic type Cell
when it can be determined by the static method being called.
The compiler cannot determine the generic parameter 'T
of the methods CreateInt
and CreateFloat
because it is unrelated to the methods' return types. In the question, it is valid to write:
Cell<float>.Create 1.0 // useless type annotation to remove warning
However, you can just as well write
Cell<string>.Create 1.0 // Trollolol
To avoid this, you need to make sure the factory can only produce the type it is called on. When declaring a factory on a generic type, use a type annotation to equate the generic argument of its return type with the generic argument of the type it is called on.
In my opinion, the complicated formulation adds to the confusion. You can achieve the desired effect with
type Cell<'T> =
{ slot: 'T }
static member Create (x : 'T) = { slot = x }
let x = Cell.Create 123
let y = Cell.Create "testing"
Note the type annotation for x
that equates the factory's input type with the generic parameter of the Cell<>
type!
Edited to address the comment:
As is, the types IntCell
and StringCell
serve no purpose; they are just a less readable form of Cell<int>
and Cell<string>
. From a comment to this answer, I understand that these types should be exposed instead of Cell
. As far as I know, this is not possible if they are defined as in the question, since type abbreviations have at most the accessibility of the type they abbreviate.
This is a reasonable design choice: if a type is generic, it should accept all valid generic type arguments. If IntCell
and StringCell
add specialized implementation, the usual way is to compose them of the appropriate instantiation of the Cell type and their specialized features. Then, the Cell type is allowed to have a more restricted accessibility than the specialized types.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With