Tuples

Tuples are commonly used in many languages, though some simply utilize arrays to represent them. We're going to learn what a Tuple is, why it is used, and what differences it may have from a List or Array.

We're working on inlining examples! Until then, please find the examples here on GitHub.

Tuples

One data structure that is very common in many languages, but won't have a specified data structure in each, is a Tuple.

Now I tend to pronounce this as "toople", since three major dictionaries favor the same, but there are a few alternatives. The most common alternative you may use or hear is "tupple", which is the way I first pronounced the word when I learned the concept.

Whichever way you choose to pronounce it, people will be able to figure out what you're talking about, and realistically we read it more than we say it.

But enough about pronunciation, let's discuss what defines a Tuple.

Unlike arrays or lists, a tuple is a finite and ordered collection of elements. It's not really meant to be iterated over, but rather intended to represent a grouping of related items that are very likely to be heterogeneous. Let's look at a few examples in a Python REPL to start with, since JavaScript doesn't have a native Tuple type.

Let's start off with the very basics. We can create an empty by using empty parens (). Or alternatively you can call the native tuple function with no argument and receive the same result, which we can verify by checking equality. This next thing is a quirk with Python, but if you're following a long it's important to know. If I define a tuple with a single element like so (1), it is going to evaluate to just the value itself. This is because the interpreter reads it as just a value with parens around it. In order to get the interpreter to read it as a tuple, all we have to do is add a comma after the first element (1,), and then it becomes the tuple we expected. Technically we don't even need the parens 1,, it's the comma that tells the interpreter it's a tuple. The native tuple function isn't variadic, meaning it doesn't take unlimited arguments. It wants you to pass an array to convert into a tuple. So we'll just pass in [1] an array containing 1, and that'll look exactly the same as using the literal syntax

Okay so now let's demonstrate what is arguably the most common type of tuple, a couple, also known as an ordered pair. It's just a tuple with two elements. This could certainly just be something like (1, 2) 1, 2, but let's assume for a moment that I have a very basic HTTP router. If a request is valid I want to return something to show it is a successful request, and provide the body for the response. If it is unsuccessful, I want to let the consumer know and provide an error why.

So let's represent these hypothetical requests as new functions right here in the REPL. First we will generate a new function called good_request(). Assuming it is successful I will respond with (200, "Hello, world!"), where the HTTP status code would be a 200, and the body a simple greeting. This fits in with the idea earlier where I mentioned that a tuple is used to store heterogeneous, but related data.

Next we'll make a function called bad_request that returns a 500 and (500, 'Server is broken') some error, in this case simply telling us the server is broken.

As you may expect, if I call these functions I get their returned tuple as the result.

Now what can I do with this. Well if I call x = good_request(), I can then access the status code and the body by their appropriate indices. That seems a bit silly to me to use data like this, so lets utilize some destructuring. What I mean by destructuring is that I am going to pull apart the elements of my tuple and assign them to variables. In Python, I think it is more common to call it unpacking a tuple, and it syntactically looks as though good_request() returns multiple values.

Instead of saying that we assign the variable x to the return type of good_request, we are instead going to assign status and body to the result of good_request(). Now within this scope I can use status to represent our status code, or element 0 of the tuple, and body to represent element 1. The same works for arrays in Python, I can easily just write foo, bar = [1,2] and now foo is 1 and bar is 2.

So with this kind of syntax available, it makes using tuples a bit more appealing than passing multiple arguments and pretending they're related. It's sometimes a better fit than creating a new object, class, or map as well. For our next example I am going to hop into a browser and we're going to do something tuples excel at - representing coordinates.

My page here is very basic - I have a canvas element that I fetch by id, then I grab it's context for some 2D drawing. These four lines I'm simply setting up the drawing context a bit and can largely be ignored. Let's look at our list of coordinates here. They're provided as object literals right now, but another common way I've seen in the wild is that a full class is defined, at least as far as JavaScript is concerned, and that each of these here are instances of a Point, which may as well simply just be the object literal since the class doesn't do much on its own.

I think that this kind of system benefits from tuples, because we are providing a point over two axis. The x and y coordinates are related and necessary to create the point, so grouping them together makes sense. Our objects work fine for this, but simply using tuples can suffice. Let's see how that would look. We'll just replace new Point with an open bracket, and replace the closing paren with a closing bracket. Now are coordinates are represented as an array of tuples, or technically an array of arrays since JS doesn't have real tuples. Now down here in the plotLine function, we could technically keep using the variable pair and now access x and y by indices 0 and 1, but that feels like a step backwards. So instead we are going to use some array destructuring available in JavaScript in either modern browsers or using a compiler such as Babel. So the syntax for that is open bracket, x, y, and close bracket - thus it looks like an array and pulls out those elements. Now in the body I can get rid of the pair references and it's ready to go! In fairness, destructuring the pair object would've worked too had I just swapped the brackets with braces, but that is a bit outside of the focus. So when we refresh everything still works as it did before.

So any of these options are ultimately okay, I just feel that having these values named x and y in an object when we know it's a list of x and y coordinate pairs doesn't win us a lot. I find that an array of arrays or tuples matches up well with the mathematical representation of a tuple and coordinate pairs so it's my preferred choice in this instance.

Be sure to look at the data structures native to your language of choice and see what works out better for your situations. In Python, tuples are lightweight, have computed lengths at compile time, and are immutable. Sometimes that's preferable to a list or a map, and other times it's not. It's all about tradeoffs, so doing a little bit of research ahead of time can save you a lot of headaches later.