I don't understand the following:
3.times { |i| puts(i) } # ok
3.times.class # Enumerator
n = 3.times
n.class # Enumerator
n { |i| puts(i) } # error!?
To a new Ruby student this error seems 'conceptually wrong'.
Playing around a bit I've discovered that this works:
n.each { |i| puts(i) }
As does:
3.times.each { |i| puts(i) }
Does this inconsistency result from a parser-level layer of 'syntactic
sugar'? I'm also getting a sense that a 'block' is a parser-level
construct,
and a 'Proc' is an execution-level object.
So, a related question: given an Enumerator and a 1-ary Proc (lambda):
n = 3.times
f = lambda { |i| puts(i) }
What expression allows us to 'map' or 'apply' the Proc to each
enumerated value?
There just seems to be something really 'wrong' about how Ruby treats
functions:
def f2(i)
puts(i)
end
f2.class # error!?
Functions are not first-class objects? I actually have no idea what f2
is. Clearly its not a symbol bound to an object. It's 'something else'.
Intuitively I would have expected the follow two constructs to produce
operatively identical objects:
def f2(i)
puts(i)
end
f2 = lambda { |i| puts(i) }
I'm really puzzled by this. Coming from years of programming in Scheme
I'm quite used to dealing with syntax-layer transformations. But there
is evidently something else going on with Ruby that violates a lot of my
intuitions and expectations. I'm hoping that once I understand it better
it will start to look 'elegant' and 'beautiful', but right now it looks
kinda 'scary' and 'repugnant'.
Help please!
- Dave
on 2013-01-21 20:20
on 2013-01-21 20:50
Subject: Enumerator usage Date: Tue 22 Jan 13 04:20:57AM +0900 Quoting David Richards (lists@ruby-forum.com): > I don't understand the following: > > 3.times { |i| puts(i) } # ok > 3.times.class # Enumerator > n = 3.times > n.class # Enumerator > n { |i| puts(i) } # error!? > > To a new Ruby student this error seems 'conceptually wrong'. Ruby documentation is well-made. Make good use of it! If you type ri Integer#times you will read: --8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<-- ------------------------------------------------------------------------------ int.times {|i| block } -> self int.times -> an_enumerator ------------------------------------------------------------------------------ Iterates block int times, passing in values from zero to int - 1. If no block is given, an enumerator is returned instead. --8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<-- In your first example you pass a block, so it returns self. In the second example, you do not provide a block, and an enumerator is returned. Note that if you type 3.times { |i| puts(i) }.class you will get Integer (self, in this case, is the integer 3). What is an enumerator, then (which is returned by the Integer#times methods when you do not provide a block)? Use the documentation: read with care what you obtain when you type ri Enumerator > There just seems to be something really 'wrong' about how Ruby treats > functions: > > def f2(i) > puts(i) > end > > f2.class # error!? With def you define a method of the current class (or a method of the Object class if you are not defining your own class). You do NOT define a variable. If you want a variable to contain the reference to your new method, you must type vrb=method(:f2) and vrb will be an instance of the Method class, containing a reference to your method. > I'm hoping that once I understand it better > it will start to look 'elegant' and 'beautiful', but right now it looks > kinda 'scary' and 'repugnant'. 'scary' and 'repugnant' are two concepts that express fear. Fear is the first enemy that has to be won on the path of growth... Ruby is just different from what you are used to. But it works.
on 2013-01-21 21:22
On 21 Jan 2013, at 19:20, David Richards <lists@ruby-forum.com> wrote: > Playing around a bit I've discovered that this works: > and a 'Proc' is an execution-level object. > functions: > Intuitively I would have expected the follow two constructs to produce > is evidently something else going on with Ruby that violates a lot of my > intuitions and expectations. I'm hoping that once I understand it better > it will start to look 'elegant' and 'beautiful', but right now it looks > kinda 'scary' and 'repugnant'. > > Help please! In Ruby objects are not first first class. The commonly given reason for this is that non-first-class blocks are faster because you don't have to create objects to use them: http://mudge.name/2011/01/26/passing-blocks-in-rub... Alan
on 2013-01-21 21:31
> 'scary' and 'repugnant' are two concepts that express fear. Fear is > the first enemy that has to be won on the path of growth... Let me respond to this part of your reply first, to get it out of the way. In this context, 'scary' should be taken to mean "very difficult and time-consuming to understand due to gross conceptual inconsistencies and poorly conceived design." For a definition of 'repugnant' please visit review the specifications for ANSI COBOL: http://pic.dhe.ibm.com/infocenter/pdthelp/v1r1/ind... Fear has nothing whatsoever to do with what I'm inquiring about. > Ruby is just different from what you are used to. But it works. COBOL also works. ------- As for the other parts of your response, thanks. I'll have a closer look at the language spec in the coming days. My questions are arising from carefully working through of Collingbourne's "The Book of Ruby", so it's not as if I'm floundering away in the dark, on my own, ignoring external resources. For the record, on my system: ri Integer Nothing known about Integer So I'll also have to figure out why that is not working. Thanks again for your responses. _ Dave
on 2013-01-21 21:37
On Mon, Jan 21, 2013 at 8:20 PM, David Richards <lists@ruby-forum.com> wrote: > I don't understand the following: > > 3.times { |i| puts(i) } # ok > 3.times.class # Enumerator > n = 3.times > n.class # Enumerator > n { |i| puts(i) } # error!? Yes, because there is no method "n". The block makes it parse as a method call. > Does this inconsistency result from a parser-level layer of 'syntactic > sugar'? I'm also getting a sense that a 'block' is a parser-level > construct, > and a 'Proc' is an execution-level object. In a way: Proc is the class of the block instance: irb(main):006:0> def f(&b) b end => nil irb(main):007:0> x = f {|a| puts a} => #<Proc:0x9284660@(irb):7> irb(main):008:0> x.class => Proc > So, a related question: given an Enumerator and a 1-ary Proc (lambda): > > n = 3.times > f = lambda { |i| puts(i) } > > What expression allows us to 'map' or 'apply' the Proc to each > enumerated value? Invoking method #each as you've shown above. More correctly, invoking *any* method will do. Some methods just ignore the block. > There just seems to be something really 'wrong' about how Ruby treats > functions: > > def f2(i) > puts(i) > end > > f2.class # error!? Ruby is not a functional language so methods are not first class objects. > Functions are not first-class objects? I actually have no idea what f2 > is. Clearly its not a symbol bound to an object. It's 'something else'. Keyword "def" introduces a method definition. The method is bound to a class (what class depends on context) under the identifier given. > Intuitively I would have expected the follow two constructs to produce > operatively identical objects: > > def f2(i) > puts(i) > end > > f2 = lambda { |i| puts(i) } They won't. > I'm really puzzled by this. Coming from years of programming in Scheme > I'm quite used to dealing with syntax-layer transformations. But there > is evidently something else going on with Ruby that violates a lot of my > intuitions and expectations. I'm hoping that once I understand it better > it will start to look 'elegant' and 'beautiful', but right now it looks > kinda 'scary' and 'repugnant'. It will be easier for you if you stop expecting Ruby to be a functional programming language - it isn't. As simple as that. Ruby is a dynamically but strictly typed object oriented programming language. Even though it has some support for functional style programming and also real closures. Cheers robert
on 2013-01-21 21:40
Subject: Re: Enumerator usage Date: Tue 22 Jan 13 05:31:43AM +0900 Quoting David Richards (lists@ruby-forum.com): > COBOL also works. I should know... Back in 1978, during my last year at high school, I did a course of COBOL programming. Believe me: there is some difference ;-) > For the record, on my system: > > ri Integer > Nothing known about Integer > > So I'll also have to figure out why that is not working. mm. Ruby without ri is a very lonely chap. I believe there are equivalent resources online, but I can't say wheræ > Thanks again for your responses. Glad to be of help! Carlo
on 2013-01-21 21:58
Robert Klemme wrote in post #1093088: > Ruby is not a functional language so methods are not first class > objects. > It will be easier for you if you stop expecting Ruby to be a > functional programming language - it isn't. As simple as that. Ruby > is a dynamically but strictly typed object oriented programming > language. Even though it has some support for functional style > programming and also real closures. That puts it in perspective. Out with the old idioms, in with the new; the price to be paid for doing away with all those parentheses. Thanks. _ Dave
on 2013-01-22 01:05
Robert Klemme wrote in post #1093088:
> Ruby is not a functional language so methods are not first class objects.
I've just learned that methods can be first class objects:
add_two = 2.method(:+)
add_two.class # => Method
(1..3).map(&add_two) # => [3,4,5]
Using this idiom, methods become first class objects.
It appears that Ruby may well facilitate many (if not all) of the
functional idioms I'm fond of using. There may be some performance
penalties associated with some of these idioms however.
So this whole topic area seems much more robust and arcane than is
apparently commonly understood. It's not as simple as "Ruby is not a
functional language" and "methods are not first class objects". It's
obviously a bigger matter of understanding the Ruby class hierarchy and
full syntax.
I've only been studying Ruby for three days and I'm still obviously
struggling with the basics. But at least now I see that Ruby has some
'hidden' potential.
_ Dave
on 2013-01-22 01:42
On Jan 21, 2013, at 2:20 PM, David Richards <lists@ruby-forum.com> wrote: > Does this inconsistency result from a parser-level layer of 'syntactic > sugar'? I'm also getting a sense that a 'block' is a parser-level > construct, > and a 'Proc' is an execution-level object. I don't think it is stressed enough that a block is a syntactic structure that is *always* part of a method call. When a method executes, the block associated with the method call can be executed implicitly via the 'yield' keyword, or explicitly reified into a Proc object. Once captured within an Proc object it can be executed via the #call or #[] methods on the object (which are instance methods of the Proc class). The reification (or capture) can be triggered via the block argument in a formal argument list: def foo(arg0, &block) yield("arg to the block) # call implicit block block.call("arg to block") # call same block via Proc#call instance method block["arg to block"] # call same block via Proc#[] instance method end or the reification can be triggered on demand: def foo(arg0) if some_condition) captured = Proc.new # Proc.new without explicit block captures current implicit block else yield("arg to block") # call implicit block end end Proc objects can also be created via the Kernel#proc method call: addition = proc { |a,b| a + b } multiplication = proc { |c,d| c * d } puts addition.call(1,2) # => 3 puts multiplication.call(2,10) # => 20 In these examples, the blocks are syntactically part of the calls to to the proc method. puts addition.class # => Proc puts multiplication.class # => Proc Gary Wright
on 2013-01-22 03:25
Gary Wright wrote in post #1093103: > On Jan 21, 2013, at 2:20 PM, David Richards <lists@ruby-forum.com> > wrote: >> Does this inconsistency result from a parser-level layer of 'syntactic >> sugar'? I'm also getting a sense that a 'block' is a parser-level >> construct, >> and a 'Proc' is an execution-level object. > > I don't think it is stressed enough that a block is a syntactic > structure But it is possible to create a block programmatically during runtime by creating a Proc and converting it to a block with the & operator. > that is *always* part of a method call. This page helped clear up a lot of my confusion: http://eli.thegreenplace.net/2006/04/18/understand... Now I understand that blocks are a shorthand notation than many Ruby programmers avoid. Depending on the case, using blocks may make the program easier or harder to understand. But more than a mere matter of style, there are performance penalties involved, depending on which constructs are used: http://www.confreaks.com/videos/427-rubyconf2010-z... > When a method executes, the block associated with the method call can > be executed implicitly via the 'yield' keyword, or explicitly reified > into a Proc object. Once captured within an Proc object it can be > executed > via the #call or #[] methods on the object (which are instance methods > of the Proc class). And Procs can be converted into blocks, using the '&' operator. multiply = lambda{ |x| x*2 } [1,2,3].map &multiply > The reification (or capture) can be triggered via the block argument in > a formal argument list: > > def foo(arg0, &block) > yield("arg to the block) # call implicit block > block.call("arg to block") # call same block via Proc#call > instance method > block["arg to block"] # call same block via Proc#[] instance > method > end > > or the reification can be triggered on demand: > > def foo(arg0) > if some_condition) > captured = Proc.new # Proc.new without explicit block > captures current implicit block > else > yield("arg to block") # call implicit block > end > end Understood. Here's a cleaned-up version of your example code with example calls: def foo(arg0, &block) yield("arg to yield") # call implicit block block.call("arg to block.call") # call same block via Proc#call instance method block["arg to block[]"] # call same block via Proc#[] instance method end foo(nil){|x| puts(x)} def foo2(arg0) if (arg0) captured = Proc.new # Proc.new without explicit block captures current implicit block captured["Proc.new"] else yield("yield") # call implicit block end end foo2(true) {|x| puts(x)} foo2(false){|x| puts(x)} > Proc objects can also be created via the Kernel#proc method call: > > addition = proc { |a,b| a + b } > multiplication = proc { |c,d| c * d } > > puts addition.call(1,2) # => 3 > puts multiplication.call(2,10) # => 20 > > In these examples, the blocks are syntactically part of the calls to to > the proc method. > > puts addition.class # => Proc > puts multiplication.class # => Proc All understood. It's coming into focus. Thanks. _ Dave
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.