Reputation: 32721
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?
Upvotes: 1
Views: 276
Reputation: 311526
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.
Upvotes: 5
Reputation: 88378
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.
Upvotes: 1