Difference between print and return [duplicate] - ruby-on-rails

This question already has answers here:
what is the point of return in Ruby?
(7 answers)
Closed 8 years ago.
When inside of a method in Ruby, what is the difference between print and return?
def squared_number(num)
return (num**2)
end
and
def squared_number(num)
print (num**2)
end

return ends current method returning passed parameter as a result. Example:
def add(a, b)
return a + b
end
c = add(1, 2)
In Ruby last statement returns value automatically. So we can define our add method like this
def add(a, b)
a + b
end
But return is very useful, if you want to end a method execution prior to the last line. For example:
def specialAdd(a, b)
if a < 0
return -1
end
a + b
end
This method returns always -1 if the first argument is negative. In all other cases it works just like add method.
On the other hand the print method outputs the passed parameter to the standard output (console) returning nil as a result. We can see it using irb - interactive ruby console:
$ irb
irb(main):002:0> print "Hello World\n"
Hello World
=> nil
irb(main):003:0>
Here we see "Hello World" plus newline printed. The returned value of the print method is nil.

A lot.
print will output the number without a newline on the end.
return will return the number from the method.

Related

Ruby: "&& return" vs "and return"

While going through the Rails guide at http://guides.rubyonrails.org/layouts_and_rendering.html#avoiding-double-render-errors ,
I wrote a test program to test Ruby's && return, and I got this strange behavior:
def test1
puts 'hello' && return
puts 'world'
end
def test2
puts 'hello' and return
puts 'world'
end
This is the result output:
irb(main):028:0> test1
=> nil
irb(main):029:0> test2
hello
world
=> nil
What accounts for the difference?
Check out the difference between and and &&. In the examples you give the method puts is called without parens around it's arguments and the difference in precedence changes how it is parsed.
In test 1 && has higher precedence than the method call. So what's actually happening is puts('hello' && return). Arguments are always evaluated before the methods they're called with -- so we first evaluate 'hello' && return. Since 'hello' is truthy the boolean does not short circuit and return is evaluated. When return we exit the method without doing anything else: so nothing is ever logged and the second line isn't run.
In test 2 and has a lower precedence than the method call. So what happens is puts('hello') and return. The puts method logs what is passed to it and then returns nil. nil is a falsey value so the and expression short circuits and the return expression is never evaluated. We just move to the second line where puts 'world' is run.

metaprograming String#scan and globals?

My goal is to replace methods in the String class with other methods that do additional work (this is for a research project). This works for many methods by writing code in the String class similar to
alias_method :center_OLD, :center
def center(args*)
r = self.send(*([:center_OLD] + args))
#do some work here
#return something
end
For some methods, I need to handle a Proc as well, which is no problem. However, for the scan method, invoking it has the side effect of setting special global variables from the regular expression match. As documented, these variables are local to the thread and the method.
Unfortunately, some Rails code makes calls to scan which makes use of the $& variable. That variable gets set inside my version of the scan method, but because it's local, it doesn't make it back to the original caller which uses the variable.
Does anyone know a way to work around this? Please let me know if the problem needs clarification.
If it helps at all, all the uses I've seen so far of the $& variable are inside a Proc passed to the scan function, so I can get the binding for that Proc. However, the user doesn't seem to be able to change $& at all, so I don't know how that will help much.
Current Code
class String
alias_method :scan_OLD, :scan
def scan(*args, &b)
begin
sargs = [:scan_OLD] + args
if b.class == Proc
r = self.send(*sargs, &b)
else
r = self.send(*sargs)
end
r
rescue => error
puts error.backtrace.join("\n")
end
end
end
Of course I'll do more things before returning r, but this even is problematic -- so for simplicity we'll stick with this. As a test case, consider:
"hello world".scan(/l./) { |x| puts x }
This works fine both with and without my version of scan. With the "vanilla" String class this produces the same thing as
"hello world".scan(/l./) { puts $&; }
Namely, it prints "ll" and "ld" and returns "hello world". With the modified string class it prints two blank lines (since $& was nil) and then returns "hello world". I'll be happy if we can get that working!
You cannot set $&, because it is derived from $~, the last MatchData.
However, $~ can be set and that actually does what you want.
The trick is to set it in the block binding.
The code is inspired by the old Ruby implementation of Pathname.
(The new code is in C and does not need to care about Ruby frame-local variables)
class String
alias_method :scan_OLD, :scan
def scan(*args, &block)
sargs = [:scan_OLD] + args
if block
self.send(*sargs) do |*bargs|
Thread.current[:string_scan_matchdata] = $~
eval("$~ = Thread.current[:string_scan_matchdata]", block.binding)
yield(*bargs)
end
else
self.send(*sargs)
end
end
end
The saving of the thread-local (well, actually fiber-local) variable seems unnecessary since it is only used to pass the value and the thread never reads any other value than the last one set. It probably is there to restore the original value (most likely nil, because the variable did not exist).
One way to avoid thread-locals at all is to create a setter of $~ as a lambda (but it does create a lambda for each call):
self.send(*sargs) do |*bargs|
eval("lambda { |m| $~ = m }", block.binding).call($~)
yield(*bargs)
end
With any of these, your example works!
I wrote simple code simulating the problem:
"hello world".scan(/l./) { |x| puts x }
"hello world".scan(/l./) { puts $&; }
class String
alias_method :origin_scan, :scan
def scan *args, &b
args.unshift :origin_scan
#mutex ||= Mutex.new
begin
self.send *args do |a|
break if !block_given?
#mutex.synchronize do
p $&
case b.arity
when 0
b.call
when 1
b.call a
end
end
end
rescue => error
p error, error.backtrace.join("\n")
end
end
end
"hello world".scan(/l./) { |x| puts x }
"hello world".scan(/l./) { puts $& }
And found the following. The change of containment of the variable $& became inside a :call function, i.e. on 3-rd step before :call $& contains a valid value, but inside the block it becomes the invalid. I guess this become due to the singularity stack and variable restoration during the change process/thread context, because, probably, :call function can't access the :scan local state.
I see two variants: the first is to avoid to use global variables in the specific function redefinitions, and second, may to dig sources of ruby more deeply.

