I was wondering, are &&, and, ||, or base core unchangeable functionalities (like in other languages e.g.: php) or are they object methods like & <=> but defined some magical way
More details on my trait of thoughts:
[] & [10]
# => []
[].&([10])
# => []
"aaa".& 10
# NoMethodError: undefined method `&' for "aaa":String
note it say undefined method
...of course you can do.
true.& false
# => false
...but you cannot do:
true.&& false
# SyntaxError:
so If it's possibility to do
class String
# monkey patch. If you googled this don't use this in real world, use ruby mixins insted
def &(right_side)
# do something meaningfull
right_side
end
end
"aaa".& 10
# => 10 # ta-da!
is there (with some magic) possible to do:
class String
# monkey patch. If you googled this don't use this in real world, use ruby mixins insted
def &&(right side)
# do something meaningfull
right side
end
end
# => SyntaxError: (irb):13: syntax error, unexpected keyword_end
thx
These are the operators that cannot be (re)defined:
&&, || (AND, OR)
.., ... (range)
?: (ternary)
rescue
= (and **=, &&=, &=, *=, +=. -=, <<=, >>= , ||=, |=, ^=)
defined?
not
and, or
if, unless, while, until
The others, like (incomplete list) !, ~, +, -, **, *, /, %, >>, ==, != are implemented as methods and can be redefined.
David A. Black stated in his book:
[T]he conditional assignment operator ||=, as well as its rarely spotted
cousin &&=, both of which provide the same kind of shortcut as the pseudooperator methods but are based on operators, namely || and &&, which you can’t override.
Now to get into the reason please Look and read Why can't we override||and&&? and Operator Overloading.
Related
I am trying to compare a number literal with the return value of a function that could return nil or a numeric. Consider this:
def unreliable
[nil, 42].sample
end
unreliable > 10
This will blow up 50% of the time with NoMethodError: undefined method '>' for nil:NilClass. So I tried this:
unreliable&.(:>, 10)
That approach does the nil guarding I expect, but I get this when unreliable returns 42:
NoMethodError: undefined method `call' for 42:Fixnum
I suspect this has to do with the quirks of allowing only one instance to exist for each Numeric, see here. And I know I can do this:
foo = unreliable
foo && foo > 10
But is there a way to use the safe navigation operator with a numeric and :>, :<, :==, :+, :-, :/, :*, etc?
Edit: The focus on Numeric in my question is a red herring. See #Jörg's answer. I was confusing Rails's try syntax with the safe-navigation operator's syntax.
This works fine in Ruby 2.3+ :
unreliable&.> 10
For example :
[-5, 0, nil, 5].each do |unreliable|
p unreliable&.> 0
end
# false
# false
# nil
# true
The way you tried it, Ruby expects unreliable to be a callable object such as a Proc :
unreliable = Proc.new{ |*params| puts "unreliable has been called with #{params}" }
unreliable&.(:>, 10)
# unreliable has been called with [:>, 10]
unreliable.call(:>, 10)
# unreliable has been called with [:>, 10]
unreliable&.call(:>, 10)
# unreliable has been called with [:>, 10]
unreliable[:>, 10]
# unreliable has been called with [:>, 10]
With the safe-navigation operator, there's no need to put parens and the method should be a method name, not a symbol (Rails' try expects a symbol).
I suspect this has to do with the quirks of allowing only one instance to exist for each Numeric
No, this has nothing to do with that at all.
foo.(bar)
is syntactic sugar for
foo.call(bar)
Ergo,
foo&.(bar)
is syntactic sugar for
foo&.call(bar)
So, your code:
unreliable&.(:>, 10)
is syntactic sugar for
unreliable&.call(:>, 10)
I'm not sure who told you that the safe-navigation operator takes the message as a symbol argument. The whole point of the safe-navigation operator is that you only have trivial syntactic overhead by adding a single character, the & in front of the ., and the expression is otherwise unchanged.
So,
unreliable > 10
which is the same as
unreliable.>(10)
simply becomes
unreliable&.>(10)
I want to create the next DSL part:
* 'Ruby'
The next experiment shows predictable results:
def *(a)
a
end
* 'Ruby' #=> SyntaxError: (irb):4: syntax error, unexpected '\n', expecting :: or '[' or '.'
self.*(1) #=> NoMethodError: private method `*' called for main:Object
self.send(:*, 1) #=> 'Ruby'
I suppose Ruby syntax analyzer considers such expression as a splat operator or syntax sugar for the asterisk method. Can someone explain this more detailed and (if it's possible) provide solution to resolve my problem?
That's not possible. There are some methods that simply cannot be called without an explicit receiver because they would otherwise be ambiguous. In particular, in every case where you have both a unary prefix and a binary infix operator, it would be impossible to distinguish the two cases:
+ a == a.+#()
- a == a.-#()
& a # interpreted as the unary prefix proc-block conversion operator
* a # interpreted as the unary prefix splat operator
or in cases where the operator conflicts with other syntax:
/ a # interpreted as the start of a Regexp literal
For consistency, Ruby forces the use of two operands for all binary infix operators, not just the ones for which the grammar would be ambiguous.
Likewise, [] cannot be called without an explicit receiver because it would conflict with literal syntax for arrays.
The other well-known example of methods that cannot be called without an explicit receiver, is setters:
self.foo = bar # setter
foo = bar # local variable
For private setters, there is actually an exception to the rule for private methods, that allows them to be called with an explicit receiver, as long as that explicit receiver is the literal pseudo-variable keyword self. However, no such exception exists for calling private binary operators or methods like []. (There are proposals to that effect, though.)
Jörg W Mittag answers why your first expression * 'Ruby' (without an explicit receiver) raises an error.
I will add why your second expression self.*(1) (with an explicit receiver) raises an error. This is because the method is defined on the main object, which are all private by default.
This gives you that the only way to call the method is neither with nor without an explicit receiver, in other words, you cannot call that method with a form of an ordinary method call. You can only pass it in the form of a symbol describing that method, and let another method (send) execute it instead.
Here are two tests:
if [1,2,3,4].include? 2 && nil.nil?
puts :hello
end
#=>
and
if [1,2,3,4].include?(2) && nil.nil?
puts :hello
end
#=> hello
The above tells me that && has higher precedence than method arguments so it logically ands 2 && nil.nil? which is true and passes that as an argument to include?.
However, there is this test:
if [1,2,3,4].include? 2 and nil.nil?
puts :hello
end
#=> hello
So this is telling me that method arguments and 'and' have the same precedence (or method args are higher than 'and') since it passed 2 to include? before it processed 'and'.
Note: I understand that && and and have different precedence. The question is not regarding this but regarding and or or vs the arguments to a ruby method.
I can't find documentation that affirms this. For instances, this doesn't mention method arguments at all: http://phrogz.net/programmingruby/language.html#table_18.4 or http://romhack.wikia.com/wiki/Ruby_operators.
Could anyone explain this behavior? Namely in that how does ruby know to pass values as arguments to a method vs. process operators?
As you said && and and have different precedence, however the explanation for the following example:
if [1,2,3,4].include? 2 and nil.nil?
puts :hello
end
#=> hello
is the binding strenght of the and as you can read here:
Difference between "and" and && in Ruby?
This basically explains that 2 and nil.nil? will be evaluated as nil, however it will return 2 as can be seen in this example:
foo = :foo
bar = nil
a = foo and bar
# => nil
a
# => :foo
a = foo && bar
# => nil
a
# => nil
I've never seen any documentation about method argument precedence, but one rule of thumb I use when seeing method arguments is to mentally strip the whitespace wherever possible in the arguments and still have the same expression. This normally gives me the precedence:
[1,2,3,4].include? 2&&nil.nil? is the same expression, but you cannot strip the whitespace in
[1,2,3,4].include? 2 and nil.nil? and therefore, the precedence is left to right ... I.e. Method argument is 2.
Anyway, the better question is why on earth would you write statements like this?
Omitting method parenthesis is only useful for code readability. However, your statements are hardly readable and makes one pause over the code and think about it more than he should. If I was to review code like this, I would definitely fail the code review due to poor readability.
In fact, many style guides explicitly state that most methods with arguments should be parenthesized (is this even a word ;). For example:
Ruby style guide
In this article, it uses the following method.
h = {}
def h.[]=(k, v)
puts "Setting hash key #{k} with #{v.inspect}"
super
end
# 1. The standard ||= approach
h[:x] ||= 10
h[:x] ||= 20
...
I understand that this is a setter like this for =( ) part.
def noise=(noise)
#noise = noise
end
Q1. But I am not sure what .[] part is doing.
Q2. Can you use [] or other non-alphabets in a Ruby method name?
Q1. But I am not sure what .[] part is doing.
Almost everything is an object in Ruby, and we can define a method on anything that's an object. So []= is a method defined on the Hash class (an object) in Ruby, just like + and - are methods on numbers (also objects):
> 4 + 5
# => 9
> 4.+(5)
# => 9
> 10.-(3)
# => 7
Likewise, we can call the .[] or .[]= methods for objects that define it, like an Array:
> arr = ['hi', 'there', 'welcome', 'to', 'StackOverflow']
> arr.[](3)
# => "to"
or like your Hash:
> hash = {:name => 'Bob', :age => 27}
> hash[:name]
# => "Bob"
> hash[:name] = 'Steve'
# => "Steve"
Again, Ruby lets us put methods on anything that's an object, and (almost) everything is an object in Ruby. So we can define that .[] method on any class we like:
> class Foo
> def [](arg)
> arg
> end
> end
> Foo.new[456]
> # => 456
Since instances of objects are also objects, we can define that method to be only on specific instances:
> h = {} # a Hash instance
> def h.[](arg) # we're giving this instance a new method
> "received #{arg}"
> end
> h[123]
# => "received 123"
Other instances of the same class won't get that implementation:
> {:foo => :bar}[123] # other Hash instances don't have this method,
# so they're using the default Hash#[] method
# => nil
.[] is something of a special case in one respect, because we let you skip the parentheses and put the argument right inside the brackets:
> arr[3] == arr.[](3)
# => true
Q2. Can you use [] or other non-alphabets in a Ruby method name?
No, you can't use [] in the name of an arbitrary Ruby method. This is an operator (like + or - in the previous example).
You can only overload specific operators, namely (listed in order of precedence):
!, ~, + (unary)
**
- (unary)
*, /, %
+, - (binary)
<<, >>
&
|, ^
<, <=, =>, >
==, ===, !=, =~, !~, <=>
Otherwise, a Ruby method can contain any mixture of alphanumeric Unicode characters and underscores. (I'm using "alphanumeric" loosely here -- Ruby is very liberal in what it allows, and generally speaking any character that isn't otherwise reserved by the language to tokenize things will work.) It may optionally end with a single ! or ?, and it may not start with a number.
So these are valid method names:
present?
valid_user?
replace!
replace
更换 (but you probably should make your method names using the A-Z Latin alphabet so developers don't hate you)
❨╯°□°❩╯︵┻━┻
┬─┬ノ❨º_ºノ❩
replace_all
REPLACE_1
REPLACE_ALL
Note that while the last two are valid method names, by convention Rubyists usually reserve ALL-CAPS identifiers for constants, not methods.
In Ruby, [] and []= are just operators and they can be overloaded.
Here []= is being defined on the singleton class for h, in other words, it is being defined to work a certain way just for h.
So when you say h[something] = somethingelse the new method gets called.
You are right that this use is quite similar to the general use of setters.
To answer the second question, you can overload the operators shown in this table, but you can't just go ahead and create operators like <-*-> as you can in some languages.
What are the various meanings of the Ruby sharp/number sign/pound/hash(#) symbol
How many contexts does the symbol # in Ruby have ?
I know that #` represents comment
# a comment
or 'convert to the value':
i = 1
print "#{i}" # simple example
However I also see some Ruby docs describe built-in methods like these:
Array#fill
File::file?
Why do they describe the same thing using 2 different symbols ?
I am new in Ruby. Thanks
This is how instance method described:
Array#fill
So you can:
a = Array.new(2)
=> [nil, nil]
a.fill(42)
=> [42, 42]
This is how class method described:
String::new
s = String.new('abc')
=> "abc"
In Perl, # is used for commenting, and since Perl is an 'ancestor' of Ruby, the role was carried over.
The "#{}" syntax is called 'interpolation' and the pound was picked most likely because interpolation is similar in a sense to commenting, because you are changing the context of your code (in this case to another context for execution)
The # following a Class name is just meant to indicate the following identifier is a method of that Class, and is just a convention. Read more about it here: Why are methods in Ruby documentation preceded by a hash sign?
The :: is interesting, it acts similarly to the . in that you can call methods via both
Car::is_hybrid?
and
car.is_hybrid?
As you will see in most code though . is preferred for methods.
One case where :: is often preferred is where you have constant in the class and you will see this in system calls such as Math::PI or ones you create, e.g. ThePentagon::NUMBER_OF_BUILDING_SIDES
Just to show you as an example,that Ruby shows instance method preceded with the symbol # and class methods preceded with the symbol ..
class Foo
def self.foo;end
def bar;end
end
p Foo.method(:foo) # => #<Method: Foo.foo>
p Foo.new.method(:bar) # => #<Method: Foo#bar>