4

I've been following the official documentation of Crystal but I couldn't find any details on this. The regular syntax when declaring a union type is String | Int32. However, I've noticed a difference regarding the Nil type.

The regular way of declaring the union still works:

def foo(id : String | Nil)
end

# Overloads are:
#  - foo(id : String | Nil)

However I've also seen a shortened syntax which I couldn't find any documentation for:

def foo(id : String?)
end

# Overloads are:
#  - foo(id : String | ::Nil)

The result is almost exactly the same except Nil if prefixed with 2 colons. My guess that this is something related to the global scope of Nil as I've seen a similar syntax in other languages.

  1. Is String | Nil and String? the same thing, and when should you use one vs the other?
  2. What's the meaning of 2 colons in the type signature (e.g. ::Nil)?
kajetons
  • 4,481
  • 4
  • 26
  • 37

1 Answers1

6
  1. yes, they're exactly the same, people typically use the Foo? version as it's shorter.

  2. ::Nil means "the class Nil at the root namespace". This means that if you define a different Nil class in a different namespace, ::Nil always refers to the nil in the stdlib.

Stephie
  • 3,135
  • 17
  • 22
  • So in the 1nd case `Nil` isn't prefixed because the type was explicitly specified (no way of class name conflict)? I expected as much, just needed a confirmation. – kajetons Apr 19 '18 at 04:53
  • Exactly. When the compiler expands the `?` suffix, it replaces it with `| ::Nil` to specifically target `Nil` at global scope and avoid potential naming clashes. – Johannes Müller Apr 19 '18 at 07:28