What's the difference between Hash and NamedTuple in Crystal?
Asked Answered
R

1

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?

Rosenblast answered 27/7, 2018 at 15:39 Comment(0)
A
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.

Adulteress answered 27/7, 2018 at 18:15 Comment(4)
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?Rosenblast
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.Inheritance
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.Loma
@Inheritance 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.Septicidal

© 2022 - 2024 — McMap. All rights reserved.