The Artima Developer Community
Sponsored Link

Articles Forum
Blocks and Closures in Ruby

14 replies on 1 page. Most recent reply: Jan 3, 2004 10:31 AM by rubyfan

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 14 replies on 1 page
Bill Venners

Posts: 2284
Nickname: bv
Registered: Jan, 2002

Blocks and Closures in Ruby Posted: Dec 21, 2003 9:00 PM
Reply to this message Reply
Advertisement
Yukihiro Matsumoto, the creator of the Ruby programming language, talks with Bill Venners about two kinds of nameless functions in Ruby: blocks and closures.

Read this Artima.com interview with the creator of Ruby:

http://www.artima.com/intv/closures.html

What do you think of Matz's comments?


Carl Manaster

Posts: 24
Nickname: cmanaster
Registered: Jun, 2003

Re: Blocks and Closures in Ruby Posted: Dec 23, 2003 12:12 AM
Reply to this message Reply
I'm interested in why blocks are so widely known as "nameless functions". It just strikes me as curious when a thing is defined in terms of what it isn't, or what it doesn't have (in this case, a name). What is so important about blocks not being named? What would be different about the language if, say, only named functions could be given to loops, etc.? Or, what is the more general term or concept that encompasses both named and nameless functions? What would a language be like if it were built around these things instead of imposing the distinction of namedness on them?

Peter Hickman

Posts: 41
Nickname: peterhi
Registered: Mar, 2003

Re: Blocks and Closures in Ruby Posted: Dec 23, 2003 6:41 AM
Reply to this message Reply
The simplest benefit is that you do not have to try to keep thinking up meaningful unique names for blocks of code that are only used in one place and that the code exists where it is used rather than defined in a procedure / function 100+ lines before or after the point that it is used. When the blocks are quite small this shrinks the code as you are not writing loads of 'structural'(?) code.

Additionialy blocks dispense with the need to create surrogate variables that the programmer is not interested in, for example:


h.each_key {|k|
puts h[k]
}


Here h is a hash and the code gived iterates over the hash passing the key into the block to be processed - in this case used to print out the value. Note that the only variables involved are the hash and the key. Try rewriting that in Java without introducing any more 'structural' variables.

Also hash also has this iterator:


h.each_pair {|k,v|
puts v
}


which returns the key and the value.

You can probably guess what h.each_value does.

You can also extend (or subclass if you wish) the hash class to provide any number of iterators you desire.

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

Re: Blocks and Closures in Ruby Posted: Dec 23, 2003 9:45 AM
Reply to this message Reply
why blocks are so widely known as "nameless functions"
Often called 'anonymous functions' - simply that they are functions that don't have a name.

More interesting to ask why they are also called lambda functions, see the informal description:
http://en2.wikipedia.org/wiki/Lambda_calculus

term or concept that encompasses both named and nameless functions?
Functions.

What would a language be like
That's what functional programming languages are like - name functions and anonymous functions are used interchangeably.

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

Re: Blocks and Closures in Ruby Posted: Dec 23, 2003 11:26 AM
Reply to this message Reply
the first reason is to respect the history of Lisp
How strange then to talk of blocks (like this Smalltalk) rather than lambda


dictionary keysDo: [:key|
*do something with key*
]

dictionary keysAndValuesDo: [:key :value|
*do something with key and value*
]


In an OO language like Smalltalk, all the 'named functions' are object methods - they are message sends to some object. In contrast, Smalltalk blocks are standalone functions.

Dave Benjamin

Posts: 10
Nickname: ramenboy
Registered: Nov, 2003

The power of anonymity Posted: Dec 23, 2003 9:50 PM
Reply to this message Reply
The really powerful thing about anonymous closures (functions or blocks) is not so much that they are anonymous, but that they can be used as expressions. This means that I can say things like "the addition of 5 to something" just as easily as I can say "5". I don't have to announce beforehand that "when I say 'add5', I mean the addition of 5 to something", and that's a good thing, because "add5" isn't a particularly reusable function anyway, so why name it? I'd rather avoid the naming issue altogether and say "map the addition of 5 to every number in this list". That's one thing you can do with anonymous closures.

