I find this block behavior befuddling, and would like to understand what is going on. Can you direct me to the appropriate part of Pickaxe where the behavior of Hash#each is clearly explained?
irb(main):008:0> h.each {|x, y, z| p x}
"one"
"two"
"three"
=> {"one"=>1, "two"=>2, "three"=>3}
How is it that declaring an additional block parameter 'y' changes the value of 'x' in the block? And where is it documented that Hash#each can yield a two-element array for each element?
Others may want to comment, but your questions are answered in the ri doc.
(Try taking the "z" parameter out of the 2nd code snippet, and print the value for both x AND y.)
hsh.each {| key, value | block } -> hsh
------------------------------------------------------------------------
Calls _block_ once for each key in _hsh_, passing the key and value
to the block as a two-element array. Because of the assignment
semantics of block parameters, these elements will be split out if
the block has two formal parameters. Also see +Hash.each_pair+,
which will be marginally more efficient for blocks with two
parameters.
h = { "a" => 100, "b" => 200 }
h.each {|key, value| puts "#{key} is #{value}" }
I'm asking the above because I'm trying to understand what it means for Hash to be an Enumerable (and therefore to have collect and inject methods). Playing around with this just leads me further into confusion:
We crossed while posting our latest comments. Looks like 'ri' says something that Pickaxe doesn't, because Pickaxe (page 537 of the PDF version) makes no mention of Hash#each with one block parameter, only with two. I guess you'll explain "the assignment
semantics of block parameters, these elements will be split out if
the block has two formal parameters" in a later lecture....
x will be a two-element Array. The 0'th element will be the key, the 1'th element will be the value.
With two parameters { |x, y| . . . }
x is the key, y the value.
What is going on behind the scenes is that you can do assignments like this in Ruby (try typing the following sequence into irb):
x = [ 1, 2 ]
x, y = [ 1, 2 ]
x
y
Now, about the documentation. I think there has been some deprecation in this area. I was just looking at the ri doc for 1.9.1 (I'm at work, and what I'm working on right now is on 1.8.6) and the ri doc has changed; they take out the specific bit about one parameter going to a two-element Array.
In what you've posted above, though, the *3* parameter (z) is just ignored. z would be set to nil, because .each doesn't set the value.
Thanks. I won't pester you any more about this, I'll just wait for the appropriate lecture. My 1.9.1. version of ri does indeed say something different from the above:
--------------------------------------------------------------
Hash#each
hsh.each {| key, value | block } -> hsh
hsh.each_pair {| key, value | block } -> hsh
From Ruby 1.9.1
------------------------------------------------------------------------
Calls _block_ once for each key in _hsh_, passing the key-value
pair as parameters.
h = { "a" => 100, "b" => 200 }
h.each {|key, value| puts "#{key} is #{value}" }
@Ron Newman
just read chapter 4 from the Pickaxe, this will shed some light.
a little note: if you want to define additional params, but want the x in your example to stay the same, define the additional vars local like this:
h.each {|x; local| p x}
because local was defined as a local var to the block (using the ";" ), it won't be assigned to behind the scenes (as John explained above).
@john
Thanks, I actually didn't get that this also counts for local block vars.
But reviewing my solutions I saw that I only did so in my student_one_liner. Is it allowed there? (I could rewrite it without the local block vars, but readability would suffer quite a bit, since its for array indexing and having a complex expression in the index doesn't seem so nice)
Don't create new local vars in your student one liner. If you like, create a student_one_liner_a and a student_one_liner_b and give both versions (with and without the local), and add comments that explains the readability (or lack of readability) for each version. Then it would be a learning experience.
You mention that new variables aren't allowed. Are semi-colons(;)? This seems to me that it would be the sane as saying, line 2 or at least in some instances.
In the instructions we say: "Your implementation must be one line of Ruby code. What is meant by “a single line”? You must supply one statement. You may not use the statement separator (the semi-colon) to separate statements inside the method block. There is an exception to the “single line” rule: You may include one extra statement inside of an iterator block by using the semi-colon. (This proves to be especially important for inject, but is also sometimes useful for collect as well.)" (http://e168f09.plugh.org/assignments/assignment-1-one-liners/)
@john
Indeed. I actually didn't think to go back and look at the rules again. Some of the methods I used to complete would run more efficiently with a semi-colon, but I think when I finished up, I didn't have any.
The start of your range is greater than the end: You can't iterate on such a range. I didn't discuss this in passing, but it was implied in the discussion of ranges such as ("2".."10").
Is there anyone using slickedit for ruby development? If so, did you manage to generate the tag files for the rails source? I tried to parse the directory and it created the tag file, but code completion still doesn't work.
They suggest a way to make class variables (implemented using class scope instance variables) inheritable using a module (in the end of the post). I think I get what's going on. But is there really no easier way to do this?
Remember that in Ruby, instance variables (and class instance variables) aren't public, not even to subclasses, and can't be shadowed / inherited. Access is always via a method. So there is a whole category of problem that Java developers face that goes away with Ruby (http://articles.techrepublic.com.com/5100-10878_11-5031837.html ).
My recommendation is to use the cattr_accessor and class_inheritable_accessor from the activesupport gem. These are not especially well-documented, but Dr. Nic provides some of the background:
OK, but if I declare an instance variable in my class, how do I avoid accidentally clobbering an instance variable with the same name in a (direct or indirect) superclass?
The "Ruby" answer is: Don't subclass unless you know how the superclass operates. This is frequently advised in the Java world, but for larger class hierarchies, it is essential for Ruby.
Here's a bit from the Flanagan/Matz Ruby Programming Language book:
"Because instance variables have nothing to do with inheritance, it follows that an instance variable used by a subclass cannot “shadow” an instance variable in the superclass. If a subclass uses an instance variable with the same name as a variable used by one of its ancestors, it will overwrite the value of its ancestor’s variable. This can be done intentionally, to alter the behavior of the ancestor, or it can be done inadvertently. In the latter case, it is almost certain to cause bugs. As with the inheritance of private methods described earlier, this is another reason why it is only safe to extend Ruby classes when you are familiar with (and in control of) the implementation of the superclass."
One of the tricky bits about Ruby is that even here the language is a bit misleading. The authors write: "If a subclass uses an instance variable with the same name as a variable used by one of its ancestors, it will overwrite the value of its ancestor’s variable." But really they mean: Instance variables are associated with self. The class doesn't "own" the instance variable (so the misleading language are phrases such as "ancestor's variable").
So that means if I subclass String, I need to know the names of any instance variables used by the String internal implementation (so I don't overwrite them). Even though they are private, and some later implementation might change them..... Ouch
Well, in general, I can't know whether or not a class has instance variables, since they are private implementation details and not part of its public API.
@Ron Newman I'm wondering whether there are meta-programming tricks whereby one sets up and checks certain class invariants. For example, I might expect my cat to have precisely 3 instance variables. I set up something that counts the instance variables and meows appropriately when the number exceeds 3. Then, when I misspell @kibble as @kible, the count goes up to 4 and I hear a warning meow.
class_inheritable_accessor is exactely the kind of easier I was looking for :) thanks!
the first link you posted (techrepublic) seems not to be working.
irb has an auto-completion mode that isn't enabled by default. It's quite useful and is described in chapter 18 of the Pickaxe. Once you enable it, you can hit the TAB key and irb will suggest how to finish the keyword or method name you've partially typed.
To enable it, create a file called ".irbrc" in your home directory, or edit such a file if you already have it. Put this line at the end of the file:
in your .irbrc file, it wlll remember your commands from one session to the next, so you can use the 'up-arrow' to recall and repeat them. Change 50 to any number you prefer.
On the other hand, this command that is documented in chapter 18 doesn't work for me. Did I make some mistake when building my Ruby?
irb(main):002:0> help String
NameError: undefined method `execute' for module `IRB::ExtendCommand::Help'
from (eval):4:in `instance_method'
from (eval):4:in `irb_help'
from (irb):2
from /Users/ronnewman/.ruby_versions/ruby-1.9.1-p243/bin/irb:12:in `'
Since we are in no danger to get into the TextMate hype (just kidding, I believe it's a good tool) I would like to gather some infos on good ruby dev-env's under linux. Personally I prefer using emacs. Any other ruby emacs users out there? How did you set up your environment?
I came across this link which has some useful hints: http://codehunk.wordpress.com/2009/01/14/ruby-on-emacsjourney-from-textmate-to-emacs/
How can I turn my local rdoc into HTML, the way you did in Assignment 2? I'd love to have a local reference for the standard Ruby classes, instead of running off to ruby-doc.org .
Here is another MVC framework a former co-worker sent to me. This is in the vein of John's comments last night that there are other frameworks and even if you don't use Rails the Railsian concepts are useful and powerful. It is actually used with Erlang and borrows from Rails.
"Chicago Boss - the no-nonsense MVC framework for Erlang
"
Its motto is:
Rails Idioms + Django Templates + Erlang Power =
Chicago
BOSS
“Don’t you worry about that. You just let Boss worry about that.”
David
@john
Hey @john -- Can't you use the local web server capabilites to do that and just scrape the resultant HTML? If you say gem server and open up a browser to http://localhost:8808 it serves up copies of the local gems' rdocs, right? How does gem find those documents?
what is the easiest way to calculate 2^n with n being any integer?
I wrote it like this:
(0...n).inject(1) {|pow, val| pow *= 2}
But I am sure there is an easier way...
2**n
I find this block behavior befuddling, and would like to understand what is going on. Can you direct me to the appropriate part of Pickaxe where the behavior of Hash#each is clearly explained?
irb(main):001:0> h = {'one' => 1, 'two' => 2, 'three' => 3}
=> {"one"=>1, "two"=>2, "three"=>3}
irb(main):006:0> h.each {|x| p x}
["one", 1]
["two", 2]
["three", 3]
=> {"one"=>1, "two"=>2, "three"=>3}
irb(main):008:0> h.each {|x, y, z| p x}
"one"
"two"
"three"
=> {"one"=>1, "two"=>2, "three"=>3}
How is it that declaring an additional block parameter 'y' changes the value of 'x' in the block? And where is it documented that Hash#each can yield a two-element array for each element?
Others may want to comment, but your questions are answered in the ri doc.
(Try taking the "z" parameter out of the 2nd code snippet, and print the value for both x AND y.)
hsh.each {| key, value | block } -> hsh
------------------------------------------------------------------------
Calls _block_ once for each key in _hsh_, passing the key and value
to the block as a two-element array. Because of the assignment
semantics of block parameters, these elements will be split out if
the block has two formal parameters. Also see +Hash.each_pair+,
which will be marginally more efficient for blocks with two
parameters.
h = { "a" => 100, "b" => 200 }
h.each {|key, value| puts "#{key} is #{value}" }
_produces:_
a is 100
b is 200
I'm asking the above because I'm trying to understand what it means for Hash to be an Enumerable (and therefore to have collect and inject methods). Playing around with this just leads me further into confusion:
irb(main):027:0> h.collect {|elt | p elt}
["one", 1]
["two", 2]
["three", 3]
=> [["one", 1], ["two", 2], ["three", 3]]
irb(main):028:0> h.collect {|elt,x | p elt}
"one"
"two"
"three"
=> ["one", "two", "three"]
... how did adding that second parameter 'x' change the value of 'elt' and the result of the collect?
We crossed while posting our latest comments. Looks like 'ri' says something that Pickaxe doesn't, because Pickaxe (page 537 of the PDF version) makes no mention of Hash#each with one block parameter, only with two. I guess you'll explain "the assignment
semantics of block parameters, these elements will be split out if
the block has two formal parameters" in a later lecture....
@Ron Newman
Don't sweat this too much.
With one parameter { |x| . . . }
x will be a two-element Array. The 0'th element will be the key, the 1'th element will be the value.
With two parameters { |x, y| . . . }
x is the key, y the value.
What is going on behind the scenes is that you can do assignments like this in Ruby (try typing the following sequence into irb):
x = [ 1, 2 ]
x, y = [ 1, 2 ]
x
y
Now, about the documentation. I think there has been some deprecation in this area. I was just looking at the ri doc for 1.9.1 (I'm at work, and what I'm working on right now is on 1.8.6) and the ri doc has changed; they take out the specific bit about one parameter going to a two-element Array.
In what you've posted above, though, the *3* parameter (z) is just ignored. z would be set to nil, because .each doesn't set the value.
Thanks. I won't pester you any more about this, I'll just wait for the appropriate lecture. My 1.9.1. version of ri does indeed say something different from the above:
--------------------------------------------------------------
Hash#each
hsh.each {| key, value | block } -> hsh
hsh.each_pair {| key, value | block } -> hsh
From Ruby 1.9.1
------------------------------------------------------------------------
Calls _block_ once for each key in _hsh_, passing the key-value
pair as parameters.
h = { "a" => 100, "b" => 200 }
h.each {|key, value| puts "#{key} is #{value}" }
_produces:_
a is 100
b is 200
@Ron Newman
just read chapter 4 from the Pickaxe, this will shed some light.
a little note: if you want to define additional params, but want the x in your example to stay the same, define the additional vars local like this:
h.each {|x; local| p x}
because local was defined as a local var to the block (using the ";" ), it won't be assigned to behind the scenes (as John explained above).
@Gabriel Hase
But remember: In the one-liners assignment, you may not define additional variables, unless explicitly allowed.
@john
Thanks, I actually didn't get that this also counts for local block vars.
But reviewing my solutions I saw that I only did so in my student_one_liner. Is it allowed there? (I could rewrite it without the local block vars, but readability would suffer quite a bit, since its for array indexing and having a complex expression in the index doesn't seem so nice)
@Gabriel Hase
Don't create new local vars in your student one liner. If you like, create a student_one_liner_a and a student_one_liner_b and give both versions (with and without the local), and add comments that explains the readability (or lack of readability) for each version. Then it would be a learning experience.
@john
You mention that new variables aren't allowed. Are semi-colons(;)? This seems to me that it would be the sane as saying, line 2 or at least in some instances.
@Jeff Ancel
In the instructions we say: "Your implementation must be one line of Ruby code. What is meant by “a single line”? You must supply one statement. You may not use the statement separator (the semi-colon) to separate statements inside the method block. There is an exception to the “single line” rule: You may include one extra statement inside of an iterator block by using the semi-colon. (This proves to be especially important for inject, but is also sometimes useful for collect as well.)" (http://e168f09.plugh.org/assignments/assignment-1-one-liners/)
So -- I think I spelled it out pretty clearly.
@john
Indeed. I actually didn't think to go back and look at the rules again. Some of the methods I used to complete would run more efficiently with a semi-colon, but I think when I finished up, I didn't have any.
I could probably get rid of the semicolons entirely with judicious use of Object#tap , but I doubt that I will bother to.
Some weird behavior with proc and lambda:
def my_meth1
@Gabriel
All I see is "def my_meth1"
You really shouldn't need lambda for the one-liners . . .
Sorry, pressed submit too early...
Some weird behavior with proc and lambda (Pickaxe page 354):
def my_meth1
a=1
Proc.new {return a}
end
my_proc1 = my_meth1
my_proc1.call
=> fails with unexpected return
BUT
my_meth2
a=1
lambda {return a}
end
my_proc2 = my_meth2
my_proc2.call
=> returns 1
So: is it the case that only lambda generates a closure? Can't explain the behavior otherwise...
This is getting way ahead of where we are in the course, but here's what's going on:
When you do a return from inside of a proc, it returns FROM THE METHOD THAT IS USING THE PROC.
When you do a return from inside a lambda, it returns FROM THE LAMBDA.
So, when you write:
my_proc1 = my_meth1
The last line of my_meth1 returns a reference to the Proc you created.
Then you write
my_proc1.call
BUT: Are you calling from inside a method? No. You're calling from the top-level binding -- there is no block.
A lambda is like a function: return means: "return from lambda."
But a Proc depends on the context in which it is used.
If you're used to lambdas in other languages, you probably want to use a Ruby lambda, not a Ruby Proc.new
See examples 9 and following here:
http://innig.net/software/ruby/closures-in-ruby.rb
In lecture 2, there was an example of a range on the slides like this:
(10..1)
I tried the following:
(10..1).each {|a| puts a}
but the output was merely (10..1). So it seems that counting down a range doesn't work. Or am I missing something?
That won't work, but this will:
10.downto(1).each {|a| puts a}
Does seem a bit inconsistent.
@Gabriel
The start of your range is greater than the end: You can't iterate on such a range. I didn't discuss this in passing, but it was implied in the discussion of ranges such as ("2".."10").
Is there anyone using slickedit for ruby development? If so, did you manage to generate the tag files for the rails source? I tried to parse the directory and it created the tag file, but code completion still doesn't work.
If you are a Facebook user and go to http://apps.facebook.com/hcourselink , you can connect there with other students taking this class.
I just read about class variables (and their smarter implementations as class scope instance variables using class << self; attr_accessor :some_var end) here:
http://railstips.org/2006/11/18/class-and-instance-variables-in-ruby
They suggest a way to make class variables (implemented using class scope instance variables) inheritable using a module (in the end of the post). I think I get what's going on. But is there really no easier way to do this?
@Gabriel Hase
Remember that in Ruby, instance variables (and class instance variables) aren't public, not even to subclasses, and can't be shadowed / inherited. Access is always via a method. So there is a whole category of problem that Java developers face that goes away with Ruby (http://articles.techrepublic.com.com/5100-10878_11-5031837.html ).
My recommendation is to use the cattr_accessor and class_inheritable_accessor from the activesupport gem. These are not especially well-documented, but Dr. Nic provides some of the background:
http://drnicwilliams.com/2006/08/27/so-cattr_accessor-doesnt-work-like-it-should/
Looks to me like instance variables are shared between an instance and its superclass:
class Animal
attr_accessor :name
def initialize
@name = "animal"
end
end
class Cat < Animal
def initialize
@name = "cat"
end
end
c = Cat.new
p c.name # prints "cat"
(why did all of my indentation go away when I posted that?)
@Ron Newman
Not exactly.
You're going through the accessor method on the superclass, which is then providing access to @name on self.
@Ron Newman
Ron - This is the example you want to think about (comment out @name = "cat" in Cat):
class Animal
attr_accessor :name
def initialize
@name = "animal"
end
end
class Cat < Animal
def initialize
# @name = "cat"
end
end
c = Cat.new
p c.name
OK?
OK, but if I declare an instance variable in my class, how do I avoid accidentally clobbering an instance variable with the same name in a (direct or indirect) superclass?
@Ron Newman
The "Ruby" answer is: Don't subclass unless you know how the superclass operates. This is frequently advised in the Java world, but for larger class hierarchies, it is essential for Ruby.
Here's a bit from the Flanagan/Matz Ruby Programming Language book:
"Because instance variables have nothing to do with inheritance, it follows that an instance variable used by a subclass cannot “shadow” an instance variable in the superclass. If a subclass uses an instance variable with the same name as a variable used by one of its ancestors, it will overwrite the value of its ancestor’s variable. This can be done intentionally, to alter the behavior of the ancestor, or it can be done inadvertently. In the latter case, it is almost certain to cause bugs. As with the inheritance of private methods described earlier, this is another reason why it is only safe to extend Ruby classes when you are familiar with (and in control of) the implementation of the superclass."
One of the tricky bits about Ruby is that even here the language is a bit misleading. The authors write: "If a subclass uses an instance variable with the same name as a variable used by one of its ancestors, it will overwrite the value of its ancestor’s variable." But really they mean: Instance variables are associated with self. The class doesn't "own" the instance variable (so the misleading language are phrases such as "ancestor's variable").
So that means if I subclass String, I need to know the names of any instance variables used by the String internal implementation (so I don't overwrite them). Even though they are private, and some later implementation might change them..... Ouch
@Ron Newman
You're making the assumption that String has instance variables . . .
Well, in general, I can't know whether or not a class has instance variables, since they are private implementation details and not part of its public API.
@Ron Newman
Not really.
Privacy in Ruby is about methods.
But instance variables are about the state of self.
As you can see, the whole philosophy pretty much assumes you have access to source code.
There have been proposals to introduce "class local" variables that would be prefixed with @_
@Ron Newman I'm wondering whether there are meta-programming tricks whereby one sets up and checks certain class invariants. For example, I might expect my cat to have precisely 3 instance variables. I set up something that counts the instance variables and meows appropriately when the number exceeds 3. Then, when I misspell @kibble as @kible, the count goes up to 4 and I hear a warning meow.
@Ken Busch
Ken - You can do that all that. Not sure about the sound generation, though.
@john
class_inheritable_accessor is exactely the kind of easier I was looking for :) thanks!
the first link you posted (techrepublic) seems not to be working.
@Gabriel Hase
Try the link again.
@john
now it's working.
irb has an auto-completion mode that isn't enabled by default. It's quite useful and is described in chapter 18 of the Pickaxe. Once you enable it, you can hit the TAB key and irb will suggest how to finish the keyword or method name you've partially typed.
To enable it, create a file called ".irbrc" in your home directory, or edit such a file if you already have it. Put this line at the end of the file:
require 'irb/completion'
Also (and again from chapter 18), if you put this
IRB.conf[:SAVE_HISTORY] = 50
in your .irbrc file, it wlll remember your commands from one session to the next, so you can use the 'up-arrow' to recall and repeat them. Change 50 to any number you prefer.
On the other hand, this command that is documented in chapter 18 doesn't work for me. Did I make some mistake when building my Ruby?
irb(main):002:0> help String
NameError: undefined method `execute' for module `IRB::ExtendCommand::Help'
from (eval):4:in `instance_method'
from (eval):4:in `irb_help'
from (irb):2
from /Users/ronnewman/.ruby_versions/ruby-1.9.1-p243/bin/irb:12:in `'
@Ron Newman
irb help is broken the same way on my 1.9.1 on the Mac/SnowLeopard.
You can put this in your .irbrc to use ri from within irb:
def ri(*names)
system(%{ri #{names.map {|name| name.to_s}.join(" ")}})
end
Note: You must surround the lookup text with double-quotes if there is a pound sign --
so
ri "String#each_line"
To all linux users:
Since we are in no danger to get into the TextMate hype (just kidding, I believe it's a good tool) I would like to gather some infos on good ruby dev-env's under linux. Personally I prefer using emacs. Any other ruby emacs users out there? How did you set up your environment?
I came across this link which has some useful hints:
http://codehunk.wordpress.com/2009/01/14/ruby-on-emacsjourney-from-textmate-to-emacs/
How can I turn my local rdoc into HTML, the way you did in Assignment 2? I'd love to have a local reference for the standard Ruby classes, instead of running off to ruby-doc.org .
@Ron Newman
rdoc: Good idea -- http://e168f09.plugh.org/notes/note-johns-todos/
Here is another MVC framework a former co-worker sent to me. This is in the vein of John's comments last night that there are other frameworks and even if you don't use Rails the Railsian concepts are useful and powerful. It is actually used with Erlang and borrows from Rails.
"Chicago Boss - the no-nonsense MVC framework for Erlang
"
Its motto is:
Rails Idioms + Django Templates + Erlang Power =
Chicago
BOSS
“Don’t you worry about that. You just let Boss worry about that.”
David
@john
Hey @john -- Can't you use the local web server capabilites to do that and just scrape the resultant HTML? If you say gem server and open up a browser to http://localhost:8808 it serves up copies of the local gems' rdocs, right? How does gem find those documents?
David