what is [] operator in Ruby - ruby

I don't get it that [] is an operator in ruby. I was wondering that if [] is an operator then what are these parenthesis {} & (). Are these also operators?
What I know is that these symbols are used by the language parser for interpreting/compiling code.

It depends if you're talking about array literals or those brackets used for getting or assigning values from/to arrays or hashes.
As a literal, [] is just an array literal, shorthand for writing Array.new. You also asked about {}, which is a hash literal, i.e. shorthand for writing Hash.new. Parentheses are not literals (or 'operators' for that matter) – they're used to group things.
As an 'operator' for getting or assigning values, as others have pointed out in the comments, [] isn't special or conceptually different from other 'operators'.
In the same way 2 + 3 is sugar for writing 2.+(3), writing array[0] is sugar for writing array.[](0).
The reason this works is that arrays have a method that's literally called []. You can find it by getting all the methods on an array:
[].methods
# => long array including :[] (and also :[]=, by the way, for assignments)
Note that the brackets in [].methods are an array literal, not an 'operator'.
I haven't looked at the implementation of any Ruby interpreters, but my guess is they see something like array[0] and convert it to array.[](0) (or at least they treat it as such). That's why this kind of sugar syntax works and looks like 'operators' even though it's all methods under the hood.

Related

In Ruby, how can you pass more than one hash to a method, without parentheses?