Another nice feature of anonymous closures is that I have more control over the order of operations. Compare (not Ruby code, because I'm still getting my feet wet with Ruby myself):

function do_it() {
print 'doing it'
}

// call do_it after 500 ms
after(500, do_it)

with:

after(500, function() {
print 'doing it'
})

In the second case, it says what I mean. After 500ms, print "doing it". This is a very straightforward and convenient way to do asynchronous / event-driven programming.

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

Re: The power of anonymity Posted: Dec 24, 2003 10:55 AM
Reply to this message Reply
> Another nice feature of anonymous closures is that I have
> more control over the order of operations

Seems like this is the same with named or anonymous functions (in Nice http://nice.sourceforge.net/index.html )

void after(int msDelay, void->void fun){
fun();
}

void main(String[] args){
// named function
after(msDelay: 500, fun: print_doing_it);

// anonymous function
after(msDelay: 500, fun: ()=>{ println("doing it 2"); });
}

void print_doing_it(){
println("doing it");
}

Dave Benjamin

Posts: 10
Nickname: ramenboy
Registered: Nov, 2003

Re: The power of anonymity Posted: Dec 24, 2003 12:34 PM
Reply to this message Reply
> > Another nice feature of anonymous closures is that I
> > have more control over the order of operations
>
> Seems like this is the same with named or anonymous
> functions (in Nice http://nice.sourceforge.net/index.html

Right, but the point I was trying to make was that by supporting closures as expressions you can say "after this, do that" instead of "after this, do that thing which I defined somewhere else". But it looks like Nice supports both.

Nice is nice. =)

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

Re: The power of anonymity Posted: Dec 24, 2003 1:11 PM
Reply to this message Reply
by supporting closures as expressions you can say "after this, do that" instead of "after this, do that thing which I defined somewhere else"
We can create an expression that will apply a function after a specific delay, and hold that expression in a variable and invoke it a little later:
void->void delayedFunction(int msDelay, void->void fun){
return ()=>{ after(msDelay, fun); };
}

void main(String[] args){
let f = delayedFunction(msDelay: 500, fun: do_it);
f();
f();
}

void do_it(){
println("doing it");
}

void after(int msDelay, void->void fun){
fun();
}

Yes, Nice is nice, and has first class functions (both named and anonymous).

best wishes, Isaac

gabriele renzi

Posts: 5
Nickname: riffraff
Registered: Nov, 2003

Re: The power of anonymity Posted: Dec 26, 2003 6:55 PM
Reply to this message Reply
> Another nice feature of anonymous closures is that I have
> more control over the order of operations. Compare (not
> Ruby code, because I'm still getting my feet wet with Ruby
> myself):

well, I suppose it is:
after(500) do
puts 'doing it'
end

And I agree that this is more readable :)

BTW, some more cool usages of blocks:

- to pass a 'discriminating' function, like in
Enumerable.sort()

array_of_persons.sort { |p1,p2|
p1.name <=> p2.name
}

or, even better, in sort_by() (that internally does a shwartzian transform)

array_of_persons.sort_by {|p| p.name}


- for threads:
Thread.new { do stuff}

- for event/signals/callbacks:
at_exit { puts "existing now.."}
or
button.onclick { puts "clicked"}

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

Re: The power of anonymity Posted: Dec 28, 2003 10:10 AM
Reply to this message Reply
Are there new uses that didn't exist in Smalltalk?

Here are some Smalltalk equivalents:

> - to pass a 'discriminating' function, like in
> Enumerable.sort()
>
> array_of_persons.sort { |p1,p2|
> p1.name <=> p2.name
> }


Smalltalk has a special SortedCollection, so we might say
array_of_persons asSortedCollection: [:p1 :p2| p1 name < p2 name ]

or for an in-place sort on the array
SequenceableCollectionSorter sort: array_of_persons using: [:p1 :p2| p1 name < p2 name ]

> or, even better, in sort_by() (that internally does a
> a shwartzian transform)
> array_of_persons.sort_by {|p| p.name}


'shwartzian transform' this caching optimization isn't built-in to Smalltalk.

> - for threads:
> Thread.new { do stuff}


t := [ do stuff ] fork.

or more interestingly

p := [ do stuff ] promise.

> - for event/signals/callbacks:
> at_exit { puts "existing now.."}
> or
> button.onclick { puts "clicked"}


Object when: anEventNameSymbol do: aBlock

(More often in the Event System a specific method symbol is used rather than aBlock.)

In Smalltalk even conditionals and loop statements are defined with blocks:

i<5 ifTrue: [ do something ].
[ i<5 ] whileTrue: [ do something ].

Joost de Vries

Posts: 19
Nickname: yoozd
Registered: May, 2003

Re: Blocks and Closures in Ruby Posted: Dec 31, 2003 4:57 AM
Reply to this message Reply
Ofcourse Matsumoto has done some impressive stuff in Ruby but I must say I think the way the keyword 'yield' works is not a good design. I have to scan the implementation of a method to find out wether the method needs or supports a block or closure.
I'd much prefer an interface declaration of the method that specifies clearly that it has an (optional) argument that is block or closure.

And since I now have spoiled the party of Ruby adulation I might as well add that I find Ruby too lacking in documentation to be workable.
Probably that's better in Japanese but then english is the lingua franca of software development.
Maybe they think that the source is the documentation but then you can't use an interface as an abstraction and thus reduce complexity. Theoretically you'd have to analyze all the code that your program uses, all the libraries down to the C-level, to find out wat it does. That's clearly not in tune with the weaknesses and strengths of humans. It's letting the human adapt to the computer.
Ofcourse there's the book by Thomas Hunt but I think API documentation, "what's new" etcetera is a requirement for a release of a serious programming language.

As a hobby language it's nice to play with Ruby for a few hours. But I'll use Python if I really need a scripting language for something. They're documentation is exemplary.

Happy Newyear,
Joost

rubyfan

Posts: 22
Nickname: rubyfan
Registered: Jan, 2004

Re: Blocks and Closures in Ruby Posted: Jan 1, 2004 9:36 PM
Reply to this message Reply
I think the way the keyword 'yield' works is not a good design. I have to scan the implementation of a method to find out wether the method needs or supports a block or closure.

If a method takes a block the last argument in the parameter list will be preceeded by a '&':

For example (not a very useful example, I admit):


def call_block(param,&b)
b.call(param)
end

call_block("Hello") { |p| puts p } #=> "Hello"


So you could do it this way instead of using yield (the two methods are essentially equivilent) and you could tell by looking at the method's param list that it takes a block.

And since I now have spoiled the party of Ruby adulation I might as well add that I find Ruby too lacking in documentation to be workable.

The pickaxe book (Programming Ruby by Dave Thomas and Andrew Hunt) is quite a good reference to get you started. Sure it doesn't have info on some of the newer included libraries (like REXML or YAML) but you can usually find docs on the newer items at:
http://www.ruby-doc.org/

I think API documentation, "what's new" etcetera is a requirement for a release of a serious programming language.
See: http://www.ruby-doc.org/stdlib/
What else are you looking for?

As a hobby language it's nice to play with Ruby for a few hours.
Gee, nobody ever told me that Ruby was a 'hobby' language. I wonder how I managed to get all that serious work done with a 'hobby' language? ;-) Oh, well, you can't please all the people all the time.

