# Multiple assignment in conditional

**URL:** <https://rubytalk.org/t/multiple-assignment-in-conditional/64737>\
**Category:** ruby-talk\
**Created:** [31 January 2012 06:46 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737 "2012-01-31T06:46:07Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![GS1](https://avatars.discourse-cdn.com/v4/letter/g/4491bb/32.png) [@GS1](https://rubytalk.org/u/GS1)\
**Post date:** [31 January 2012 06:46 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/1 "2012-01-31T06:46:07Z")

</div>

I find this a strange Ruby error.

foo = [1,2]

# The following is fine.  
if (a = foo)  
&nbsp;&nbsp;puts a  
end

# The following causes a SyntaxError: multiple assignment in conditional.  
if (a, b = foo)  
&nbsp;&nbsp;puts a  
end

Why would that be a syntax error? Surely the grammar is

&nbsp;&nbsp;if EXPR  
&nbsp;&nbsp;&nbsp;&nbsp;...

and (a, b = foo) is an expression, isn't it?

Just curious, though my curiosity was prompted by a failing piece of real  
code.

Gavin

---

<div class="post-metadata">

**Author:** ![Josh\_Cheek](https://avatars.discourse-cdn.com/v4/letter/j/e79b87/32.png) [@Josh\_Cheek](https://rubytalk.org/u/Josh_Cheek)\
**Post date:** [31 January 2012 07:22 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/2 "2012-01-31T07:22:31Z")

</div>

What did you expect your real code to do? It seems to me that it should  
raise an error unless it's an array of size 2, and if it is, then it should  
return an array of size two, making the conditional necessarily true. So I  
don't know what you were expecting to happen.

> **···**
>
> On Tue, Jan 31, 2012 at 12:46 AM, Gavin Sinclair \<gsinclair@gmail.com\>wrote:
> 
> > I find this a strange Ruby error.
> > 
> > foo = [1,2]
> > 
> > # The following is fine.  
> > if (a = foo)  
> > puts a  
> > end
> > 
> > # The following causes a SyntaxError: multiple assignment in conditional.  
> > if (a, b = foo)  
> > puts a  
> > end
> > 
> > Why would that be a syntax error? Surely the grammar is
> > 
> > if EXPR  
> > &nbsp;&nbsp;&nbsp;...
> > 
> > and (a, b = foo) is an expression, isn't it?
> > 
> > Just curious, though my curiosity was prompted by a failing piece of real  
> > code.
> > 
> > Gavin

---

<div class="post-metadata">

**Author:** ![GD1](https://avatars.discourse-cdn.com/v4/letter/g/6f9a4e/32.png) [@GD1](https://rubytalk.org/u/GD1)\
**Post date:** [31 January 2012 07:57 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/3 "2012-01-31T07:57:17Z")

</div>

Hi Gavin,

> I find this a strange Ruby error.
> 
> foo = [1,2]
> 
> # The following is fine.  
> if (a = foo)  
> &nbsp;&nbsp;&nbsp;puts a  
> end
> 
> # The following causes a SyntaxError: multiple assignment in conditional.  
> if (a, b = foo)  
> &nbsp;&nbsp;&nbsp;puts a  
> end
> 
> Why would that be a syntax error? Surely the grammar is
> 
> &nbsp;&nbsp;&nbsp;if EXPR  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...
> 
> and (a, b = foo) is an expression, isn't it?
> 
> Just curious, though my curiosity was prompted by a failing piece of real  
> code.

I can understand why the language rejects that construct (I've never tried it myself- an interesting find!). The method itself would be returning an array (correct?), and an array would always be treated as true in the expression, regardless of the results. Thus, it is likely to be some sort of error (why put an always-statically-true expression in a conditional?), and hence knocks it back with an error.

I'm wondering as to the best behaviour if it were actually handled directly by the language (which I'm not specifically suggesting). True if any of the multiple assignments evaluate to true? Or just the first? Or last? Certainly not always-true. I can't say I'd know a sensible default. 😕

Garth

> **···**
>
> On 31/01/12 17:16, Gavin Sinclair wrote:

---

<div class="post-metadata">

**Author:** ![botp1](https://avatars.discourse-cdn.com/v4/letter/b/6de8d8/32.png) [@botp1](https://rubytalk.org/u/botp1)\
**Post date:** [31 January 2012 12:38 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/4 "2012-01-31T12:38:48Z")

</div>

because it's a parallel assignment and ruby would not know which to  
check, a or b, no?

try eg,

&nbsp;&nbsp;a,b=true  
or  
&nbsp;&nbsp;a,b,c=1

kind regards -botp

> **···**
>
> On Tue, Jan 31, 2012 at 2:46 PM, Gavin Sinclair \<gsinclair@gmail.com\> wrote:
> 
> > # The following causes a SyntaxError: multiple assignment in conditional.  
> > if (a, b = foo)  
> > puts a  
> > end

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [31 January 2012 22:16 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/5 "2012-01-31T22:16:54Z")

</div>

> I find this a strange Ruby error.
> 
> foo = [1,2]
> 
> # The following is fine.  
> if (a = foo)  
> puts a  
> end
> 
> # The following causes a SyntaxError: multiple assignment in conditional.  
> if (a, b = foo)  
> puts a  
> end
> 
> Why would that be a syntax error? Surely the grammar is
> 
> if EXPR  
> ...
> 
> and (a, b = foo) is an expression, isn't it?

Yeah, I'd agree. But why write such obfuscated code?

> Just curious, though my curiosity was prompted by a failing piece of real  
> code.

Well, there is no point in having assignments in conditionals - unless  
it's a loop in which case the code often becomes more elegant, e.g.:

while ( line = gets )  
&nbsp;&nbsp;puts line  
end

For a simple if and unless there is really no advantage in having an  
assignment in the condition.

Kind regards

robert

> **···**
>
> On Tue, Jan 31, 2012 at 7:46 AM, Gavin Sinclair \<gsinclair@gmail.com\> wrote:
> 
> --  
> remember.guy do |as, often| as.you\_can - without end  
> [http://blog.rubybestpractices.com/](http://blog.rubybestpractices.com/)

---

<div class="post-metadata">

**Author:** ![Nikolai\_Weibull2](https://avatars.discourse-cdn.com/v4/letter/n/94ad74/32.png) [@Nikolai\_Weibull2](https://rubytalk.org/u/Nikolai_Weibull2)\
**Post date:** [31 January 2012 08:27 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/6 "2012-01-31T08:27:25Z")

</div>

> > # The following causes a SyntaxError: multiple assignment in conditional.  
> > if (a, b = foo)

> I can understand why the language rejects that construct (I've never tried  
> it myself- an interesting find!). The method itself would be returning an  
> array (correct?), and an array would always be treated as true in the  
> expression, regardless of the results. Thus, it is likely to be some sort of  
> error (why put an always-statically-true expression in a conditional?), and  
> hence knocks it back with an error.

if true  
&nbsp;&nbsp;puts 'well that’s a relief'  
end

> I'm wondering as to the best behaviour if it were actually handled directly  
> by the language (which I'm not specifically suggesting). True if any of the  
> multiple assignments evaluate to true? Or just the first? Or last? Certainly  
> not always-true. I can't say I'd know a sensible default. 😕

[a, b, …].any?

> **···**
>
> On Tue, Jan 31, 2012 at 08:57, Garthy D \<garthy\_lmkltybr@entropicsoftware.com\> wrote:
> 
> > On 31/01/12 17:16, Gavin Sinclair wrote:

---

<div class="post-metadata">

**Author:** ![botp1](https://avatars.discourse-cdn.com/v4/letter/b/6de8d8/32.png) [@botp1](https://rubytalk.org/u/botp1)\
**Post date:** [31 January 2012 12:55 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/7 "2012-01-31T12:55:25Z")

</div>

ok, ignore. i get gavin's point regarding expression

> **···**
>
> On Tue, Jan 31, 2012 at 8:38 PM, botp \<botpena@gmail.com\> wrote:
> 
> > try eg,
> > 
> > a,b=true  
> > or  
> > a,b,c=1

---

<div class="post-metadata">

**Author:** ![botp1](https://avatars.discourse-cdn.com/v4/letter/b/6de8d8/32.png) [@botp1](https://rubytalk.org/u/botp1)\
**Post date:** [1 February 2012 00:22 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/8 "2012-02-01T00:22:35Z")

</div>

i dont know, Robert, since i also find

&nbsp;&nbsp;while ( line,x,y = get\_something)

also elegant.  
if ruby would support that, wouldn't it be elegant?

best regards -botp

> **···**
>
> On Wed, Feb 1, 2012 at 6:16 AM, Robert Klemme \<shortcutter@googlemail.com\> wrote:
> 
> > it's a loop in which case the code often becomes more elegant, e.g.:
> > 
> > while ( line = gets )

---

<div class="post-metadata">

**Author:** ![GS1](https://avatars.discourse-cdn.com/v4/letter/g/4491bb/32.png) [@GS1](https://rubytalk.org/u/GS1)\
**Post date:** [1 February 2012 11:49 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/9 "2012-02-01T11:49:47Z")

</div>

> > # The following causes a SyntaxError: multiple assignment in conditional.  
> > if (a, b = foo)  
> > puts a  
> > end

> What did you expect your real code to do? It seems to me that it should  
> raise an error unless it's an array of size 2

Nope. It can return anything at all and Ruby will deal with it.  
Parallel assignment is (thankfully) flexible.

def foo; 1; end  
a, b = foo # returns 1; a == 1, b == nil

def bar; [1,2,3,4,5]; end  
a, b = bar # returns [1,2,3,4,5]; a == 1, b == 2

> and if it is, then it should  
> return an array of size two, making the conditional necessarily true.

Nope. The conditional can be false.

def foo; nil; end  
a, b = foo # returns nil; a == nil, b == nil

> So I don't know what you were expecting to happen.

def foo; nil; end

if (a, b = foo)  
&nbsp;&nbsp;puts "outcome 1"  
else  
&nbsp;&nbsp;puts "outcome 2" # I was expecting this.  
end

Of course I don't have a function that returns nil unconditionally!  
Just showing the structure.

> **···**
>
> On Tue, Jan 31, 2012 at 6:22 PM, Josh Cheek \<josh.cheek@gmail.com\> wrote:

---

<div class="post-metadata">

**Author:** ![GS1](https://avatars.discourse-cdn.com/v4/letter/g/4491bb/32.png) [@GS1](https://rubytalk.org/u/GS1)\
**Post date:** [1 February 2012 11:57 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/10 "2012-02-01T11:57:55Z")

</div>

Here's the code with the thing that doesn't work. Of course you don't  
know the context, but I hope this is enlightening.

&nbsp;&nbsp;# week\_and\_day(date) -\> [17,1] week 17, day 1 (Mon)  
&nbsp;&nbsp;# Returns nil if the given date is not in this term.  
&nbsp;&nbsp;def week\_and\_day(date)  
&nbsp;&nbsp;&nbsp;&nbsp;if not self.include? date  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return nil  
&nbsp;&nbsp;&nbsp;&nbsp;elsif (week, day = @t1.week\_and\_day(date))  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return [week, day]  
&nbsp;&nbsp;&nbsp;&nbsp;elsif (week, day = @t2.week\_and\_day(date))  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;week += @t1.number\_of\_weeks  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return [week, day]  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end

I don't see anything obfuscated about that. @t1.week\_and\_day(date)  
will return nil if the date is outside the range of @t1, so we will go  
to the next part of the conditional.

Here it is in acceptable Ruby.

&nbsp;&nbsp;# week\_and\_day(date) -\> [17,1] week 17, day 1 (Mon)  
&nbsp;&nbsp;# Returns nil if the given date is not in this term.  
&nbsp;&nbsp;def week\_and\_day(date)  
&nbsp;&nbsp;&nbsp;&nbsp;if not self.include? date  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return nil  
&nbsp;&nbsp;&nbsp;&nbsp;elsif (week\_and\_day = @t1.week\_and\_day(date))  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return week\_and\_day  
&nbsp;&nbsp;&nbsp;&nbsp;elsif (week\_and\_day = @t2.week\_and\_day(date))  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;week, day = week\_and\_day  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;week += @t1.number\_of\_weeks  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return [week, day]  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end

This one has a clumsy variable name "week\_and\_day" and an extra line  
to unpack it into "week" and "day". I'm not crying mercy over one  
extra line, but I definitely prefer the first version. It seems more  
intentional.

Gavin

> **···**
>
> On Wed, Feb 1, 2012 at 9:16 AM, Robert Klemme \<shortcutter@googlemail.com\> wrote:
> 
> > Yeah, I'd agree. But why write such obfuscated code?

---

<div class="post-metadata">

**Author:** ![GD1](https://avatars.discourse-cdn.com/v4/letter/g/6f9a4e/32.png) [@GD1](https://rubytalk.org/u/GD1)\
**Post date:** [31 January 2012 08:41 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/11 "2012-01-31T08:41:22Z")

</div>

Hi Nikolai,

> > > # The following causes a SyntaxError: multiple assignment in conditional.  
> > > if (a, b = foo)
> 
> > I can understand why the language rejects that construct (I've never tried  
> > it myself- an interesting find!). The method itself would be returning an  
> > array (correct?), and an array would always be treated as true in the  
> > expression, regardless of the results. Thus, it is likely to be some sort of  
> > error (why put an always-statically-true expression in a conditional?), and  
> > hence knocks it back with an error.
> 
> if true  
> &nbsp;&nbsp;&nbsp;puts 'well that’s a relief'  
> end

Haha, I \*knew\* someone would call me out on that one if I wasn't more specific. What I didn't expect was how little time it'd take. 😉

To clarify: If "if (a, b = foo)" would always evaluate to true, it might cause confusion for someone expecting it to base the evaluation on one of the assigned variables; whereas the intent for "if true" is pretty clear; it's an expression with less than two assignments.

Still, it's not necessarily a strong argument or one I'd get behind. I'm just saying that I understand why it might have turned out that way. Maybe the potential for confusion led to that particular design decision?

> > I'm wondering as to the best behaviour if it were actually handled directly  
> > by the language (which I'm not specifically suggesting). True if any of the  
> > multiple assignments evaluate to true? Or just the first? Or last? Certainly  
> > not always-true. I can't say I'd know a sensible default. 😕
> 
> [a, b, …].any?

Indeed, that's another possibility, although I'll point out that it's inconsistent with an empty array normally being treated as true in an ordinary expression. But hey, we are working with an odd case here, so why not? 🙂

Garth

> **···**
>
> On 31/01/12 18:57, Nikolai Weibull wrote:
> 
> > On Tue, Jan 31, 2012 at 08:57, Garthy D \> \<garthy\_lmkltybr@entropicsoftware.com\> wrote:
> > 
> > > On 31/01/12 17:16, Gavin Sinclair wrote:

---

<div class="post-metadata">

**Author:** ![Josh\_Cheek](https://avatars.discourse-cdn.com/v4/letter/j/e79b87/32.png) [@Josh\_Cheek](https://rubytalk.org/u/Josh_Cheek)\
**Post date:** [1 February 2012 00:28 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/12 "2012-02-01T00:28:23Z")

</div>

I don't think it would be elegant, because the relationship between the  
condition and the assignment is obscure. I would assume it's a shorthand  
for `loop { line, x, y = get_something; ... }` but would have to look at it  
for a while and then run some experiments to see.

> **···**
>
> On Tue, Jan 31, 2012 at 6:22 PM, botp \<botpena@gmail.com\> wrote:
> 
> > On Wed, Feb 1, 2012 at 6:16 AM, Robert Klemme \> \<shortcutter@googlemail.com\> wrote:  
> > \> it's a loop in which case the code often becomes more elegant, e.g.:  
> > \>  
> > \> while ( line = gets )
> > 
> > i dont know, Robert, since i also find
> > 
> > while ( line,x,y = get\_something)
> > 
> > also elegant.  
> > if ruby would support that, wouldn't it be elegant?
> > 
> > best regards -botp

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [1 February 2012 07:48 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/13 "2012-02-01T07:48:14Z")

</div>

I find

something.each do |line, x, y|  
&nbsp;&nbsp;...  
end

more elegant and idiomatic Ruby. That's why I typically use

ARGF.each do |line|  
&nbsp;&nbsp;...  
end

instead of while ( line = gets ).

Kind regards

robert

> **···**
>
> On Wed, Feb 1, 2012 at 1:22 AM, botp \<botpena@gmail.com\> wrote:
> 
> > On Wed, Feb 1, 2012 at 6:16 AM, Robert Klemme \> \<shortcutter@googlemail.com\> wrote:
> > 
> > > it's a loop in which case the code often becomes more elegant, e.g.:
> > > 
> > > while ( line = gets )
> > 
> > i dont know, Robert, since i also find
> > 
> > while ( line,x,y = get\_something)
> > 
> > also elegant.  
> > if ruby would support that, wouldn't it be elegant?
> 
> --  
> remember.guy do |as, often| as.you\_can - without end  
> [http://blog.rubybestpractices.com/](http://blog.rubybestpractices.com/)

---

<div class="post-metadata">

**Author:** ![GS1](https://avatars.discourse-cdn.com/v4/letter/g/4491bb/32.png) [@GS1](https://rubytalk.org/u/GS1)\
**Post date:** [1 February 2012 12:05 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/14 "2012-02-01T12:05:57Z")

</div>

Sorry to reply to my own message, but I thought of something I should  
have included.

Here is the forbidden version I would like to write. Obviously I'm  
combining assignment and conditional, which may not win plaudits as a  
general rule.

> def week\_and\_day(date)  
> if not self.include? date  
> return nil  
> elsif (week, day = @t1.week\_and\_day(date))  
> return [week, day]  
> elsif (week, day = @t2.week\_and\_day(date))  
> week += @t1.number\_of\_weeks  
> return [week, day]  
> end  
> end

But consider this alternative, where I separate the assignment and the  
conditional.

&nbsp;&nbsp;def week\_and\_day(date)  
&nbsp;&nbsp;&nbsp;&nbsp;if not self.include? date  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return nil  
&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;week, day = @t1.week\_and\_day(date)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if week  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return [week, day]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;week, day = @t2.week\_and\_day(date)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;week += @t1.number\_of\_weeks  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return [week, day]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end

I consider this very clumsy. By \_not\_ combining assignment with  
conditional, I cannot use "elsif". I must split the "else" and the  
"if", and turn the second conditional into a child instead of a  
sibling.

Definitely less intentional and unattractive code.

Gavin

> **···**
>
> On Wed, Feb 1, 2012 at 10:57 PM, Gavin Sinclair \<gsinclair@gmail.com\> wrote:

---

<div class="post-metadata">

**Author:** ![Joel\_VanderWerf](https://avatars.discourse-cdn.com/v4/letter/j/e19b73/32.png) [@Joel\_VanderWerf](https://rubytalk.org/u/Joel_VanderWerf)\
**Post date:** [1 February 2012 20:15 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/15 "2012-02-01T20:15:13Z")

</div>

You can trick ruby:

def foo; nil; end

if (\_ = (a, b = foo))  
&nbsp;&nbsp;&nbsp;puts "outcome 1"  
else  
&nbsp;&nbsp;&nbsp;puts "outcome 2"  
end

So, the question is parsing, not semantics.

> **···**
>
> On 02/01/2012 03:49 AM, Gavin Sinclair wrote:
> 
> > def foo; nil; end
> > 
> > if (a, b = foo)  
> > &nbsp;&nbsp;&nbsp;puts "outcome 1"  
> > else  
> > &nbsp;&nbsp;&nbsp;puts "outcome 2" # I was expecting this.  
> > end

---

<div class="post-metadata">

**Author:** ![Josh\_Cheek](https://avatars.discourse-cdn.com/v4/letter/j/e79b87/32.png) [@Josh\_Cheek](https://rubytalk.org/u/Josh_Cheek)\
**Post date:** [1 February 2012 21:03 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/16 "2012-02-01T21:03:28Z")

</div>

Sorry, but I find this incredibly opaque.

Could you just write what you expect the evaluation to be in each of these  
cases?

a, b = 1, 1  
a, b = 1, nil  
a, b = nil, 1  
a, b = nil, nil

I'd expect return values of [1, 1], [1, nil], [nil, 1], [nil, nil] which  
are all true.

Now does this change when the RHS is an array instead of two values?  
For example, would `a, b = [1, 1]` return a different value than `a, b =  
[1, 1]`?

Your example seems particularly devious in that it only has one value on  
the RHS of the assignment. This means that the second argument will be  
assigned nil (because there is no value for it), and because assignment  
operators always return the RHS, it will then return whatever single value  
was over there. This causes it to look like you are assigning multiple  
values to the variables and having it return nil, when in fact you are only  
assigning one value (the second variable is along for the ride and will  
always be nil).

There are so many nuanced ruby edge cases one must know (and then must also  
know the implementation of how it is being returned) to understand that  
example that I think it has more overhead than it is worth.

> **···**
>
> On Wed, Feb 1, 2012 at 5:49 AM, Gavin Sinclair \<gsinclair@gmail.com\> wrote:
> 
> > On Tue, Jan 31, 2012 at 6:22 PM, Josh Cheek \<josh.cheek@gmail.com\> wrote:
> > 
> > \>\> # The following causes a SyntaxError: multiple assignment in  
> > conditional.  
> > \>\> if (a, b = foo)  
> > \>\> puts a  
> > \>\> end
> > 
> > \> What did you expect your real code to do? It seems to me that it should  
> > \> raise an error unless it's an array of size 2
> > 
> > Nope. It can return anything at all and Ruby will deal with it.  
> > Parallel assignment is (thankfully) flexible.
> > 
> > def foo; 1; end  
> > a, b = foo # returns 1; a == 1, b == nil
> > 
> > def bar; [1,2,3,4,5]; end  
> > a, b = bar # returns [1,2,3,4,5]; a == 1, b == 2
> > 
> > \> and if it is, then it should  
> > \> return an array of size two, making the conditional necessarily true.
> > 
> > Nope. The conditional can be false.
> > 
> > def foo; nil; end  
> > a, b = foo # returns nil; a == nil, b == nil
> > 
> > \> So I don't know what you were expecting to happen.
> > 
> > def foo; nil; end
> > 
> > if (a, b = foo)  
> > &nbsp;&nbsp;puts "outcome 1"  
> > else  
> > puts "outcome 2" # I was expecting this.  
> > end
> > 
> > Of course I don't have a function that returns nil unconditionally!  
> > Just showing the structure.

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [1 February 2012 12:33 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/17 "2012-02-01T12:33:42Z")

</div>

There are plenty more solutions, for example:

def week\_and\_day(date)  
&nbsp;&nbsp;&nbsp;return nil unless include? date

&nbsp;&nbsp;&nbsp;week\_and\_day = @t1.week\_and\_day(date) and return week\_and\_day

&nbsp;&nbsp;&nbsp;week\_and\_day = @t2.week\_and\_day(date)  
&nbsp;&nbsp;&nbsp;week\_and\_day[0] += @t1.number\_of\_weeks if week\_and\_day

&nbsp;&nbsp;&nbsp;week\_and\_day  
end

Maybe also

def week\_and\_day(date)  
&nbsp;&nbsp;&nbsp;return nil unless include? date

&nbsp;&nbsp;&nbsp;case  
&nbsp;&nbsp;&nbsp;when week\_and\_day = @t1.week\_and\_day(date)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil  
&nbsp;&nbsp;&nbsp;when week\_and\_day = @t2.week\_and\_day(date)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;week\_and\_day[0] += @t1.number\_of\_weeks  
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;week\_and\_day  
end

Kind regards

robert

> **···**
>
> On Wed, Feb 1, 2012 at 1:05 PM, Gavin Sinclair \<gsinclair@gmail.com\> wrote:
> 
> > On Wed, Feb 1, 2012 at 10:57 PM, Gavin Sinclair \<gsinclair@gmail.com\> wrote:
> > 
> > Sorry to reply to my own message, but I thought of something I should  
> > have included.
> > 
> > Here is the forbidden version I would like to write. Obviously I'm  
> > combining assignment and conditional, which may not win plaudits as a  
> > general rule.
> > 
> > > def week\_and\_day(date)  
> > > if not self.include? date  
> > > return nil  
> > > elsif (week, day = @t1.week\_and\_day(date))  
> > > return [week, day]  
> > > elsif (week, day = @t2.week\_and\_day(date))  
> > > week += @t1.number\_of\_weeks  
> > > return [week, day]  
> > > end  
> > > end
> > 
> > But consider this alternative, where I separate the assignment and the  
> > conditional.
> > 
> > def week\_and\_day(date)  
> > if not self.include? date  
> > return nil  
> > else  
> > week, day = @t1.week\_and\_day(date)  
> > if week  
> > return [week, day]  
> > else  
> > week, day = @t2.week\_and\_day(date)  
> > week += @t1.number\_of\_weeks  
> > return [week, day]  
> > end  
> > end  
> > end
> > 
> > I consider this very clumsy. By \_not\_ combining assignment with  
> > conditional, I cannot use "elsif". I must split the "else" and the  
> > "if", and turn the second conditional into a child instead of a  
> > sibling.
> > 
> > Definitely less intentional and unattractive code.
> 
> --  
> remember.guy do |as, often| as.you\_can - without end  
> [http://blog.rubybestpractices.com/](http://blog.rubybestpractices.com/)

---

<div class="post-metadata">

**Author:** ![botp1](https://avatars.discourse-cdn.com/v4/letter/b/6de8d8/32.png) [@botp1](https://rubytalk.org/u/botp1)\
**Post date:** [2 February 2012 02:56 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/18 "2012-02-02T02:56:00Z")

</div>

> You can trick ruby:
> 
> def foo; nil; end
> 
> if (\_ = (a, b = foo))
> 
> puts "outcome 1"  
> else  
> puts "outcome 2"  
> end
> 
> So, the question is parsing, not semantics.

indeed. ruby just checks the last assignment.

> if (x,y=(a, b = foo))  
> p 1  
> end

SyntaxError: (irb):17: multiple assignment in conditional

but i do not know why it has to do that checking. too much work. and  
could probably slow down ruby.

kind regards -botp

> **···**
>
> On Thu, Feb 2, 2012 at 4:15 AM, Joel VanderWerf \<joelvanderwerf@gmail.com\> wrote:

---

<div class="post-metadata">

**Author:** ![GS1](https://avatars.discourse-cdn.com/v4/letter/g/4491bb/32.png) [@GS1](https://rubytalk.org/u/GS1)\
**Post date:** [2 February 2012 11:45 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/19 "2012-02-02T11:45:55Z")

</div>

> Could you just write what you expect the evaluation to be in each of these  
> cases?
> 
> a, b = 1, 1  
> a, b = 1, nil  
> a, b = nil, 1  
> a, b = nil, nil
> 
> I'd expect return values of [1, 1], [1, nil], [nil, 1], [nil, nil] which  
> are all true.

Yes, I expect what you expect.

Also,

&nbsp;&nbsp;a, b = nil # a and b both get the value nil

> Now does this change when the RHS is an array instead of two values?  
> For example, would `a, b = [1, 1]` return a different value than `a, b =  
> [1, 1]`?

No, because you wrote them exactly the same!

Assuming you meant to compare these two:

&nbsp;&nbsp;a, b = 1, 1  
&nbsp;&nbsp;a, b = [1, 1]

then I expect them to behave exactly the same. I can see why you  
expect it to set a to [1,1] and b to nil, but that's just not the way  
it is. If I'm not wrong, Ruby actually converts the first line above  
into the second line behind the scenes. After all, that's precisely  
how you return multiple values from a method, or at least give the  
appearance of doing so.

&nbsp;&nbsp;def two\_values(x)  
&nbsp;&nbsp;&nbsp;&nbsp;[x\*2, x^2]  
&nbsp;&nbsp;end

&nbsp;&nbsp;a, b = two\_values(5)

From faint memory, to achieve the same thing in Perl you must wrap the  
LHS in an array. Ruby's equivalent would be

&nbsp;&nbsp;[a, b] = two\_values(5) # This doesn't work in Ruby, and it's not missed.

> Your example seems particularly devious in that it only has one value on  
> the RHS of the assignment.

No it doesn't. That's not a value, per se, it's a method call. The  
method call returns either an array, which assigns the two variables  
and activates the "if" branch, or nil, which activates the "else"  
branch.

I didn't approach this being devious or thinking it would be at all  
controversial. I simply have a good intuition for assignment in Ruby.

> This means that the second argument will be  
> assigned nil (because there is no value for it),

No. Try this in irb:

&nbsp;&nbsp;if \_ = (a, b = [5,2,16,100])  
&nbsp;&nbsp;&nbsp;&nbsp;puts a + b  
&nbsp;&nbsp;end

And this.

&nbsp;&nbsp;a, b = nil  
&nbsp;&nbsp;a, b = 1  
&nbsp;&nbsp;a, b = 1, 2  
&nbsp;&nbsp;a, b = [1, 2]  
&nbsp;&nbsp;a, b = [1,2,3,4,5]

&nbsp;&nbsp;a, \*b = nil  
&nbsp;&nbsp;a, \*b = 1  
&nbsp;&nbsp;a, \*b = 1, 2  
&nbsp;&nbsp;a, \*b = [1, 2]  
&nbsp;&nbsp;a, \*b = [1,2,3,4,5]

and see what these assignment operators return and what values get set  
to a and b.

> [...]
> 
> There are so many nuanced ruby edge cases one must know (and then must also  
> know the implementation of how it is being returned) to understand that  
> example that I think it has more overhead than it is worth.

There isn't a single nuance [1]; it all follows from understanding  
parallel assignment in Ruby. I didn't go out of my way to learn that.  
It must have been in one of the early Ruby books I read, or  
something, and something I use all the time (especially multiple  
returns from methods).

[1] in 1.9.3. The earlier versions have the nuance of

&nbsp;&nbsp;a, b = nil # Returns [nil] instead of nil.

That pre-1.9.3 behaviour is contrary to what I've always expected and  
I'm glad to see it corrected. I can only surmise that the syntax  
error "multiple assignment in conditional" is a hangover from those  
days as a (fair) warning that it's not going to do what you expect,  
and no good can come of it. They've changed the behaviour, but left  
the completely unnecessary syntax error.

Gavin

> **···**
>
> On Thu, Feb 2, 2012 at 8:03 AM, Josh Cheek \<josh.cheek@gmail.com\> wrote:

---

<div class="post-metadata">

**Author:** ![GS1](https://avatars.discourse-cdn.com/v4/letter/g/4491bb/32.png) [@GS1](https://rubytalk.org/u/GS1)\
**Post date:** [2 February 2012 11:55 UTC](https://rubytalk.org/t/multiple-assignment-in-conditional/64737/20 "2012-02-02T11:55:40Z")

</div>

Done and done!

&nbsp;&nbsp;def week\_and\_day(date)  
&nbsp;&nbsp;&nbsp;&nbsp;if not self.include? date  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil  
&nbsp;&nbsp;&nbsp;&nbsp;elsif \_ = (week, day = @t1.week\_and\_day(date))  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[week, day]  
&nbsp;&nbsp;&nbsp;&nbsp;elsif \_= (week, day = @t2.week\_and\_day(date))  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[week + @t1.number\_of\_weeks, day]  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end

I guess I need to document a Ruby 1.9.3+ requirement 🙂

> **···**
>
> On Thu, Feb 2, 2012 at 7:15 AM, Joel VanderWerf \<joelvanderwerf@gmail.com\> wrote:
> 
> > You can trick ruby:
> > 
> > def foo; nil; end
> > 
> > if (\_ = (a, b = foo)) [...]

[Next page](https://rubytalk.org/t/multiple-assignment-in-conditional/64737.md?page=2)
