Its very simple question but I am at beginning level and little bit confused from if modifier of Ruby, i search on Google but not clear yet how it is different than other programming languages like java etc.
can anyone make me understand with simple example or refer to useful blog please.
Thanks in advance. :)
Favor modifier if/unless usage when you have a single-line body. Like :
number = 4
puts "number is even" if number.even?
# >> "number is even"
If you have more than one line of logic, then use the traditional way to write it :
number = 4
if number.even?
# some work with number then print it
puts "number is even"
end
# >> "number is even"
expr if expr
executes left hand side expression, if right hand side expression is true.
There is a gotcha with using the if modifier, which could be a source of bugs. The if modifier has very low precedence and binds more loosely than the assignment operator. That is, the assignment expression will supersede the modifier expression.
If x does not have a method named foo, then nothing happens at all, and the value of y is not modified.
y = x.foo if x.respond_to? :foo
In the second line, the if modifier applies only to the method call. If x does not have a foo method, then the modified expression evaluates to nil, and this is the value that is assigned to y.
y = (x.foo if x.respond_to? :foo)
This really could trip up your program. Again, y is not modified in first example. y is assigned value nil in second example:
y = x.foo if x.respond_to? :foo
y = (x.foo if x.respond_to? :foo)
Related
I'm practicing a Ruby program for 2D coordinate operations. Among them, the writing of def +(other) and def -(other) confuses me. I have the following three questions:
Why is the method name equal to the operator name?
Where are the parameters received? Passed from where?
Why is the parameter other called other, and what is its value and
transmission process?
This is code
class Point
attr_accessor :x, :y
def initialize(x=0, y=0)
#x, #y = x, y
end
def inspect # p印出(x, y)
"(#{x}, #{y})"
end
def +(other)
self.class.new(x + other.x, y + other.y)
end
def -(other)
self.class.new(x - other.x, y - other.y)
end
end
point0 = Point.new(3, 6)
point1 = Point.new(1, 8)
p point0
p point1
p point0 + point1
p point0 - point1
it will eventually print
(3, 6)
(1, 8)
(4, 14)
(2, -2)
Why is the method name equal to the operator name?
Why not? Why should the symbol used to define the operator not be the symbol used to call it? That's how we do it for every other method, after all: if I want to call foo, I define def foo.
The Language designers could have chosen any arbitrary name. But it just makes sense to have the name of the method be the same symbol that you use to call it. Can you imagine the confusion if the language designers had chosen, for example, the symbol - for the name of the method which corresponds to the + operator?
Other programming languages make different choices. For example, in C++, the name of the function corresponding to the + operator is operator+. In Python, the name of the method corresponding to the + operator is __add__. (More precisely, when encountering the expression a + b, Python will first try calling a.__add__(b) and if that is not implemented by a, then it will try the "reverse add" b.__radd__(a).)
In C#, there is no method name which corresponds to the operator, rather, there is an operator keyword followed by the symbol corresponding to the operator.
If you want to know all the nitty-gritty details about how operator expressions are evaluated in Ruby, I recommend checking out Section 11.4.3 Unary operator expressions and Section 11.4.4 Binary operator expressions of the ISO/IEC 30170:2012 Information technology — Programming languages — Ruby specification.
Where are the parameters received? Passed from where?
It's not quite clear what you mean by this. A parameter is kind of like a "hole" or a placeholder in the method definition. This "hole" then gets filled in with an argument when you actually call the method. For example, here:
def foo(a, b) a + b end
a and b are parameters (more precisely, mandatory positional parameters, they are mandatory because you have to pass an argument for them and they are positional because which argument gets bound to which parameter in the parameter list depends on the position of the argument in the argument list). You don't actually know what the result of this method will be because you don't know what a and b are. They are placeholders for values that will be filled in when you call the method:
foo(2, 3)
Here, 2 and 3 are arguments (more precisely, positional arguments). The argument 2 gets bound to the parameter a because 2 is the first positional argument in the argument list and a is the first positional parameter in the parameter list. The argument 3 gets bound to the parameter b because 3 is the second positional argument in the argument list and b is the second positional parameter in the parameter list.
So, the code that gets ultimately executed for this particular method call is (replacing a with 2 and b with 3):
2 + 3
Please note: this is a simplified explanation. The mental model of replacing every occurrence of the parameter in the method definition body with the argument expression is a good first approximation, but it is not actually what Ruby does. In particular, that mental model I just described corresponds to the call-by-name evaluation strategy, whereas Ruby actually uses a special case of the call-by-value evaluation strategy called call-by-object-sharing.
You can observe the difference in this code:
def bar(a) a + a end
bar((puts "Hello"; 23))
# Hello
#=> 46
In the "replace every occurrence of the parameter with the argument expression" mental model which corresponds to call-by-name, the code would look like this:
(puts "Hello"; 23) + (puts "Hello"; 23)
# Hello
# Hello
#=> 46
and Hello would be printed twice.
However, with call-by-value and call-by-object-sharing, the argument expression gets evaluated before calling the method and the result of that evaluation gets passed in, so the actual code execution looks more like this:
__fresh_variable_with_unspeakable_name__ = (puts "Hello"; 23)
# Hello
__fresh_variable_with_unspeakable_name__ + __fresh_variable_with_unspeakable_name__
#=> 46
If you want to know all the nitty-gritty details about how method arguments are evaluated in Ruby, I recommend checking out Section 11.3 Method invocation expressions, in particular Section 11.3.1 General description and Section 11.3.2 Method arguments of the ISO/IEC 30170:2012 Information technology — Programming languages — Ruby specification.
There is also some (unfortunately incomplete) information to be found in The Ruby Spec Suite aka ruby/spec, in particular in language/def_spec.rb and language/method_spec.rb.
Why is the parameter other called other, and what is its value and
transmission process?
The parameter other is called other because that is what the author of that piece of code chose to call it. They could have called it a or b or x or y or foo or bar or i_dont_have_the_slightest_idea_what_to_call_this_parameter_so_i_am_just_choosing_something_totally_random. If you want to know why the author of that piece of code chose to call it other, you would have to ask the author of that piece of code.
other is a somewhat popular name for the "other" operand of a binary operator definition, not just in Ruby, as you can see for example in the Python documentation as well. It does make sense if you read it out loud: in an Object-Oriented Programming Language like Ruby or Python, where operators are interpreted as being sent to one of the operands, one of the two operands of a binary operator will always be self or this and the "other" operand will be … well … the "other" operand. So, naming it other is just natural. In Ruby, this is codified in some Style Guides, for example the Rubocop Ruby Style Guide.
I am curious about how method calls relate to operator precedence. In irb, I see this:
var = puts(5)
5
=> nil
var
=> nil
This implies that the call to puts has higher precedence than the assignment operator, since nil (the return value of puts(5)) is assigned to var, rather than the method call itself. Because nil is assigned to var (as we can see on line 4), I would guess that puts(5) was called before the assignment operator.
In this Stackoverflow thread, everybody agrees that method-calls have lower precedence than every operator.
However this website lists the . as an operator for method-calls, and says that it is the highest-precedence operator.
If this second website is indeed accurate, I'm unsure about whether there is an implicit . operator when you call a method on main (and therefore about whether . being a high-precedence operator is sufficient to explain the irb session above).
In general, I'm curious about the order in which Ruby does things when it encounters a line of code, so if you know of any resources that explain that in an accessible way I would be interested in reading them.
EDIT: thanks for answers so far. Maybe I wasn't clear enough about my basic questions, which are theoretical not practical (so are arguably 'overthinking', depending on how much you like to think):
is . technically an operator, or technically not an operator?
is there a . somewhere behind the scenes every time you call a method?
are operators the basic way that Ruby decides in what order it will evaluate a line of code, or are there factors other than operators and their precedence/associativity/arity?
Thanks
You're overthinking this. Your expression is basically this: x = something. So, right-hand side must be evaluated first, then the assignment can be done.
Here is how to print AST
2.6.3 :008 > RubyVM::AbstractSyntaxTree.parse('x = puts(5)')
=> #<RubyVM::AbstractSyntaxTree::Node:SCOPE#1:0-1:11>
2.6.3 :009 > pp _
(SCOPE#1:0-1:11
tbl: [:x]
args: nil
body:
(LASGN#1:0-1:11 :x
(FCALL#1:4-1:11 :puts (ARRAY#1:9-1:10 (LIT#1:9-1:10 5) nil))))
=> #<RubyVM::AbstractSyntaxTree::Node:SCOPE#1:0-1:11>
I'm using ruby 2.6. This way is possible to solve any parsing doubt. For this case is little obvious as other answers said if you have x = expr, then expr need to be evaluated first since we're talking about a strict language, for lazy languages you will only need to evaluate expr when x is evaluated, but this is another topic
I'm guessing you come from a JavaScript or similar background. Where the following is possible:
function puts(...args) { args.forEach(arg => console.log(arg)); }
var x;
(x = puts)(5);
puts(x);
However in JavaScript calling puts without () will return the whole function. Which allows easy function assignment. However in Ruby calling puts without () will still call the method. Making parentheses optional. See the Calling Methods documentation.
In Ruby (x = puts)(5) would result in a syntax error. You can achieve the same by doing the following:
(x = method(:puts)).call(5)
# here parentheses are still required since
x = method(:puts).call(5)
# will still assign the result of the puts call to x
The first link you provided talking about operators having a higher precedence than method calls is talking about method arguments.
puts 5 + 5
# can be seen as
(puts 5) + 5
# or
puts (5 + 5)
In this case 10 is printed since the operators have higher precedence than the method call itself. This also works for the = operator, but when used as argument.
puts x = 5
Will print 5, return nil and have 5 assigned to x. When using x = puts 5, x can't be assigned without evaluating puts 5 so that is what happens first. Precedence only comes into play if the same code could be executed in multiple ways.
Calling methods with parentheses never yields the above issue.
puts(5 + 5)
# or
puts(5) + 5
Both speak for themself. Although the latter will raise a NoMethodError.
In Ruby, what is the difference between == and ===? The RDoc says
Case Equality—For class Object,
effectively the same as calling #==,
but typically overridden by
descendents to provide meaningful
semantics in case statements.
Is #== the same as ==? And could you provide an example of when/how this is used in case statements?
The two really have nothing to do with each other. In particular, #== is the equality operator and #=== has absolutely nothing to with equality. Personally, I find it rather unfortunate that #=== looks so similar to #==, uses the equals sign and is often called the case equality operator, triple equals operator or threequals operator when it really has nothing to do with equality.
I call #=== the case subsumption operator (it's the best I could come up with, I'm open to suggestions, especially from native English speakers).
The best way to describe a === b is "if I have a drawer labeled a, does it make sense to put b in it?"
So, for example, Module#=== tests whether b.is_a?(a). If you have Integer === 2, does it make sense to put 2 in a box labeled Integer? Yes, it does. What about Integer === 'hello'? Obviously not.
Another example is Regexp#===. It tests for a match. Does it make sense to put 'hello' in a box labeled /el+/? Yes, it does.
For collections such as ranges, Range#=== is defined as a membership test: it makes sense to put an element in a box labeled with a collection if that element is in the collection.
So, that's what #=== does: it tests whether the argument can be subsumed under the receiver.
What does that have to with case expressions? Simple:
case foo
when bar
baz
end
is the same as
if bar === foo
baz
end
Yes, by #== the docs mean "the instance method == of the current object".
=== is used in case statements as such:
case obj
when x
foo
when y
bar
end
Is the same as
if x === obj
foo
elsif y === obj
bar
end
Some classes that define their own === are Range (to act like include?), Class (to act like obj.is_a?(klass)) and Regexp (to act like =~ except returning a boolean). Some classes that don't define their own === are the numeric classes and String.
So
case x
when 0
puts "Lots"
when Numeric
puts(100.0 / x)
when /^\d+$/
puts(100.0 / x.to_f)
default
raise ArgumentError, "x is not a number or numeric string"
end
is the same as
if 0 == x
puts "Lots"
elsif x.is_a? Numeric
puts(100.0 / x)
elsif x =~ /^\d+$/
puts(100.0 / x.to_f)
else
raise ArgumentError, "x is not a number or numeric string"
end
Fun fact, === is also used to match exceptions in rescue
Here is an example
class Example
def self.===(exception)
puts "Triple equals has been called."
true
end
end
raise rescue Example
# => prints "Triple equals has been called."
# => no exception raised
This is used to match system errors.
SystemCallError.=== has been defined to return true when the two have the same errno. With this system call errors with the same error number, such as Errno::EAGAIN and Errno::EWOULDBLOCK, can both be rescued by listing just one of them.
I am trying to halt input from a user when their input is 42.
The correct answer on the website I'm working on is:
while line = gets
break if (/42/ =~ line)
x << line
end
The code I tried that does not work is:
while line = gets.chomp
break if (line == 42)
x << line
end
Why is this the case? Am I missing some limitations to what I can use in my if statement?
The problem is that 42 is an integer, but line is a string:
1.9.3p392 :001 > "42" == 42
=> false
So it's never the case that your if statement is getting triggered, because it's comparing two different kinds of things. Matching with a Regex fixes it, though it's looking for "42" to appear anywhere in the input (e.g. "3427"). I think what you meant to say was
while line = gets.chomp
break if (line == "42")
x << line
end
In other words, break when the input is a string with the characters 4 and 2 in it.
I suspect it's because you're comparing a number to a string. The example uses a regular expression it appears. "42" == 42 will give you false in ruby.
<< is a method(Append) on Array or String class objects. But your x not holding any referencing to such objects. Thus you are getting undefined local variable or method 'x' for main:Object (NameError).
Try this instead(by fixing local variable x to hold a practical object and converting line value to Fixnum object:
x = "hi"
while line = gets.chomp
break if (line.to_i == 42)
x << line
end
This program will help you to halt input from a user when their input is 42.
until (line = gets.chomp).to_i == 42
x << line
end
This of course bypasses the if statement you were asking about.
Your limitation for the if is based solely on the fact that you are comparing a string that will always be a string to a number, and this will never be equal. (as others have mentioned)
So we must reconsider the conditional statement. In this case, I considered it "out of place" and moved the comparison to the 'while' loop, and then inverted it to an 'until' statement, to be able to positively express the condition to end the loop on. Whenever I see a 'break' in a loop, I try to get rid of that smell, as the condition to leave a loop should really be expressed in the loop condition if possible.
I hope this helps.
Trying to do something weird that might turn into something more useful, I tried to define my own []= operator on a custom class, which you can do, and have it return something different than the value argument, which apparently you can't do. []= operator's return value is always value; even when you override this operator, you don't get to control the return value.
class Weird
def []=(key, value)
puts "#{key}:#{value}"
return 42
end
end
x = Weird.new
x[:a] = "a"
output "a:a"
return value => "a" # why not 42?
Does anyone have an explanation for this? Any way around it?
ruby MRI 1.8.7. Is this the same in all rubys; Is it part of the language?
Note that this behavior also applies to all assignment expressions (i.e. also attribute assignment methods: def a=(value); 42; end).
My guess is that it is designed this way to make it easy to accurately understand assignment expressions used as parts of other expressions.
For example, it is reasonable to expect x = y.a = z[4] = 2 to:
call z.[]=(4,2), then
call y.a=(2), then
assign 2 to the local variable x, then finally
yield the value 2 to any “surrounding” (or lower precedence) expression.
This follows the principle of least surprise; it would be rather surprising if, instead, it ended up being equivalent to x = y.a=(z.[]=(4,2)) (with the final value being influenced by both method calls).
While not exactly authoritative, here is what Programming Ruby has to say:
Programming Ruby (1.8), in the Expressions section:
An assignment statement sets the variable or attribute on its left side (the lvalue) to refer to the value on the right (the rvalue). It then returns that value as the result of the assignment expression.
Programming Ruby 1.9 (3rd ed) in section 22.6 Expressions, Conditionals, and Loops:
(right after describing []= method calls)
The value of an assignment expression is its rvalue. This is true even if the assignment is to an attribute method that returns something different.
It’s an assignment statement, and those always evaluate to the assigned value. Making this different would be weird.
I suppose you could use x.[]= :a, "a" to capture the return value.