Joost de Vries

Posts: 19
Nickname: yoozd
Registered: May, 2003

Re: Blocks and Closures in Ruby Posted: Jan 3, 2004 5:27 AM
Reply to this message Reply
Phil, I knew that there is another way in Ruby to handle closures. I think the argument you mention is called a 'proc' object. My point was that the construction with 'yield' is bad design.
You will notice that Matsumoto takes the 'yield' approach as the way to explain it. I think it is somewhat the dominant approach in Ruby. So you will not be able to conclude on the basis of the interface that the method does not take a block or closure since there is a construction, that is often used that doesn't show up until you read the code.
I think it is a redundant construction that wastes a whole language keyword while the other construction is also more object-oriented. It does not follow Matsumatos principle of least surprise.
If you're from the planet Perl you'll think that's a feature of course. :-)

Concerning the documentation: the documentation of the standard lib has been set up 2003-11-23 so that wasn't there when I worked with Ruby in June and July. I remember that I ran rdoc over the stdlib and just found empty html. Looking at the dates in code comments I see that a lot of them have been added around november and december this year. Apparently people had the same opinion that it won't do without uptodate API docs.

I was very disappointed when I found the empty rdoc html, so this is a great improvement. Thanks for mentioning it. I had't noticed.

My 'hobby language' comment was a bit provocative I admit. My point is just that I can not deliver code to a customer on a platform that has no uptodate documentation. Especially since Ruby is an obscure language. With 'obscure' I mean that not a lot of developers are proficient in it. In the Netherlands at least. I'd be throwing a heap of unmaintainable code on customer.
So in that way I think that a language implementation that does not document it's standard libs and keep this uptodate is not fit for professional, commercial work. If you're just writing code for yourself it's no problem of course. (If you want to invest the time)

Anyhow,
Groeten,
Joost

rubyfan

Posts: 22
Nickname: rubyfan
Registered: Jan, 2004

Re: Blocks and Closures in Ruby Posted: Jan 3, 2004 10:31 AM
Reply to this message Reply
So in that way I think that a language implementation that does not document it's standard libs and keep this uptodate is not fit for professional, commercial work. If you're just writing code for yourself it's no problem of course. (If you want to invest the time)

Again, there is plenty of documentation of Ruby's standard libs. Most of us use the pickaxe book (Dave Thomas and Andy Hunt's Programming Ruby book), there is online documentation at http://www.ruby-doc.org. Other resources are available at http://rubygarden.org (a wiki) and http://www.rubyforge.net.

There are many of us doing "professional, commercial work" with Ruby. I am currently doing some for a very big, well known, household name company and there are several others in the same company using Ruby. And this isn't just new work in the last few months, it's been going on for a couple of years now. If, as you alledge, there is "no uptodate documentation" for Ruby's libraries, then how did we manage to get so much done in the language in a commercial setting?

Especially since Ruby is an obscure language. With 'obscure' I mean that not a lot of developers are proficient in it.

True, Ruby isn't as well known as Perl,Java or C++. However, when I need to bring a new developer up to speed with Ruby I give him/her a copy of the pickaxe book and if they're reasonably bright and have some background in OO programming they're starting to be productive in a couple of days and after a week or two they are making real contributions. So sure, it's not as common a language, but things tend to make sense and much of the standard lib is very intuitive without even having to reach for the documentation (which is available if you need it).
I've heard many times from people that they consider Ruby to be their most productive language even after only a couple of months using it.

See: http://www.rubygarden.org/ruby?RealWorldRuby
For more stories of Ruby being used in commercial, government and academic settings.

Flat View: This topic has 14 replies on 1 page
Topic: Collective Ownership of Code and Text Previous Topic   Next Topic Topic: Inappropriate Abstractions

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use