Just a quick rant today.
Guid struct encapsulates
properties of universally unique identifier:
ID once generated locally in this way has a very low probability of being generated again,
at a different place or in a different time. This is accomplished using theoretically
unsound, but in practice very effective tricks like taking into account MAC addresses
of the generating computer.
The .NET implementation sucks at this encapsulation job inevitably, as struct encapsulation in .NET environment
is broken by enforced parameterless constructor.
This is a performance trade-off: when writing
new int, you don’t want to run ten
thousand constructors, you just allocate memory.
You can’t guarantee uniqueness though in a world when you have to be able instantiate with nothing.
(This is by the way something that reference types don’t suffer
not because they are on the heap, but because they are nullable, something that is now recognized
as a clear design mistake.
Notice how recent reference type nullability efforts
dance around what
new string should mean.)
So you are necessarily able to say
new Guid(); and have identifier that is not only not unique,
au contraire, that’s forced to be exactly the same as all other guids generated like this on the planet.
The only other alternative in .NET is to make some
GuidRef class, but this would be obviously
very wasteful. Guids are otherwise very good fit for value types as they are short and immutable.
What is really surprising: there is a widely used static property
Guid.Empty that offers
the same empty value as the one “generated” by
new Guid();. This is entirely unprovoked offer for doing the
wrong thing, subverting type system that is trying to say something (“this is a unique id!”) by introducing
meaningless noise (“this is
Nullable<T>, so the whole thing might just be a relict of times when it was practical
to do things like saying “customer ID not provided” by passing “customerId: -1”. I remember the past though and I’m quite
sure people didn’t like it even then: the advice was to create overloaded method without the possibly empty argument,
or encapsulate such “possible customer” by hand in an object.
Now, at whatever place you expect that
Guid can be missing, you should use
Guid? to inform the consumer about the situation and then just pass
One can argument that, given broken encapsulation of struct, it’s important to check
Guids for emptiness
all the time – and that
Guid.Empty makes that easier and more explicit. You know what would make it even easier?
Two extension methods like this:
public static bool IsEmpty(this Guid g) => g == new Guid(); public static bool IsEmpty(this Guid? g) => !g.HasValue || g.Value == new Guid();
All in all, one should be mindful about role of types when using them. Even in fairly basic type systems
without sum types (like C# has) there are ways to distinguish
between value presence and non-presence at the type level using
parametric polymorphism (
Nullable<T>) and such
distinction is crucial for any kind of type-safe work with the values provided.
Guid.Empty is a bad practice. Let’s hope it won’t spread.
Update: There is a good point
from user takerukoushirou at Reddit: UUID RFC defines
Nil value that corresponds
Guid.Empty. This redirects lots of my critique towards the standard (“why is any UUID actually
I don’t want to criticize standards. They are not valuable because they conform to my particular view of the world,
they are valuable because they establish any not-totally-insane common ground for us all.
The important point of this article remains: in a strongly typed program, non-
Nil GUID should have its type to use in domain
and database logic as we almost never want to have implicit nullability. Almost everyone can use
Guid as this non-
type as long as they won’t touch
Guid.Empty outside of boundary of the application. At the boundary, we must respect that
any other side can send us
Guid.Empty and still conform to the RFC.