In Progress
Unit 1, Lesson 21
In Progress

Multiple Assignment

Video transcript & code

It's a lazy New Years day as I'm making this, and I have a cold, so for today's topic I just have a short rant on coding style.

In past episodes we've learned about "splatting" and "slurping" in Ruby. We can splat arrays out into multiple variables:

a, b, c = [1,2,3]
a                               # => 1
b                               # => 2
c                               # => 3

And we can slurp multiple values into an array:

arr = 1, 2, 3
arr                             # => [1, 2, 3]

Putting these two facts together, the obvious conclusion is that we can also do multiple assignment on a single line. Here we assign the numbers 1, 2, and 3 to variables a, b, and c respectively.

a, b, c = 1, 2, 3
a                               # => 1
b                               # => 2
c                               # => 3

But just because we can do something, doesn't mean we should. Here's an initializer method I snagged from some open-source code.

def initialize(filter, current_user, topics)
  @filter = filter
  @current_user = current_user
  @topics_input = topics
end

We could set all these variables on one line, like so.

def initialize(filter, current_user, topics)
  @filter, @current_user, @topics_input = filter, current_user, topics
end

And I've occasionally seen code that looks like this. But this is an abuse of multiple assignment in my not-so-humble opinion. Instead of having a table-like layout with a variable on the left and a value down the right, I have to visually associate a position on the left side of the equals sign with a position on the right. I don't know about you, but I find this unreadable. And that's just reading it - trying to modify a line like this, by adding or removing an assignment, takes too many keystrokes and is way too easy to mess out. Contrast that with modifying a series of single assignments: every assignment added or removed is just a line added or a line removed.

def initialize(filter, current_user, topics)
  @filter = filter
  @topics_input = topics
end

So is multiple assignment ever warranted? I think in cases where there are two or three variables which are very closely related, it might be a reasonable syntactic shortcut. For instance, here's the perennial Point class example. We can't have a Point class without X and Y coordinates, and those two variables are fundamentally linked. In this case, it doesn't seem horrible to me to assign them on a single line.

class Point
  def initialize(x, y)
    @x, @y = x, y
  end
end

Multiple assignment is also the idiomatic way to swap variable values in Ruby. In other languages we might need a third, temporary variable to complete the swap. But in Ruby we can do it in a single logical operation.

x = 1
y = 2
x, y = y, x
x                               # => 2
y                               # => 1

Apart from these two rare scenarios, I see little legitimate use for multiple assignment. If you like readable and maintainable code, my advice is to avoid using this feature.

And this plays into a larger point about coding style: in general, I think it's better to expand a program vertically than horizontally. When each logical statement has it's own line, the program is easier to comprehend, it's easier to move code around with cut and paste, it's easier to temporarily comment parts of the code out, and so on.

That's all for today. Happy hacking!

Responses