shin
shin

Reputation: 32721

What kinds of names are legal for Ruby methods?

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

Answers (2)

John Feminella
John Feminella

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

Ray Toal
Ray Toal

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

Related Questions