If I assign a value to the variable pp and then call pp pp in the console why doesn't pretty print loop?
$ irb
pp = "hello world"
=> "hello world"
pp pp
"hello world"
=> "hello world"
According to this explanation I think it should
https://blog.brycekerley.net/2014/08/27/Working-with-pp-the-Ruby-Pretty-Printer.html
Edit: I didn't mean that it must loop, I just wanted to know the method call order that happened that prevented it from looping.
Ruby is an interpreted language, meaning that, instead of compiling, it executes the code as written, interpreting the code line by line, word by word (or rather token by token).
When ruby interpreter encounters a line pp pp, it needs to resolve two tokens. First one is clearly a method as it takes an argument, the other one can be either a method OR local variable (there are no brackets nor arguments).
So, during execution, ruby will start resolution from the second token. When it is not clear whether token denotes variable or method, ruby always searches for variable first. In this case, the variable is there as you assigned a value to pp creating a local variable (let's say by pp = 1).
Then ruby has still to process the second token, but now it looks like pp(1) (because first token has been resolved already). In this case this is, again, clearly a method so ruby just send a pp message to self (which in this context is (main) object). Method pp is defined on Kernel, so each object - including (main) can access it.
The key point here is to understand that you have not overridden method pp - that method is still there. The only thing that happened is different resolution of pp token. Even with pp hidden (or shadowed) by local variable, you can still invoke it either by using explicit self.pp or by making sure that it looks like a method pp()
I'm going far on a limb here (for fun mostly) and guessing you do something like this
>> pp "this is a test"
"this is a test"
=> "this is a test"
>> pp = pp
=> nil
>> pp pp
nil
=> nil
>> pp "this is another test"
"this is another test"
=> "this is another test"
So here's what happens
pp = pp
You've created a local variable pp which got assigned a value of whatever pp method returned (nil in this case)
>> pp pp
here you call pp method and passing it pp variable, which holds nil
>> pp "this is another test"
"this is another test"
=> "this is another test"
you still can call pp method as usually.
Not sure why would you expect it to loop. Expressions are evaluated (right to left in general), so they will evaluate eventually. No infinite loops should generally happen. Take this example:
x = y = z = x
It will first evaluate right-most x (which has not been defined, so defaults to nil, so next step conceptually will be:
x = y = z = nil
assigns nil to z, and result of this evaluation is also nil
x = y = nil
assigns nil to y
and so on...
Related
This question already has answers here:
Why can I refer to a variable outside of an if/unless/case statement that never ran?
(3 answers)
Closed 5 years ago.
We define a function foo:
def foo(s)
case s
when'foo'
x = 3
puts x.inspect
when 'bar'
y = 4
puts y.inspect
end
puts x.inspect
puts y.inspect
end
We then call it as follows:
1.9.3p194 :017 > foo('foo')
in foo scope
3
in outer scope
3
nil
=> nil
1.9.3p194 :018 > foo('bar')
in bar scope
3
in outer scope
nil
3
=> nil
Why does the function not throw an error about an unregistered local variable in either case? In the first case, the variable y seems like it should not exist, so you can't call inspect on it in the outer scope; the same for x in the second case.
Here's another similar example:
def test1
x = 5 if false
puts x.inspect
end
def test2
puts x.inspect
end
And then:
1.9.3p194 :028 > test1
nil
=> nil
1.9.3p194 :029 > test2
NameError: undefined local variable or method `x' for main:Object
What's going on here? It seems like Ruby is hoisting the variable declaration into the outer scope, but I wasn't aware that this is something Ruby does. (Searching for "ruby hoisting" only turns up results about JavaScript hoisting.)
When the Ruby parser sees the sequence identifier, equal-sign, value,
as in this expression
x = 1
it allocates space for a local variable called x. The creation of the
variable—not the assignment of a value to it, but the internal
creation of a variable—always takes place as a result of this kind of
expression, even if the code isn’t executed! Consider this example:
if false
x = 1
end
p x # Output: nil
p y # Fatal Error: y is unknown
The assignment to x isn’t executed, because it’s wrapped in a failing
conditional test. But the Ruby parser sees the sequence x = 1, from
which it deduces that the program involves a local variable x. The
parser doesn’t care whether x is ever assigned a value. Its job is
just to scour the code for local variables for which space needs to
be allocated. The result is that x inhabits a strange kind of variable limbo.
It has been brought into being and initialized to nil.
In that respect, it differs from a variable that has no existence at
all; as you can see in the example, examining x gives you the value
nil, whereas trying to inspect the non-existent variable y results
in a fatal error. But although x exists, it has not played any role in
the program. It exists only as an artifact of the parsing process.
Well-Grounded Rubyist chapter 6.1.2
The ruby parser goes through every lines and set to nil all variable =. The code being actually executed or not does not matter.
See Why can I refer to a variable outside of an if/unless/case statement that never ran?
def foo(_, _='override')
_
end
p foo("bye bye")
p foo("hello", "world")
Output:
"override"
"hello"
I could understand if the result was:
"override"
"world"
or even:
"bye bye"
"hello"
But the result I'm getting causes me confusion.
Default arguments are evaluated earlier in time than regular arguments if an argument is passed for it, otherwise they are evaluated last. Almost certain but unsure how to prove it.
Meaning in this example:
at time 0 call p foo("hello", "world")
at time 1 _ = 'override'
at time 2 _ = "world"
at time 3 _ = "hello"
at time 4 variables are printed and you see "hello"
EDIT here is some evidence:
def foo(_, _='override',_)
_
end
p foo("bye bye","goodbye")
p foo("hello", "world", "three")
prints
"override"
"three"
Ican't find better explanation than this one
ruby magic underscore
The reason for this is found in Ruby’s parser, in shadowing_lvar_gen. All the normal checks for duplication are skipped iff the variable name consists of exactly one underscore.
One possible explanation is that name _ stands for "unused variable". You're not supposed to even reference it, let alone expect any values of it. As it is a special name, it gets special treatment from the parser (such as suppressing "duplicate parameter" errors). I imagine that no one cared to make this code produce a logical result, because, again, these are unused variables.
If you rename it to anything else (say, a), you'll get an error, because now this method signature doesn't make sense.
When I run the following code:
class GermanShepard
attr_accessor :name
def bark
puts "Loud Bark"
end
end
max = GermanShepard.new
max.name = "Max"
puts "#{max.name} goes #{max.bark}"
the result is:
Loud Bark
Max goes
When I change puts to return at the GermanShepard. It gives:
Max goes Loud Bark
I don't understand the difference between the two command in the class.
Expression
In most languages, return in a method means giving a value to the caller.
In Ruby, everything is an expression. In an essence, the last line of a method is automatically called with return. As an example, the following methods are equivalent:
def bark_a
'Woof!'
end
def bark_b
return 'Woof!'
end
However, some methods may not be returning anything.
def bark_c
end
In this case, ruby is actually returning a nil object. An example would be the
puts method. The puts method simply displays whatever you've given it.
So in your example,
def bark
puts "Loud Bark"
end
is actually doing 2 things.
It's calling the puts method (displaying Loud Bark to the terminal screen)
then it's giving a nil value back to the method caller.
You can try running puts nil and see what's printed out!
"#{}"
Calling #{} in ruby is called interpolation, which is basically putting the variables together in their closest string representation value. The following statements are roughly equivalent:
puts "One plus one equals #{1 + 1}"
puts "One plus one equals " + (1 + 1).to_s
Your example
With all the information above, we can now go through your example step-by-step.
The line puts "#{max.name} goes #{max.bark}" can be separated into a few steps
Calls the name method
The value returned is converted into the closest string representation (In this case we don't need to do anything since name is already a string)
The value is then saved to a temporary variable
At this point, our temporary variable is Max goes.
Calls the bark method
The line puts "Loud Bark" gets executed since we're calling it in the bark method.
Terminal(console) displays "Loud Bark"
Since the puts method returns a nil value, the bark method is also going to return a nil value because it's the last line of the bark method. (Read "Expression" above)
nil is then converted to the closest string representation (which is "")
It is then saved to a temporary variable
The temporary variable is now Max goes
Now, the temporary variable is passed into the puts method, and the terminal(console) displays "Max goes "
Program finishes
Therefore, your example prints out
Loud Bark
Max goes
However, if we change the puts inside the bark method to return,
Step 6 will not happen.
Instead of returning a nil value in step 7, it will return "Load bark"
Step 8 will not happen since "Loud bark" already a string value
and the temporary value after step 9 will become Max goes Loud bark
Hope this helps!
Ray's answer is probably correct, but since it is too verbose (and I didn't even feel like reading it), I will post a concise answer.
There are two things to have in mind.
All arguments passed to a method are evaluated prior to the method call.
All methods in Ruby have a return value. In addition, some methods have side effect, an example of which is to output on the terminal. In any case, returning a value is done after a method has done all its side effects.
With your code as is, the argument of puts in
puts "#{max.name} goes #{max.bark}"
is first evaluated. In order to do so, max.bark (among other things like max.name) would have to be evaluated in advance. The method bark prints "Loud Bark", then returns nil. So the argument mentioned above becomes "#{"Max"} goes #{nil}", and eventually to "Max goes ". That is printed after "Loud Bark".
When you change the puts in the method to return, the method bark will have no side effect, and returns "Loud Bark"; that is the function of return (and by the way, return is not a method but is a keyword). So the argument mentioned above becomes "#{"Max"} goes #{"Loud Bark"}", and eventually to "Max goes Loud Bark". That would be the only thing printed.
puts(string) in ruby writes the string value into $stdout. For example if you run ruby console in terminal, string will be written into your terminal. At the same time every method in ruby returns something and method puts returns nil. So, when we want to interpolate string like "Hello #{some_method}" it will interpolate a returning value of some_method, in case of puts it will interpolate nil value.
Loud Bark # output of max.bark method
Max goes # output of last puts
puts "Loud Bark" # => returns nil
return "Loud Bark" # => returns "Loud Bark"
This question already has answers here:
Why can I refer to a variable outside of an if/unless/case statement that never ran?
(3 answers)
Closed 5 years ago.
We define a function foo:
def foo(s)
case s
when'foo'
x = 3
puts x.inspect
when 'bar'
y = 4
puts y.inspect
end
puts x.inspect
puts y.inspect
end
We then call it as follows:
1.9.3p194 :017 > foo('foo')
in foo scope
3
in outer scope
3
nil
=> nil
1.9.3p194 :018 > foo('bar')
in bar scope
3
in outer scope
nil
3
=> nil
Why does the function not throw an error about an unregistered local variable in either case? In the first case, the variable y seems like it should not exist, so you can't call inspect on it in the outer scope; the same for x in the second case.
Here's another similar example:
def test1
x = 5 if false
puts x.inspect
end
def test2
puts x.inspect
end
And then:
1.9.3p194 :028 > test1
nil
=> nil
1.9.3p194 :029 > test2
NameError: undefined local variable or method `x' for main:Object
What's going on here? It seems like Ruby is hoisting the variable declaration into the outer scope, but I wasn't aware that this is something Ruby does. (Searching for "ruby hoisting" only turns up results about JavaScript hoisting.)
When the Ruby parser sees the sequence identifier, equal-sign, value,
as in this expression
x = 1
it allocates space for a local variable called x. The creation of the
variable—not the assignment of a value to it, but the internal
creation of a variable—always takes place as a result of this kind of
expression, even if the code isn’t executed! Consider this example:
if false
x = 1
end
p x # Output: nil
p y # Fatal Error: y is unknown
The assignment to x isn’t executed, because it’s wrapped in a failing
conditional test. But the Ruby parser sees the sequence x = 1, from
which it deduces that the program involves a local variable x. The
parser doesn’t care whether x is ever assigned a value. Its job is
just to scour the code for local variables for which space needs to
be allocated. The result is that x inhabits a strange kind of variable limbo.
It has been brought into being and initialized to nil.
In that respect, it differs from a variable that has no existence at
all; as you can see in the example, examining x gives you the value
nil, whereas trying to inspect the non-existent variable y results
in a fatal error. But although x exists, it has not played any role in
the program. It exists only as an artifact of the parsing process.
Well-Grounded Rubyist chapter 6.1.2
The ruby parser goes through every lines and set to nil all variable =. The code being actually executed or not does not matter.
See Why can I refer to a variable outside of an if/unless/case statement that never ran?
At Surface,
Ruby appears to be quite similar to other object orieinted languages like Java,Php,C etc.
but, things get bit weird when we start to bump into blocks.
for example, this works
(0...8).max()
=> 7
but this doesn't
(0...8).map(puts "hello world")
hello world
ArgumentError: wrong number of arguments(1 for 0)
Apprantly, map method doesn't take arguments but takes blocks, so passing replacing () with {} fix the error.
(0...8).map{puts "hello world"}
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
=> [nil, nil, nil, nil, nil, nil, nil, nil]
And then, there are some methods should take both -- blocks & arguments
8.downto(1){puts "hello world"}
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
=> 8
The problem I have is the confusion on if I should be using () , {} or both on given method. On what basis it gets decided?
Is it fixed on per method basis & I just to have remember what the method takes(Blocks or params)?
Or is there any other logical reasoning on basis of which it gets decided, if the method takes blocks{} or params()?
Please help me understand
Parenthesis after method calls are actually optional.
(0...8).map{puts "hello world"} is equivalent to (0...8).map() {puts "hello world"}
So you don't really replace them.
The acceptance of blocks is entirely up to the method, they can be specified in the method declaration:
def method(param, &block)
block.call
end
which will allow the block to be accessed as a variable from within the method, and be invoked via block.call for example.
They can also be used implicitely via the use of the yield keyword:
def method(param)
yield
end
So you have to refer to the API documentations to be sure what is accepted or not.
It should be documented in the API of the method.
If there is a method that accepts an argument, the block usually is optional - in such a case it is used to "refine" the way the method works - e.g. Hash.new, that may accept an argument (the default hash value) and a block, which is used to do smart things during key-value initialization. But most of the methods that require a block, don't accept an argument, e.g. Array#select or Array#map.
You use parenthesise to pass arguments to a function. This is always a comma separated list of Objects. They may be the result of a function, but don't have to. The function they are a result of will always only be called exactly once.
Example:
x = Array.new
=> []
x.push(2)
=> [2]
x.push(7.modulo(4))
=> [2,3]
You use blocks to pass functional behaviour to a method. These functions are usually intended to be called with many different arguments or a certain amount of times. puts "hello world" is a function that prints something, but does only return nil. So you will almost never try to use that as an argument for a function (as you would be passing nil to that function), but usually pass that as a block to a function so that it can be called multiple times.
Most of the time you will want to have the block, that you pass to a function, use arguments, so that it actually does something different for every time it is called.
Example:
(0..8).each{ |number|
if number.odd?
puts "#{number} is odd"
end
}
=> 1 is odd
=> 3 is odd
=> 5 is odd
=> 7 is odd
=> => 0..8