5

Both syntaxes look rather equivalent, and their use cases are similar too. Example:

# Hash
hash = {"name" => "Crystal", "year" => 2011}
hash["name"] # outputs: Crystal

# NamedTuple
tuple = {name: "Crystal", year: 2011}
tuple[:name] # outputs: Crystal

So where exactly those two primitive differ from each other?

Johannes Müller
  • 5,581
  • 1
  • 11
  • 25
Claudio Holanda
  • 2,455
  • 4
  • 21
  • 25

1 Answers1

8

The API docs already explain this pretty good. From NamedTuple (emphasis by me):

A named tuple is a fixed-size, immutable, stack-allocated mapping of a fixed set of keys to values.

You can think of a NamedTuple as an immutable Hash whose keys (which are of type Symbol), and the types for each key, are known at compile time.

And further:

The compiler knows what types are in each key, so when indexing a named tuple with a symbol literal the compiler will return the value for that key and with the expected type. Indexing with a symbol literal for which there's no key will give a compile-time error.

In contrast, Hash:

A Hash is a generic collection of key-value pairs mapping keys of type K to values of type V.

Put in simple words, a hash is a data structure that can be changed at runtime and all keys/values can have any type as long as it matches the generic type arguments K/V. A named tuple on the other hand is an immutable data structure which is completely known at compile time. If you access a key, the compiler knows its type. Having a named tuple is pretty much similar to just having the keys as variables with a common prefix:

foo = {bar: "bar", baz: 1}

foo_bar = "bar"
foo_baz = 1

NamedTuple just adds a few tools to use these variables as a coherent set.

Johannes Müller
  • 5,581
  • 1
  • 11
  • 25
  • So since a NameTuple structure is completely known at compile time, does it means that it can be optimized further by the compiler and so its faster than using Hash on similar conditions? – Claudio Holanda Jul 27 '18 at 18:31
  • 2
    No. Please never use NamedTuple in your code. A named tuple is just the representation of named arguments. You should probably always use Hash or a class in your code. – asterite Jul 27 '18 at 19:12
  • Still, accessing a named tuple is typically faster than a hash. But as asterite said, you should rather use a struct/class or hash for your data structure, depending on whether types and values are known at compile time or not. – Johannes Müller Jul 27 '18 at 20:16
  • @asterite Is your comment still true in 1.0? I just stumbled upon a situation where I have [] of results of method calls and concatenating them with + doesn't work, because it tries to do `[NamedTuple(x: int32, y: int32)] + [NamedTuple(a: "a")]`. -The syntax `{x: 1}` creates NamedTuple, but `{"x": 1}` creates a Hash.- EDIT: just discovered you can do `{ :x => 1 }` as a Hash, but `{"x": 1}` creates a NamedTuple. So it's consistend. Nevermind then, i was just confused. – Dalibor Filus May 29 '21 at 12:17