Consider this DU:
type Foo = | Foo
My understanding was that this is equivalent:
type Foo = Foo
However, if we introduce generics they are not:
// Does not compile
type Bar<'t> = Bar
// Compiles
type Bar<'t> = | Bar
What's going on here?
More discoveries:
// Works
type Bar<'t> = Bar of 't
// Works
type Bar<'t> = | Bar of 't
I think there are two interesting cases here. The first one is:
type Foo = Foo
This looks like a self-referential type alias at first, but that's not allowed, so the compiler instead accepts it as a valid DU. This is correct, although subtle, behavior.
The second interesting case is:
type Bar<'t> = Bar // Error: The type 'Bar<_>' expects 1 type argument(s) but is given 0
This also looks like a self-referential type alias at first, but with the wrong number of type parameters. Since the reference is invalid, the compiler issues an error before it has a chance to realize that it's actually looking at a valid DU definition. I think one could reasonably argue that this is a bug in the compiler, and I suggest submitting it as an issue to the F# compiler team. The expected behavior is that this is a valid DU, just like type Foo = Foo and type Bar<'t> = | Bar.
Note also that the following is (correctly) not allowed:
type Bar<'t> = Bar<'t> // Error: This type definition involves an immediate cyclic reference through an abbreviation
The compiler source-code has the following to say:
// This unfortunate case deals with "type x = A"
// In F# this only defines a new type if A is not in scope
// as a type constructor, or if the form type A = A is used.
// "type x = | A" can always be used instead.
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