4

F# Types Docs said that:

Unit Type: Describes the unit type, a type that has one value and that is indicated by (); equivalent to void in C# and Nothing in Visual Basic.

It said they're equal, but why does the following comparison return false?

typedefof<System.Void> = typedefof<unit>;;
val it : bool = false
Community
  • 1
  • 1
MiP
  • 5,846
  • 3
  • 26
  • 41
  • 1
    I guess it’s because `Sustem.Void` cannot be used as a the parameter for generic types. That’s why we have both `Task` and `Task` where’s F# allows us to have only `Async<'T>`. – Pavel Voronin Jan 14 '18 at 08:12
  • 2
    Read [here](https://stackoverflow.com/questions/20704860/why-do-i-need-to-use-the-unit-type-in-f-if-it-supports-the-void-type) and [there](http://hestia.typepad.com/flatlander/2012/01/action-func-void-and-unit.html) – Zohar Peled Jan 14 '18 at 08:14
  • *Equivalent* and *equal* are different things. – molbdnilo Jan 14 '18 at 21:04

2 Answers2

12

Well, they're not really equivalent. The quote you posted is a bit misleading.

The F# type unit is equivalent to C# keyword void (not the type System.Void!) in that both the type and the keyword are used to declare functions that don't return anything:

// F#
let f (x:int) : unit = ...

// C#
void f( int x ) { ... }

This is what your quote is talking about, but the equivalence stops there.

In C# void is not really a type. It's a keyword that is used to declare return-less methods, but you can't use it in type positions - e.g. you can't have void variables, parameters, type parameters, etc. That's why we have a separate delegate Action instead of just using Func<void>.

The type System.Void is a different animal altogether: it exist only to support reflection, but it's not the same as void, the way System.Int32 is the same as int.

In F#, on the other hand, the type unit is mostly just a regular type, like any other. It even has a definition in the standard library. Yes, the compiler does give it some special treatment in certain special cases, but that's only for optimization and interop, invisible at the language level. Consequently, unit can be used in any type position - parameters, variables, whatever. This means that F#, for example, doesn't need a special function type for functions that don't return anything, it can just use int -> unit.

Fyodor Soikin
  • 78,590
  • 9
  • 125
  • 172
0

They are similar but not the same. However the compiler will compile a function with the unit parameter as void function. Unit is a special type in Functional Programming, unlike void. Also, you shouldn't be surprised by the comparison returning false, as this is void:

val it : Type = System.Void {Assembly = mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; AssemblyQualifiedName = "System.Void, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";

and this is unit:

val it : Type = Microsoft.FSharp.Core.Unit {Assembly = FSharp.Core, Version=4.4.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; AssemblyQualifiedName = "Microsoft.FSharp.Core.Unit, FSharp.Core, Version=4.4.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";

Quite clearly they are not the same. For more see Wikipedia for example.

s952163
  • 6,276
  • 4
  • 23
  • 47