InfoQ

News

The state of the Lambda in Ruby 1.9

Posted by Werner Schuster on Jan 15, 2008

Community
Ruby
Topics
Dynamic Languages ,
Language ,
Programming ,
Domain Specific Languages
Tags
Language Features ,
Closures
Ruby's Blocks are one of the crucial features that allow to write concise and highly reusable algorithms. If nothing else, it helped to extinguish the venerable for loop. The concept has many names in other languages and theory:
  • lambda function
  • anonymous function
  • closure (e.g. the term used for the lamdba functions in Java 7)
    This is a somewhat confusing term, because the term closure also refers to the capturing of the scope surrounding the code. A Block doesn't necessarily need to capture the scope - this code
     x = lambda {|x,y| x + y} 
    doesn't use any free variables (i.e. variables that are unbound; x and y are declared in formal argument list), and hence doesn't require the creation of a closure
Blocks come in many shapes and forms in other languages, with a varying amount of verbosity. One of Ruby's influences, LISP, for instance uses this syntax:
 (lambda (arg) "hello world").
Another language influential in Ruby's design, Smalltalk, uses a very concise syntax using brackets:
 [arg| ^"hello world"].

Ruby's most convenient and often used syntax for Blocks is as a parameter to a function, which allows to simply append a Block surrounded by either do/end or braces {/}. Eg.
5.times {|x| puts x} 
It's convenient, and also allows idioms such as Builder, which allows to create hierarchical data structures very easily by using a nested Blocks. (Tip: An upcoming article here on InfoQ will explain the details of creating a Builder in Ruby - watch out for it in the 2nd half of January).

However, there was one problem: passing more than one Block to a function or method didn't work as easily. It was possible, but not with this shorthand. Instead, a Block had to be created using either the Proc.new {} or lambda {} notations. While not horrible, these options are much more verbose and introduce unwelcome tokens that clutter up the code. (Note: Proc.new {} and lambda {} notations have subtle differences as well, but this is not significant in this context).

Workarounds are possible for this in certain situations. For instance, if an API call requires multiple Blocks, helper functions could be mixed into the class to a) help with Blocks and b) have the side effect of looking like named arguments:
find (predicate {|x,y| x < y}, predicate{|x,y| x > 20}) 
The predicate function is nothing more than:
def predicate(&b)
 b
end
I.e. returns the Block. Whether this is appropiate or not depends on the specific use case. In this case, the shown code is - arguably - more expressive then the equivalent:
find (lambda{|x,y| x < y}, lambda {|x,y| x > 20}) 

Why? Because lambda leaks implementation details about how this is implemented - with one block argument, no extra keyword would be needed. The predicate solution annotates the code and generates the lambda. To be clear: this is a workaround.

Ruby 1.9 now introduces an new, more concise syntax for creating lambda functions:
x = ->{puts "Hello Lambda"} 
The new syntax is shorter and removes the unfamiliar term lambda. To be clear: this is syntactic sugar. It does, however, help to write APIs that yield very readable code. Some of these APIs might be called "internal DSLs", although the definition for those are quite fuzzy. For these, the new lambda definition helps getting rid of the quite obscure term "lambda" in the middle of otherwise purely domain or problem specific code.

Sidu Ponnappa reports about another syntax change in 1.9:
Explicitly invoking one block from another in Ruby 1.9.0. This method was something I didn't even cover in my previous post, because the parser would simply blow up when parsing |*args, &block|. Here's what it looks like. [..]
class SandBox
 def abc(*args)
  yield(*args)
end
define_method :xyz do
 |*args, &block|
 block.call(*args)
 end
end
SandBox.new.abc(1,2,3){|*args| p args} # => [1, 2, 3]
This code doesn't work in Ruby 1.8.x - it actually fails at the parser stage with:
benchmark3.rb:8: syntax error, unexpected ',', expecting '|' 
define_method :xyz do |*args, &block|
 ^
benchmark3.rb:11: syntax error, unexpected kEND, expecting $end
In Ruby 1.9, this works fine.

Another change in 1.9 fixes a long standing issue: block arguments are now local. Take this code:
foo = "Outer Scope"
[1,2,3].each{|foo|
 foo = "I'm not local to this block"
}
puts foo
In 1.8, the code would print "I'm not local to this block", wheras in 1.9 it prints "Outer Scope". In short, blocks now behave as expected: the block argument shadows the variable of the same name in the outher scope inside the block. (Let's preempt the question "How can I access the variable in the outer scope?". You don't - just choose a different name for the block argument).

What do you think about the Ruby 1.9 lambda/block changes? Do they address all existing concerns or are there other problems left?

Tip: see all Ruby 1.9 stories on InfoQ.
I don't know by Michael Neale Posted Jan 15, 2008 5:03 PM
new syntax comment by Roger Pack Posted Sep 16, 2008 2:59 PM
SandBox example segfaults Ruby 1.9 by Paul Harvey Posted Dec 14, 2008 12:50 AM
  1. Back to top

    I don't know

    Jan 15, 2008 5:03 PM by Michael Neale

    I thought the lambda word was clear, and makes perfect sense what you are doing. I guess its just taste. the shadowing is nice, and will either break a lot of existing code (which was bad to start with) and/or get rid of a confusing class of bugs.

  2. Back to top

    new syntax comment

    Sep 16, 2008 2:59 PM by Roger Pack

    Note also that 1.9 allows for default parameters to proc's:
    z = proc {|x, y = 3| 33 }

  3. Back to top

    SandBox example segfaults Ruby 1.9

    Dec 14, 2008 12:50 AM by Paul Harvey

    I just generated a bug report based on your SandBox example code that actually Segfaults Ruby 1.9.

    See redmine.ruby-lang.org/issues/show/871

    Cheers

Educational Content

Brian Marick on 4 Challenges and 5 Guiding Values of Agile Software Development

Brian Marick takes us through a quick tour of the most important values and challenges to adopting Agile successfully (they aren't the typical challenges and values we hear in the community).

Are You a Software Architect?

The line between development and architecture is tricky. Does it exist at all? Is an ivory tower actually needed? There's a balance in the middle, but how do you move from developer to architect?

Agile – A Way of Life and Pragmatic Use of Authority

The word 'authority' sometimes produces an allergic response in hard-line agilists. Freedom and authority – both are bad if misused and both are good if used in right spirit for a noble cause.

Getting Started with Grails, Second Edition

"Getting Started with Grails" brings you up to speed on this modern web framework. Companies as varied as LinkedIn, Wired, and Taco Bell are all using Grails. Are you ready to get started as well?

Using ITIL V3 as a Foundation for SOA Governance

Those familiar with only ITIL V2 often scoff at the thought that ITIL could serve as a governance framework for SOA. With ITIL V3, the focus of the framework shifted towards service-orientation.

Adrian Colyer on AspectJ, tc Server and dm Server

SpringSource CTO Adrian Colyer discusses AspectJ, SpringSource's dm Server and tc Server products, OSGi and Scrum.

Adam Wiggins on Heroku

Heroku's Adam Wiggins talks about Rails, Background Jobs, Add-Ons, Ruby, and how Heroku manages to work around Ruby's inefficiencies using Erlang and other languages.

SOA as an Architectural Pattern: Best Practices in Software Architecture

For Grady Booch the foundation of a good architecture is patterns, SOA being just one of many patterns. In this Second Life presentation, Booch attempts to bring more clarity on what architecture is.