Take the 2-minute tour ×

In F#, I'd like to have what I see as a fairly standard Abstract Datatype:

// in ADT.fsi
module ADT
  type my_Type

// in ADT.fs
module ADT
  type my_Type = int

In other words, code inside the module knows that my_Type is an int, but code outside does not. However, F# seems to have a restriction where type abbreviations specifically cannot be hidden by a signature. This code gives a compiler error, and the restriction is described here.

If my_Type were instead a discriminated union, then there is no compiler error. My question is, why the restriction? I seem to remember being able to do this in SML and Ocaml, and furthermore, isn't this a pretty standard thing to do when creating an abstract datatype?


share|improve this question

4 Answers 4

up vote 8 down vote accepted

As Ganesh points out, this is a technical limitation of the F# compiler (and .NET runtime), because the type abbreviation is simply replaced by the actual type during the compilation. As a result, if you write a function:

let foo (a:MyType) : MyType = a + 1

The compiler will compile it as a .NET method with the following signature:

int foo(int a);

If the actual type of the abbreviation was hidden from the users of the library, then they wouldn't be able to recognize that the foo function is actually working with MyType (this information is probably stored in some F#-specific meta-data, but that is not accessible to other .NET languages...).

Perhaps the best workaround for this limiation is to define the type as a single-case discriminated union:

type MyType = MT of int
let foo (MT a) = MT(a + 1)

Working with this kind of type is quite convenient. It adds some overhead (there are new objects created when constructing a value of the type), but that shouldn't be a big issue in most of the situations.

share|improve this answer
Yeah, thanks Tomas and Ganesh also. I now understand the issue, and I can see that, given this compilation strategy, this issue is a consequence. It's a little disappointing since I am working almost entirely in the F# space but I know interoperability is very important, so I won't complain! :-) –  Nels Beckman May 18 '10 at 15:10

Type abbreviations in F# are compiled away (i.e. the compiled code will use int, not MyType), so you can't make them properly abstract. In theory the compiler could enforce the abstraction within the F# world, but this wouldn't be very helpful as it would still leak in other languages.

share|improve this answer

Note that you can define a type abbreviation as private within a module:

// File1.fs
module File1
    type private MyType = int 
    let e : MyType = 42
    let f (x:MyType) = x+1

// Program.fs
module Program
do printfn "%A" (File1.f File1.e)

I am unclear why you can't hide it with a signature; I logged a bug to consider it.

share|improve this answer
True, but the sense in which I am imagining an ADT allows clients to know about the type, just not its representation. If I have another function in File1, let empty () : MyType = 1 Can I call this function from outside of File1 and pass its result to f? –  Nels Beckman May 18 '10 at 12:36
Yes (I edited example above). But I see your point, this is klutzy, as e.g. File1.MyType does not appear as an entity in the intellisense list, though File1.MyType does appear in the signatures of f and e. –  Brian May 18 '10 at 16:47
Note that this does not prevent you from doing something like File1.f 42 from outside the module, so the information that MyType = int isn't really hidden. So sadly this does not achieve the desired effect. –  sepp2k Oct 31 '13 at 10:46

From what I understand F# does not allow an abbreviation to be hidden by a signature.

I found this link where the blogger commented on this but I am not sure on the specifics of why this is the case.

My assumption is that this is a restraint set to allow more effective interop with other languages on the CLR.

share|improve this answer

Your Answer


