I am confused with the scope of a variable inside a block. This works:
f = 'new'
[1,2,3].each do |n| puts f * n end
#=> new newnew newnewnew
But this doesn't:
[1,2,3].each do |n|
a ||=[]
a << n
end
a
#=>a does not exsit!
Why is this? And please put some resource on this topic for me.
What's confusing?
In the first snippet f is created and then the each block is executed, which can see things outside itself (called enclosing scope). So it can see f.
In the second snippet you create a inside the block, and so its scope is that block. Outside the block, a doesn't exist.
When you refer to a name (a, for instance) ruby will go from the current scope outwards, looking in all enclosing scopes for the name. If it finds it in one of the enclosing scopes, it uses the value that name is associated with. If not, it goes back to the most local scope and creates the name there. Subsequent name lookups will yield the value tied to that name.
When a block ends, the names that were in that scope are lost (the values aren't lost, just the names; values are lost when the garbage collector sees that no more names (or anything) refer to that value, and the gc collects the value to reuse its memory).
If visualization is your thing, I find it helpful to think of scopes as a staircase, and at the beginning of a program, you are standing on the top step1. Every time a block is entered, you step down one step. You can see everything on the current step, and everything on steps above the one you're on, but nothing on the steps below. When you refer to a variable name, you look around on the step you're on to find it. When you see it, you use that value. If you don't see it, you look to the next step above the one you're on. If you see it, you use that value. You do this over and over till you've looked at the very top step but don't see that name. If this happens, you create the name on the step you are standing on (and give it a value, if you're looking it up for an assignment). The next time you look for that name, you'll see it on the step you're standing on, and use it there.
When a block ends, you step up one stair step. Because you can't see any names on the steps below, all the names on the step you were previously on are lost.
If that helps you, think of it that way. If not, don't.
1 Actually you're on the second step because you're not in global scope, but to use names from global scope, you have to use a $ at the beginning of the name. So in the staircase example, if the name you are looking for has an $ at the beginning, you look directly at the top step. If not, you don't look that far. However, this is kind of wrong, since all the stairs in the program would share the same top step, which is weird to think about.
map works much better:
a = [1,2,3].map do |n|
n
end
No need to declare a outside of the block.
It's simple, a variable defined inside a block is not visible outside (if this happened, we'd say the variable had leaked, and as the word suggests, this would be bad):
>> lambda { x = 1 }.call
=> 1
>> x
NameError: undefined local variable or method `x' for main:Object
Related
I'm a newbie to Ruby, and so far have found the explanations for ! a bit too technical.
Let's say we have the following:
print "What is your first name?"
first_name = gets.chomp.upcase!
puts "Hi, #{first_name}. How are you?"
What does the ! add to the method? Does it mean that every time I use #{first_name} in any subsequent strings, all the letters in the name will print in upper-case? How is the code affected if I leave ! out?
Please explain it in layman's terms if you can, as I'm still coming to grips with some of Ruby's technical jargon.
Thanks in advance.
Ruby method names may end in !. It doesn't do anything special by itself, but there is a convention on which methods have it (though it is not always consistent); thus, just learn the method String#upcase! (and how it differs from String#upcase) on individual method-by-method basis, with the convention being a helpful reminder.
The convention is that the methods ending in ! are either dangerous, or change the object, or perform some other kind of change, or can raise an error where the other version wouldn't.
Specifically, String#upcase! changes the string it operates on. String#upcase makes a new string that is upcased.
foo = "test"
p(foo.upcase) # => "TEST"
p(foo) # => "test"
foo = "test"
p(foo.upcase!) # => "TEST"
p(foo) # => "TEST"
As described in comments, String#upcase! returns nil when no upcasing needs to happen, so you never want to reassign the return value of String#upcase! back to the same variable you tried to upcase!.
foo = "TEST"
p(foo.upcase!) # => nil
p(foo) # => "TEST"
RE: bang methods: see here
EDIT: "receiver" is the object receiving the message (i.e. method call). In foo.upcase!, the object in foo is the receiver. In "TEST".upcase, the string "TEST" is the receiver.
"in-place"` means the object itself is changed. The alternative is to create a new object that has the changes you want applied, with no change to the original object. For example, if you have a photo, cover the bottom half with a piece of paper and take a photo of that, you did a crude censorship by creating a new photo that is missing the lower half (but the original still exists). If you splat paint on the original photo, you censored it "in place".
What does the ! add to the method?
Nothing. The ! is simply part of the message name, just like the u, the p, the c, the a, the s, and the e are. It does not change anything about the message.
How is the code affected if I leave ! out?
Then you are simply sending a different message.
There is absolutely no difference whatsoever between upcase and upcase! or between foo and bar. They are just message names. If you write foo, then you send message foo, if you write bar, then you send message bar, if you write upcase, then you send message upcase (which in your case will be dispatched to the method String#upcase), if you write upcase!, then you send message upcase! (which in your case will be dispatched to the method String#upcase!).
There is absolutely nothing special about message names ending in !, just like there is absolutely nothing special about message names ending in ?, just like there is absolutely nothing special about message names ending in a or b or c.
There are, however, some conventions. In particular, the convention is:
If you have a pair of methods that both do more or less the same thing, then the one that is more surprising is named with a !.
That's it. That is all there is to it.
For example, there are the methods Process::exit and Process::exit!. They both do the same thing (terminate the process), but one of them skips running the installed exit handlers.
Since they both do the same thing, they could both be named "exit", but of course, you can't have two methods with the same name (on the same receiver). Therefore, we need to somehow distinguish between the two. We could come up with a completely different name for one of the two, but that would also be annoying.
So, instead, we add a ! to one of the two methods. Now, the question is: which one of the two do we add the ! to? Based on our convention, the "more surprising" one should get the !. The Ruby developers chose the one which ignores the exit handlers, which I think is the right choice: the whole point of exit handlers is that they get run when you exit, so a method that exits without running the exit handlers is surprising, and therefore should be marked with a !.
Note that none of this has anything to do with "destructive" or "mutation". Process::exit! doesn't mutate anything and it doesn't destroy anything. Note also that we only use the ! to mark the more surprising method of a pair of methods. There should never be a method named foo! when there is not also a method named foo.
In particular, the fact that a method does not have a ! does not tell you anything about the method. And the only thing that a method that does have a ! tells you is that there are two methods, and you should probably check the documentation to make sure that you understand what these two methods do and what the "surprise" is that the ! is warning you about. That's it.
I have the following code:
# Assuming each element in foo is an array.
foo.each do |bar|
zaz = bar.first
# Other code using zaz, but not modifying it.
end
Will zaz local variable be modified on each iteration inside this loop, making it mutable? I am not sure about the behavior of Ruby here.
It depends on the code before the loop, really.
If that is all the code, then zaz is a block-local variable, and a new zaz variable will be created every time the loop body is evaluated.
If, however, there is a zaz local variable in the surrounding scope, then zaz is a free variable in the block, and since block scopes nest in their surrounding scope, the existing zaz variable outside the block will be re-assigned over and over again, every time the block is evaluated.
You can ensure that zaz is always treated as a block-local variable and never looked up in the surrounding scope, by explicitly declaring it as a block-local variable in the block's parameter list:
foo.each do |bar; zaz|
zaz = bar.first
end
Note, however, that your code only makes sense IFF your code is impure and mutable:
You assign to zaz but never actually use it inside the block. So, the only way that this makes sense at all is if zaz is a local variable in the outer scope and you are assigning it. Although in that case, your entire loop is just equivalent to zaz = foo.last.first.
each evaluates the block only for its side-effects. Without side-effects, each makes no sense at all, so the fact that you are using each implies that you have side-effects.
Note that the term "immutable" without additional qualification usually refers to values. When talking about "immutable variables", we usually say "immutable variable" explicitly, to make clear that we are only talking about whether or not a variable can be re-bound, not about mutating object state. Or, one could just say "constant", which is the technical term for "immutable variable" … although that term already has a specific meaning in Ruby.
each loops often mutate the object. Each has to do something.
Because each doesn't return anything useful - it returns the array itself, It won't mutate the object if it sends every element somewhere, like to be printed on screen.
foo.each do |bar|
# do something with element like
# print it, change it, save it
end
Functional alterantive is map
foo.map { |bar| bar.something }
It returns new array which is original array processed in immutable way. Obviously you have to be careful to use immutable methods. This would not be immutable:
foo.map { |bar| bar.something! }
Here something! does something destructive to the element of array.
However I have never seen map used like that. Use each for something destructive.
In the books I'm reading, I always see
def initialize (side_length)
#side_length = side_length
end
If the object variable always equals the variable with the same name why not write the language to just equal it without having to type it out?
For example:
def initialize (side_length)
#side_length # this could just equal side_length without stating it
end
That way we don't have to type it over with over.
In the example given:
def initialize(side_length)
#side_length = side_length
end
The #side_length = side_length is just an assignment, passing the available argument to an instance variable, in this case it happens to be the same name as the argument.
However those two values don't have to have same names - it's usually named that way for readability/convention reasons. That same code could just as easily be:
def initialize(side_length)
#muffin = side_length
end
The above code is perfectly fine, it just wouldn't read as well (and might slightly confuse someone giving it a first glance). Here's another example of the argument not being assigned to an instance variable of the same name.
It would be possible to write the language in a way which assumes that the argument variable should automatically be assigned to an instance variable of the same name, but that would mean more logic for handling arguments, and that same assumption may result in more restrictions for the developer, for example, someone who may actually want to assign side_length to #muffin for whatever reason.
Here's a SO question similar to this one - the accepted answer provides an interesting solution.
Hope this helps!
It is because "the object variable [does not] always [equal] the variable withthe [sic] same name".
Why doesn't this code work?
b if b = true
Error: undefined local variable or method `b'
But this does:
if b = true
b
end
Shouldn't they be the same?
This is a very good question. It has to do with the scoping of variables in Ruby.
Here is a post by Matz on the Ruby bug tracker about this:
local variable scope determined up to down, left to right. So a local variable first assigned in the condition of if modifier is not effective in the left side if body. It's a spec.
In the first version as soon as k is hit, the parser pukes because it hasn't been seen yet.
In the second version, k is part of an assignment expression, and is parsed differently.
I don't know the reason but the problem that the interpreter tries to lookup the variable k before evaluating the condition.
If you write it like this, there won't be any error and works as you expected:
k = nil
h = {k: 1}
v = k if k = h.delete(:k)
you have put only one '='
Try with '=='
Then you will get error
In second example, you are assigning 'true' to b.
Because the Ruby interpreter creates a local variable when it sees an assignment
In the second case, it hasn't yet seen the assignment, so the variable doesn't exist when the expression is parsed.
To be more precise, a method is first parsed into an internal representation, and then, perhaps, the code will eventually be called and actually executed.
Local variables are created in that parsing pass. It's a matter of declaration, it just means that the interpreter becomes aware of them. They won't be created in the sense of being given space or a value until the surrounding method is called by someone.
I have the following code in one of my personal projects:
def allocate(var, value) # Allocate the variable to the next available spot.
#storage.each do |mem_loc|
if mem_loc.free?
mem_loc.set(var, value) # Set it then break out of the loop.
break
end
end
end
Each item in the storage array is an object that responds to free? and set. What I am trying to do is cycle through the array, looking for the next free (empty) object to set the variable to. My problem is, this just cycles through every object and sets them all. Am I using the break function incorrectly?
Testing it, I call the following:
store.allocate(:a, 10)
store.allocate(:b, 20)
So store[1] should be set to :b and 20. But when I output the contents, it's value is 10, as is the rest of the array.
I believe I have found the mistake, and it wasn't actually in the code above.
When I set up the storage array, I did like so:
#storage = [Memory_location.new] * 1000
Believing it would create 1000 different objects. What I think actually happened, was that it created 1000 references to the same object, so when I changed one of them, I changed all of them. I could prove this by using the puts method on two different array locations, with both of them returning:
#{Memory_location:0x2bc8b74}