Fans of functional programming and/or strong typing certainly know unit
: tuple with zero elements, type ()
that only posses the single value ()
. C# 7.0 now has it too, albeit with a slightly ugly name: ValueTuple
.
Let me explain.
C# has void
keyword and it’s not a good thing. It creates an artificial asymmetry between methods that return something and methods that do not return anything. From this decision follows the necessity to distinguish between Func<>
and Action<>
.
In Haskell, you have type ()
and it’s what it looks like: the empty tuple. This type has the single value ()
, so when you are returning it, you are not conveying any information.
(Well, up to the fact that you are returning, but this distinction between unit
and bottom
is not important for us now.) It’s a good replacement for a special keyword like void
, because it fits well into another concept (of tuples) anyway.
If we had ()
in C#, we would not write Action<int>
, but Func<int, ()>
– we would abolish Action
completely. In a similar vein, we would be able to use ConcurrentDictionary
like
ConcurrentDictionary<string, ()>
, i.e. as a non-existent ConcurrentHashSet<string>
.
We know that there are differences between System.Tuple<T1, T2, ...>
and System.ValueTuple<T1, T2, ...>
: the most important one being that the old Tuple
is a reference type and the new ValueTuple
is a value type.
Did you notice though that there is System.ValueTuple
without generic arguments? System.Tuple
is just a static shorthand for creation of generic tuples using its Create
method, you can’t instantiate it.
This instantiable System.ValueTuple
is unit
in a very real sense. It’s inhabited by the single value, so new ValueTuple().Equals(new ValueTuple())
, default(ValueTuple).Equals(new ValueTuple())
. Conceptually, it corresponds to Haskell’s type ()
as “product of empty set of types”.
Unfortunately, the language does not accept ()
syntax sugar for System.ValueTuple
:
public () DoStuff() // <- does not compile
{
// ...
return (); // <- does not compile
}
This has the same meaning though – and it compiles:
public ValueTuple DoStuff()
{
// ...
return new ValueTuple();
}
It’s kind of nice that in this way, even beginners see the difference between “value ()
” and “type ()
”. That makes problems in Haskell sometimes.
It arguably looks weird though, especially given already suspicious name ValueTuple
for such a fundamental thing. It’s difficult to imagine an organization that decides to opt into this style just to make the codebase slightly more consistent and nice.
Nevertheless, void
-free style is from now on possible in C#. All it takes is to write an analyzer that forbids void
s and Action
s.