|
Ruby's extreme expressiveness comes from a few things. First, everything is an object. Second, Ruby has lots of functional features that make it exceptionally concise to express certain things. Here's a simple example I'll do in JavaScript first since most people can read it. You have an array of the numbers 1 through 10 and want to get a new array with only the odd numbers. arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
arr.filter(num => num % 2)
> [1, 3, 5, 7, 9]
In Ruby you could express this the same way: arr.filter { |num| num % 2 }
=> [1, 3, 5, 7, 9]
But there's a better way. Since everything is an object, including integers, you can just ask the numbers if they are odd instead of using the mod operator. arr.filter { |num| num.odd? }
=> [1, 3, 5, 7, 9]
(Yes, method names can end in a question mark (?). By convention, methods that end in a question mark are predicate methods that return a boolean. Methods can also end in an exclamation point/bang (!). By convention, these bang methods are "dangerous" – they might do something destructive like mutate an object in-place instead of returning a new copy.)We can make this even more concise though. arr.filter(&:odd?)
=> [1, 3, 5, 7, 9]
There's a bit to unpack here.:odd? is a Symbol The & operator calls the #to_proc method on the symbol :odd? then converts the result into a block, which is passed to the filter method. In other words, the #odd? method is called on each element in the array no different than the previous example. Here's another way to express the exact same thing: arr.reject(&:even?)
=> [1, 3, 5, 7, 9]
This is just one simple example. Ruby can express many things on one line that would take several lines in other languages. This is what makes it expressive – it's the density and readability of operations.Another one of my favorite language features is that parentheses on method calls are optional, so a lot of syntax that looks like it would be language-level operators are actually just regular method calls to objects in Ruby. An example of this is ==, which is an operator in many other languages. In Ruby it is a method call. Consider this expression: true == false
This is calling the #== instance method on the object `true` (which is an instance of TrueClass), passing `false` as the first argument. Written identically: true.==(false)
This is wild if you're coming from another language where things like this are operators, but it is completely natural in Ruby. It is extremely powerful. |