Giorgi Tsiklauri
Giorgi Tsiklauri

Reputation: 11110

Difference between array<<element and array.push(element)? or string<<"something" and string+"something"? in Ruby

Before judging me for an irrelevant question, I'll safeguard myself, that I know << is a bitwise operator. However, in both cases (array, string) it operates as just adding / concatenating values.

Any tip for clarifying whether there's difference if we use array<

Thanks

Upvotes: 1

Views: 68

Answers (2)

Cary Swoveland
Cary Swoveland

Reputation: 110675

Firstly, << is not a bit-wise operator. Nor is :<< or "<<". The first is not a Ruby object or keyword. :<< is a symbol and "<<" is a string. Fixnum#<<, by constrast, is a bit-wise operator, implemented as an instance method on the class Fixnum.

You may argue that it's obvious what you meant, but it's not. Many classes have instance methods of the same name that are unrelated. Several classes, for example, have methods called "<<", "+", "size", "replace", "select", "each" and on and on. The only way to speak meaningfully of an instance method, therefore, is to also give the class on which it is defined.

What is an "operator" in Ruby? Frankly, I don't know. I've never found a definition. Whatever it is, however, most of them are implemented as instance methods.

Many of Ruby's core methods have names that may seem unusual to those coming from other languages. Examples are "<<", "+" and "&". The important thing to remember is that these are perfectly-valid names. Let's try using them as you would any other method:

[1,2,3].<<(4)    #=> [1, 2, 3, 4] 
"cat".+("hat")   #=> "cathat" 
[1,2,3].&([2,4]) #=> [2] 

The head Ruby monk knew that his disciples would prefer to write these as follows:

[1,2,3] << 4
"cat" + "hat"
[1,2,3] & [2,4]

so he said "OK", which when translated from Japanese to English means "OK". He simply designed the Ruby parser so that when it saw the later form it would convert the expression to the standard form before parsing it further (or something like that). This has come to be called syntactic sugar. (Syntactic sugar doesn't allow you to write "cat" concat "hat", however--it only applies to names that are made up of symbols.)

My point with Ruby's operators is that most are implement with garden-variety methods, albeit methods with odd-sounding names. Yes, there are methods String#+ and Array#+ but they are completely unrelated to each other. If they were instead named String#str_add and Array#arr_add and used like so:

"abc".str_add("def")
[1,2,3].arr_add([2,4])

you probably wouldn't be asking the question you've raised.

Upvotes: 0

Andrey Deineko
Andrey Deineko

Reputation: 52357

However, in both cases (array, string) it operates as just adding / concatenating values.

It makes no difference "result-wise" - in both cases you get a value containing both operands (in that or another form).

The difference shows up in the way operands are impacted:

  • one performs in-place mutating
  • second is simply concatenating without changing the original strings.

Consider the following examples:

a = 'a'
b = 'b'

Now:

# concatenation - no changes to original strings
a + b #=> "ab"
a     #=> "a"
b     #=> "b"

Whereas:

# mutation - original string is changed in-place
a << b #=> "ab"
a      #=> "ab"

Same goes with arrays:

# concatenation - no changes to original arrays
a = ['a'] #=> ["a"]
b = ['b'] #=> ["b"]
a + b     #=> ["a", "b"]
a         #=> ["a"]
b         #=> ["b"]

# mutation - original array is changed in-place
a << b #=> ["a", ["b"]]
a      #=> ["a", ["b"]]

As to Array#push and Array#<< - they do the same thing.

Upvotes: 2

Related Questions