Why does Kernel#p duplicate my text on standard output? - ruby

Look at this code :
def hello
p "Hey!"
end
p hello
the output will be:
"Hey!"
"Hey!"
=> "Hey!"
And so here is my conclusion: puts itself returns the text which is going to be sent in output in Ruby code, else it wouldn't print "Hey!" again. What is happening while printing the string? If puts doesn't send it to standard output directly, who is responsible for it and how?

All Methods Return a Value
In Ruby, almost everything returns a value, even if that value is nil. However, in your case the issue is that Kernel#p and Kernel#puts differ in the values they return.
def hello
# Print string literal, then return
# the printed object.
p "Hey!"
end
# Print the return value of main#hello.
p hello
As a result, the string gets printed once inside the method, and then the method's return value is passed to Kernel#p and printed again. This is by design.
Use Kernel#puts to Avoid Duplicated Output
def hello
# Print string; return nil.
puts "Hey!"
end
# Calls main#hello, but prints nil (blank line).
puts hello
This will result in the string literal being printed inside the method, and then a blank line printed since the return value from the method is nil.
Hey!
=> nil
The Right Way
If you want to avoid the blank line, avoid sending to standard output more than once. For example:
def hello
'Hey!'
end
p hello

If the p method returns the string it's given, then hello would return that as well, which means that the secondary p call would repeat it.
This is probably why puts returns nil by default.

Related

Why does `puts {}.class.name` return nothing in Ruby?

I've tried this with other classes and they return things. Just this one doesn't.
puts ''.class.name # String
puts 1.class.name # Integer
puts [].class.name # Array
puts {}.class.name
but {}.class.name just returns blank.
Because puts {} passes a block.
Any method can take a block.
puts {}.class.name is really (puts {}).class.name. puts {} ignores the block and prints a newline. It returns nil. class.name is called on nil so the return value is NilClass. But that doesn't get passed to puts so it's not printed.
We can see it in IRB.
> puts {}.class.name
=> "NilClass"
Use parens to clarify. puts({}.class.name).
It's because {} is interpreted as a block sent to puts.
class.name is executed when puts returns, and the value is discarded.

In Ruby Why is the If/Then logic written without the If/Then structure failing?

Why does the following code fail to produce expected output, for the first two test cases if I don't add the "then" section to the the 'If?' I set the default value of the second variable "False" and I was under the impression that in Ruby a method could take an unspecified number of parameters, and the lack of a parameter when the method is called will roll back to using the default values of that parameters within the method if set.
def alphabetize(arr,rev=false)
arr.sort!
if rev == true
arr.reverse!
end
end
numbers = [1,9,2,1,10]
Test cases:
print alphabetize(numbers,false)
=begin
input: numbers,false
output: nil
expected output: 1,1,2,9,10
=end
print alphabetize(numbers)
=begin
input: numbers
output: nil
expected output 1,1,2,9,10
=end
print alphabetize(numbers,true)
=begin
input: numbers,true
output: 10,9,2,1,1
expected output: 10,9,2,1,1
=end
This code produced the expected results:
def alphabetize(arr,rev=false)
if rev == true
arr.sort!.reverse!
else
arr.sort!
end
end
numbers = [1,9,2,1,10]
You are printing the return value of the alphabetize method, which is not necessarily the value of the array.
In your first code, you have an if without a corresponding else as the last statement. In Ruby, the return value of an if statement without an else is nil, when the if condition fails.
In your second code, you have an if with an else statement. So the return value of the method, when the ifcondition fails, will be what gets executed inside the else block. In this case, arr.sort!.
It's worth mentioning the alphabetize method modifies the numbers array being passed in (indicated by the ! in the sort! and reverse! methods). If you printed numbers, instead of return value of alphabhetize, you would have the expected output as well.
def alphabetize(arr,rev=false)
arr.sort!
if rev == true
arr.reverse!
end
arr
end
Return array at the end when if false it return nil. To make sure the it returns the array value at the end of method.
Tested on rubyfiddle.com
http://rubyfiddle.com/riddles/c36bc/1

What does it mean that the return value of `puts` is `nil`?

The output for this code:
x = puts 'hello'
puts x
was:
hello
hello
But I expected the output to be one hello. puts x didn't return the value I expected. I thought puts x was the same as puts 'hello'. What am I missing?
In your example, you are declaring the value of x to be puts 'hello'. The value of x in this case is nil. Try it out in your irb console.
x
=> nil
If you try to call nil on puts you will get this output
puts nil
=>
nil
As for why the method returns nil
The puts method echoes the previous argument to the console. In this case, nil is actually the return value.
Here is some info from the documentation
puts(obj, ...) → nil
Writes the given objects to ios as with IO#print. Writes a record separator (typically a newline) after any that do not already end with a newline sequence. If called with an array argument, writes each element on a new line. If called without arguments, outputs a single record separator.
http://ruby-doc.org/core-2.2.2/IO.html#method-i-puts
Here is the source code for that method
if (argc == 0) {
rb_io_write(out, rb_default_rs);
return Qnil;
}
Take a look at that last line. return Qnil;

What's the difference between `puts` and `return` result?

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"

Ruby puts command in modules returning nil

i am working though LearnTocodethehardway.com http://ruby.learncodethehardway.org/book/ex25.html
On ex25. In the example there is a module that has a bunch of methods that return or print values. The Print_last_word method when supplied with an array of strings just puts nil. it does this even in his example output. My question would then be why?
To be precise, it doesn't puts nil - it puts the last word and returns nil. Here's the example output:
>> Ex25.print_last_word(words)
wait. # <- this is the output
=> nil # <- this is the return value
puts always returns nil.
UPDATE
There seems to be a bug in print_first_word:
module Ex25
def Ex25.print_first_word(words)
word = words.pop(0)
puts word
end
end
Ex25.print_first_word(["foo", "bar", "baz"])
#=> nil
This is because ["foo", "bar", "baz"].pop(0) returns an empty array and puts [] just returns nil without printing anything.
A working implementation (in the exercise's style) could look like this:
module Ex25
def Ex25.print_first_word(words)
word = words.shift
puts word
end
end
To make it more easy to understand:
"puts" never is used for its return value. It is used for its side effect if you wanted a method that would return a word, you would then do something with that word.
words = ["apple", "cucumber", "apple"]
def give_me_first_word(array_of_words)
array_of_words.first
end
variable_to_be_used_later = give_me_first_word(words)
This function would return "apple"(and in this case the variable would be assigned "apple"), but it would puts nothing to the screen. This value would then be used in another program or function.
If you puts a value, you would then not need to return it to any other program as it's already served its purpose. It's actually intuitive because if puts also returned the value, it would be doing two things. The counterpart to "puts" would be "return" that simply returns the value and does not display it to the screen.

Resources