In Ruby, how can one pass more than one hash to a method, without parentheses?
For example
def abc x,y
end
abc {4,5},{6,4} <-- syntax error, unexpected ',', expecting '}'
Mu points out that you can pass multiple hashes without parentheses, if you pass them in as non-literals i.e. as variables.
But other than that, so, for literal hashes,
You do(need parentheses to pass multiple literal hashes), unless you are passing keyword arguments.. You can pass multiple keyword arguments without parentheses.
a keyword argument would be when the parameters of the method include a colon like e.g. def blah x:, y: then you can call with blah y:2,x:3 . Sometimes you have to look at the parameter(s) to see if an argument is a keyword argument, e.g. if you have a method called with abc x:3
then that might be def abc x: in which case you called it with a keyword argument. Or it might be def abc x in which case you called it with a hash, omitting the {}.
When I say keyword argument, I don't mean a hash.. and vice versa, when I say hash I mean not a keyword argument.
When a call is without parentheses, you can only pass one hash and that hash has to be the last argument. And you can skip the {} around it.
note- I'm no expert, but as to a related question of whether a keyword argument is a type of hash, from what I understand, as of writing, pre ruby 3, they are, but there is a proposal for ruby 3 to have 'real' keyword arguments that are distinct from hashes https://bugs.ruby-lang.org/issues/14183
a keyword argument can't be multi-valued.
also, a hash can be automatically converted to a keyword argument. (e.g. if a method is defined with a parameter that is a keyword argument, you can pass a hash in e.g. {x:"a"} , that x being a symbol, and that hash will be converted to a keyword argument x:"a" (that x being a parameter name).
I'll add a point regarding blocks and parentheses, because a block done with {} does look a little bit like a hash though is not a hash. And a block can have some influence on whether parentheses are needed.
If you see abc {}, that {} is a block not a hash, and blocks don't count as an argument. Hence that call works for def abc but not for def abc x where one would get an error related to number of arguments passed.
even when passing a block after some other arguments, there should be no comma before the block, and if a block done with {} follows some arguments, you need parentheses, but if a block done with do .. end follows some arguments, you don't need parentheses
it is suggested that one use parentheses when one has multiple arguments, unless it's a DSL(domain specific language). Do you leave parentheses in or out in Ruby?

Can someone please explain what (:+) is in Ruby?

Can someone please explain what (:+) is in Ruby? I have tried googling it & looking a reference guides and cant find anything. Thanks, sorry Im pretty new to Ruby & programming.
A colon : before a sequence of characters* is a Symbol literal. This applies to :+, which is a Symbol with content "+".
A symbol can be used to reference a method with the same name in some contexts, and in a couple of places your example :+ can be a reference to the + operator, which is really just a method with the same name. Ruby supports syntax to call it when it sees a plain + in an expression, or in some core methods it will convert :+
As an example you can use :+ as shorthand to create a sum of an Array of integers:
[1,2,3,4].inject( :+ )
=> 10
This works because Ruby has special-cased that specific use of operators in Array#inject (actually defined in Enumberable#inject, and Array gets it from that module).
A more general use-case for a symbol like this is the send method:
2.send( :+, 2 )
=> 4
Although 2.send( "+", 2 ) works just fine too. It might seem odd when used like this instead of just 2 + 2, but it can be handy if you want to make a more dynamic choice of operator.
* The rules for the syntax allowed or not allowed in a Symbol literal are a little arcane. They enable you to write shorter literals where possible, but Ruby has to avoid some ambiguous syntax such as a Symbol with a . or whitespace in the middle. This is allowed, just you have to add quotes if you generate such a Symbol e.g. :"this.that"
Ruby will tell you
:+.class
# Symbol
(:+) is the symbol in parentheses.

Why are empty Arrays and Hashes treated differently when cast to string and then to symbol?

In Ruby, why are these two operations different for empty Arrays and Hashes?
Empty Array:
[].to_s.to_sym => :[]
Empty Hash:
{}.to_s.to_sym => :"{}"
They aren't really different, it's just that they're displayed differently. The { character can't be the start of a symbol, so it's enclosed in quote marks. It's the same thing you'd do if you wanted to create a symbol that had a - in it, since otherwise it would be interpreted as the subtraction operator. In fact, you can go into IRB and test that the quotes don't really affect the symbol.
:[] == :"[]" #=> true
So, basically, one is able to use a shorter form, and the other has to be more verbose so that the parser can understand it. But there's not an essential difference in the meaning or form of the two.
Because string representation of [] is "[]" and string representation of {} is "{}". By the way, :[] is equal to :"[]". The difference is that you can write symbol :"[]" without parenthesis, but you can't do it for :"{}", Ruby syntax disallow that.

How to use ':' to break out words in %w'dog:cat:bird' w/o split

I am trying to do %w'dog:cat:bird' but I want the character that breaks apart the words to be a : rather than whitespace as %w currently does.
I do not want to use .split as in the actual code I am using a few different % idioms for different needs and I would like to use just one syntax.
I just checked in "The Ruby Programming Language" by Matz and David Flanagan, and it appears that array literals created with %w must use spaces to delimit the elements. If you really want to have arrays of strings, delimited by ":", and you don't want to use "split" in the code, I suggest you define a method of your own which will allow you to simulate the desired behavior, maybe something like:
class Object
def w(str)
str.split(":")
end
end
Then you can write something like:
w'a:b:c'

Most concise way to test string equality (not object equality) for Ruby strings or symbols?

I always do this to test string equality in Ruby:
if mystring.eql?(yourstring)
puts "same"
else
puts "different"
end
Is this is the correct way to do this without testing object equality?
I'm looking for the most concise way to test strings based on their content.
With the parentheses and question mark, this seems a little clunky.
According to http://www.techotopia.com/index.php/Ruby_String_Concatenation_and_Comparison
Doing either
mystring == yourstring
or
mystring.eql? yourstring
Are equivalent.
Your code sample didn't expand on part of your topic, namely symbols, and so that part of the question went unanswered.
If you have two strings, foo and bar, and both can be either a string or a symbol, you can test equality with
foo.to_s == bar.to_s
It's a little more efficient to skip the string conversions on operands with known type. So if foo is always a string
foo == bar.to_s
But the efficiency gain is almost certainly not worth demanding any extra work on behalf of the caller.
Prior to Ruby 2.2, avoid interning uncontrolled input strings for the purpose of comparison (with strings or symbols), because symbols are not garbage collected, and so you can open yourself to denial of service through resource exhaustion. Limit your use of symbols to values you control, i.e. literals in your code, and trusted configuration properties.
Ruby 2.2 introduced garbage collection of symbols.

Resources