Output value of puts in Ruby

I'm probably missing something really obvious here. I have the following Ruby method:
def pair_array
return self.pair.each_slice(2) {
|x| puts x.join(" & ")
}.to_s
end
When I try to display the value of this method in my Rails view by calling #team.pair_array nothing appears, but the correct value gets printed on the console. I know this is probably because I'm using puts. How can I get the result of this method to display in my view?
You're confusing printing with returning a value. puts returns nil, and each_slice does not return the result of the block anyway. What you want is this:
def pair_array
pair.each_slice(2).map {|arr| arr.join ' & '}
end

rspec and_return multiple values

I am trying to stub a method that returns multiple values. For example:
class Foo
def foo(a,b)
return a + 1, b + 2
end
end
I want to stub it but I'm having trouble with and_return with 2 value returns
f = Foo.new
f.stub!(:foo).and_return(3,56)
doesn't work. It basically returns 3 the first time it's called and 56 the second time. Does anyone know what the syntax would be to have it return 3,56 the first time it's called? Is this even possible with rspec?
thanks in advance...
jd
Multiple-value returns are arrays:
> def f; return 1, 2; end
> f.class
=> Array
So return an array:
f.stub!(:foo).and_return([3, 56])

How to do lazy evaluation of Ruby arguments

I have a code to do a check of nil in ruby. So what I want to achieve is this:
for example, if I call get_score_value(nil,(nil-1)). I want ruby to delay the evaluation of nil-1 till it reaches the get_score_value function, instead of evaluate it before it got passed in the function. In another word, I want to pass a mathematical expression as an argument into a method.
What is the most elegant way to do this in ruby? Thanks very much
def get_score_value(value,value2)
value.nil? ? "NULL" : value2.round(2)
end
UPDATE:
I just realized this question is actually related to the topic of lazy and strict evaluation. ( the following is from this great site:
http://www.khelll.com/blog/ruby/ruby-and-functional-programming/
Strict versus lazy evaluation
Strict evaluation always fully evaluates function arguments before invoking the function. Lazy evaluation does not evaluate function arguments unless their values are required to be evaluated. One use of Lazy evaluation is the performance increases due to avoiding unnecessary calculations.
However as the following example shows, Ruby use Strict evaluation strategy:
print length([2+1, 3*2, 1/0, 5-4])
=>ZeroDivisionError: divided by 0
The third parameter of the passed array contains a division by zero operation and as Ruby is doing strict evaluation, the above snippet of code will raise an exception.
You might be interested in using a Proc...
func = Proc.new {|n| n -1 }
def get_score_value(value, proc)
if value.nil?
return proc.call(0)
end
end
p get_score_value(nil, func)
Your proc is like a normal method, it can still test for nil and things like that.
Or, it allows you to provide separate functions to handle those situations:
func1 = Proc.new {|n| n -1 }
func2 = Proc.new { "was nil" }
def check_for_nil(value, funcNil, funcNotNil)
if value.nil?
return funcNil.call()
else
return funcNotNil.call(value)
end
end
p check_for_nil(nil, func2, func1)
p check_for_nil(1, func2, func1)
Also note the potential use of the or keyword in cases when you simply want to convert it to an empty or default type of the input (i.e. use 0 for numbers, [] for arrays, etc.)
def get_score_value(value)
(value or 0).round(2)
end
The Ruby-ish way to do this is to put your expression in your method's block and have the method execute a conditional yield.
def f x
yield if x
end
x = nil
f x do
x - 1
end
You can use a block:
def get_score_value value
value.nil? ? "NULL" : yield
end
x = 1
puts get_score_value(x) { x-1 } #=> 0
x = nil
puts get_score_value(x) { x-1 } #=> "NULL"

Resources