# Question about case statement and lambdas

**URL:** <https://www.ruby-forum.com/t/question-about-case-statement-and-lambdas/152092>\
**Category:** Ruby\
**Created:** [October 30, 2008, 3:25am UTC](https://www.ruby-forum.com/t/question-about-case-statement-and-lambdas/152092 "2008-10-30T03:25:21Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![jeff](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e19b73/32.png) [@jeff](https://www.ruby-forum.com/u/jeff)\
**Post date:** [October 30, 2008, 3:25am UTC](https://www.ruby-forum.com/t/question-about-case-statement-and-lambdas/152092/1 "2008-10-30T03:25:21Z")

</div>

I fear this has an obvious answer that I’m just not figuring out.

Sometimes I dive into the Rails source code to see how something works  
(don’t worry, this isn’t a Rails question). I have been looking at  
the implementation of the named\_scope feature in Rails, and found some  
dense Ruby indeed. As an exercise, I decided to refactor it to be  
more readable and to force me to understand what it’s doing. A series  
of simple refactorings has led to a change in behavior, and I’m not  
sure why.

Along the way, I ended up with this method (extracted from the  
original implementation):

# Starting point

def create\_lambda\_for\_scope(name, options, &block)  
lambda do |parent\_scope, \*args|  
Scope.new(parent\_scope, case options  
when Hash  
options  
when Proc  
options.call(\*args)  
end, &block)  
end  
end

All tests still pass at this point… but that inline case statement  
bugs me, so I refactor it out to a temporary variable:

# Attempt #2

def create\_lambda\_for\_scope(name, options, &block)  
lambda do |parent\_scope, \*args|  
arg = case options  
when Proc  
options.call(\*args)  
when Hash  
options  
end  
Scope.new(parent\_scope, arg, &block)  
end  
end

Tests still pass, yessss! But, I still hate seeing that case  
statement. So I now do this:

# Attempt #3:
 arg = (options.is\_a?(Proc) ? options.call(\*args) : options) Scope.new(parent\_scope, arg, &block) 

Test still pass, I’m about to declare victory. But I can’t resist one  
more simplification to remove the temporary. Since the case statement  
is so simple, it looks to me like, if options is a Hash, don’t do  
anything, but if it’s a Proc, then call it.

So I decide to just get rid of the temporary and simply assign a new  
value to options only if it’s a Proc:

# Attempt #4
 options = options.call(\*args) if options.is\_a?(Proc) Scope.new(parent\_scope, options, &block) 

Kaboom, several tests now fail.

Is there something I don’t understand about the difference between #3  
and #4? I’m guessing it’s something to do with the fact that I’m  
building a lambda here, so there’s closure scope to be concerned  
about… but still, #3 and #4 look semantically the same to me.

Any insight or ideas would be appreciated.

Thanks!  
Jeff

---

<div class="post-metadata">

**Author:** ![jeff](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e19b73/32.png) [@jeff](https://www.ruby-forum.com/u/jeff)\
**Post date:** [October 30, 2008, 3:41am UTC](https://www.ruby-forum.com/t/question-about-case-statement-and-lambdas/152092/2 "2008-10-30T03:41:45Z")

</div>

From: Jeff [[mailto:removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)]

# # Attempt #4

# 

# options = options.call(\*args) if options.is\_a?(Proc)

# Scope.new(parent\_scope, options, &block)

# 

the only difference i see is that #4 modifies options

---

<div class="post-metadata">

**Author:** ![jeff](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e19b73/32.png) [@jeff](https://www.ruby-forum.com/u/jeff)\
**Post date:** [October 30, 2008, 4:48am UTC](https://www.ruby-forum.com/t/question-about-case-statement-and-lambdas/152092/3 "2008-10-30T04:48:33Z")

</div>

Hi –

On Thu, 30 Oct 2008, Jeff wrote:

> Along the way, I ended up with this method (extracted from the  
> end, &block)  
> when Proc
> 
> Is there something I don’t understand about the difference between #3  
> and #4? I’m guessing it’s something to do with the fact that I’m  
> building a lambda here, so there’s closure scope to be concerned  
> about… but still, #3 and #4 look semantically the same to me.
> 
> Any insight or ideas would be appreciated.

Expanding on Botp’s point about options being changed:

The problem is that if options is a Proc the first time you call the  
lambda, it isn’t the second time. It’s still whatever got assigned to  
it.

Say options.call(\*args) returns “Hello!”. The second time you call the  
lambda, options will be “Hello!”, and not a Proc. “Hello!” will then  
be sent to Scope.new, which is probably not going to be right.

That’s why you need a temporary variable or an inlined conditional.  
You don’t want to trample the options variable itself, since it’s the  
only place where the original options are stored.

David

---

<div class="post-metadata">

**Author:** ![jeff](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e19b73/32.png) [@jeff](https://www.ruby-forum.com/u/jeff)\
**Post date:** [October 30, 2008, 9:23am UTC](https://www.ruby-forum.com/t/question-about-case-statement-and-lambdas/152092/4 "2008-10-30T09:23:11Z")

</div>

David A. Black wrote:

> Expanding on Botp’s point about options being changed:
> 
> The problem is that if options is a Proc the first time you call the  
> lambda, it isn’t the second time. It’s still whatever got assigned to  
> it.

And whilst at first glance it seems that ‘options’ is actually “just” a  
local method argument which drops out of scope when the method returns,  
it is of course bound into the environment of the lambda (i.e. the  
closure), and persists there.

---

<div class="post-metadata">

**Author:** ![jeff](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e19b73/32.png) [@jeff](https://www.ruby-forum.com/u/jeff)\
**Post date:** [October 30, 2008, 1:45pm UTC](https://www.ruby-forum.com/t/question-about-case-statement-and-lambdas/152092/5 "2008-10-30T13:45:57Z")

</div>

Hi –

On Thu, 30 Oct 2008, Brian C. wrote:

> closure), and persists there.  
> Yes, I should have made that explicit – I had the impression the OP  
> was hip to that part.

David

---

<div class="post-metadata">

**Author:** ![jeff](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e19b73/32.png) [@jeff](https://www.ruby-forum.com/u/jeff)\
**Post date:** [October 30, 2008, 2:41pm UTC](https://www.ruby-forum.com/t/question-about-case-statement-and-lambdas/152092/6 "2008-10-30T14:41:03Z")

</div>

On Oct 29, 10:47 pm, “David A. Black” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> That’s why you need a temporary variable or an inlined conditional.  
> Seehttp://www.rubypal.comfor details and updates!  
> Ah! Thanks for that explanation! Makes perfect sense now.

Jeff

[purpleworkshops.com](http://purpleworkshops.com)

---

<div class="post-metadata">

**Author:** ![jeff](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e19b73/32.png) [@jeff](https://www.ruby-forum.com/u/jeff)\
**Post date:** [October 30, 2008, 2:42pm UTC](https://www.ruby-forum.com/t/question-about-case-statement-and-lambdas/152092/7 "2008-10-30T14:42:48Z")

</div>

On Oct 30, 3:22 am, Brian C. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> ## closure), and persists there.
> 
> Posted viahttp://www.ruby-forum.com/.

Excellent… thanks for that insight.

Jeff

[purpleworkshops.com](http://purpleworkshops.com)
