Why do we need tuple?

Hi, everyone. I’m new to Crystal and I have two language-design-related questions:

(1)Why do we need tuple?
I think maybe it’s because of the speed, the same reason in Python and in Elixir. Is performance of tuple being the whole reason to make Crystal’s designers choose to add tuple to the language?

(2)Why do we need named tuple?
It’s just a hash in Ruby. Why not directly use Hash?

2 Likes

Hi @ccmywish, welcome to the forum!

Short answer on the run, feel free to ask for follow ups.

Tuples (be they named or not) are not only more efficient than a hash, but they are also more precisely typed. In a hash, you need to assign the same type to all the entries (which in Crystal it can be a union of several types). With a tuple, each tuple field has its own, precise type. Perhaps a better sibling of a tuple is the struct. In a sense, you could say that a (named) tuple is like an anonymous struct.

The typical use case for tuples is for returning multiple values. With a hash that’s ugly and error-prone.

5 Likes

The main reason why named tuples exist is to capture named arguments in a type-safe anonymous data structure. This is particularly useful for forwarding parameters:

def foo(**args)
  args.class # => NamedTuple(string_parameter: String)
  bar(**args)
end

def bar(string_parameter : String)
  string_parameter.upcase
end

foo(string_parameter: "foo") # => "FOO"

That’s also pretty much the single relevant use case. In all other cases it’s probably better to use a dedicated struct type instead.
A named tuple type is basically like a struct type except that it doesn’t need an explicit definition (it’s created ad hoc) and it can only hold properties, no methods, inheritance etc.

4 Likes

Really helpful. Thank you! :smiling_face_with_three_hearts:

By the way, a non-technical question:

How do you pronounce tuple

  1. /ˈtjʊpəl/
  2. /ˈtʌpəl/

“TWO-pull” is how I do

2 Likes

Named tuples are fabulous because you can’t accidentally refer to a key by name and use a wrong name on accident…

1 Like

Love to see some usage of IPA. I use pronunciation 2, though I don’t think I’ve ever heard that first one used.

1 Like

I’ve always pronounced it as in quintuple/sextuple/septuple/octuple, since that’s the origin of the term. Same reason I pronounce “gif” with a hard G.

4 Likes

Except @beta-ziliani post above, for returning multiple values, I never read explicitely that named tuples c(sh)ould be used instead of tuples, yet using NamedTuple keys are much less error prone than integer indexes.
Isn’t that use another main reason of NamedTuple existence ?

Not really. At that point why not use a record ? You get the same named arguments and parameters, but you also get a specific type and the ability to define methods on it.

2 Likes

Yes, but for very simple cases, such as returning a terminal lines and columns for example, I think terminal[:columns] is much clearer than terminal[1] and defining a Struct to handle such a simple case seems to me to be overkill.

I think for this use case its assumed you’d return {lines, columns} then the caller would do like lines, columns = get_terminal_lines_and_columns. Such that you don’t really need to access them by index anyway.

Ref: Assignment - Crystal

3 Likes

Then it sounds like assignments or some other kind of pattern matching syntax should be able to destructure named values.

IMO ideally every Tuple construct in Crystal should have a NamedTuple counterpart, but we are very far away from that.

2 Likes