Not sure if I am searching in a wrong way, but couldn't find the answer anywhere online...
What does :^ stand for in Ruby? In particular trying to understand the code below:
# this returns the element in array_of_numbers, which occurs an odd number of times
array_of_numbers.reduce(:^)
# this returns 0
[1,2,3].reduce(:^)
# this returns 4
[1,2,3,4].reduce(:^)
Was tying to understand the logic playing with different arrays, but I think I am missing something. Thanks in advance!
: in front of a name produces a Symbol.
In some contexts, a Symbol can be used as a message to an object. The object that receives the message reacts to it by calling its method that has the same name as the symbol (if such a method exists).
In your examples, this method is Integer#^, which represent the exclusive OR bit operator.
[1,2,3].reduce(:^) is, more or less, the same as 1 ^ 2 ^ 3.*
Being an OOP language, 1 ^ 2 ^ 3 in Ruby is syntactic sugar for (1.^(2)).^(3).
Read more about the exclusive OR bit operator.
* They produce the same result but the explicit expression should be faster.
Related
I am learning OCaml and I'm a complete beginner at this point. I'm trying to get used to the syntax and I just spent 15 minutes debugging a stupid syntax error.
let foo a b = "bar";;
let biz = foo 2. -1.;;
I was getting an error This expression has type 'a -> string but an expression was expected of type int. I resolved the error, but it prompted me to learn what is the best way to handle this syntax peculiarity.
Basically OCaml treats what I intended as the numeric constant -1. as two separate tokens: - and 1. and I end up passing just 1 argument to foo. In other languages I'm familiar with this doesn't happen because arguments are separated with a comma (or in Scheme there are parentheses).
What is the usual way to handle this syntax peculiarity in OCaml? Is it surrounding the number with parentheses (foo 2. (-1.)) or there is some other way?
There is an unary minus operator ~-. that can be used to avoid this issue: foo ~-.1. (and its integer counterpart ~-) but it is generally simpler to add parentheses around the problematic expression.
I'm wondering why calls to operator methods don't require a dot? Or rather, why can't normal methods be called without a dot?
Example
class Foo
def +(object)
puts "this will work"
end
def plus(object)
puts "this won't"
end
end
f = Foo.new
f + "anything" # "this will work"
f plus "anything" # NoMethodError: undefined method `plus' for main:Object
The answer to this question, as to pretty much every language design question is: "Just because". Language design is a series of mostly subjective trade-offs. And for most of those subjective trade-offs, the only correct answer to the question why something is the way it is, is simply "because Matz said so".
There are certainly other choices:
Lisp doesn't have operators at all. +, -, ::, >, = and so on are simply normal legal function names (variable names, actually), just like foo or bar?
(plus 1 2)
(+ 1 2)
Smalltalk almost doesn't have operators. The only special casing Smalltalk has is that methods which consist only of operator characters do not have to end with a colon. In particular, since there are no operators, all method calls have the same precedence and are evaluated strictly left-to-right: 2 + 3 * 4 is 20, not 14.
1 plus: 2
1 + 2
Scala almost doesn't have operators. Just like Lisp and Smalltalk, *, -, #::: and so on are simply legal method names. (Actually, they are also legal class, trait, type and field names.) Any method can be called either with or without a dot. If you use the form without the dot and the method takes only a single argument, then you can leave off the brackets as well. Scala does have precedence, though, although it is not user-definable; it is simply determined by the first character of the name. As an added twist, operator method names that end with a colon are inverted or right-associative, i.e. a :: b is equivalent to b.::(a) and not a.::(b).
1.plus(2)
1 plus(2)
1 plus 2
1.+(2)
1 +(2)
1 + 2
In Haskell, any function whose name consists of operator symbols is considered an operator. Any function can be treated as an operator by enclosing it in backticks and any operator can be treated as a function by enclosing it in brackets. In addition, the programmer can freely define associativity, fixity and precedence for user-defined operators.
plus 1 2
1 `plus` 2
(+) 1 2
1 + 2
There is no particular reason why Ruby couldn't support user-defined operators in a style similar to Scala. There is a reason why Ruby can't support arbitrary methods in operator position, simply because
foo plus bar
is already legal, and thus this would be a backwards-incompatible change.
Another thing to consider is that Ruby wasn't actually fully designed in advance. It was designed through its implementation. Which means that in a lot of places, the implementation is leaking through. For example, there is absolutely no logical reason why
puts(!true)
is legal but
puts(not true)
isn't. The only reason why this is so, is because Matz used an LALR(1) parser to parse a non-LALR(1) language. If he had designed the language first, he would have never picked an LALR(1) parser in the first place, and the expression would be legal.
The Refinement feature currently being discussed on ruby-core is another example. The way it is currently specified, will make it impossible to optimize method calls and inline methods, even if the program in question doesn't actually use Refinements at all. With just a simple tweak, it can be just as expressive and powerful, and ensure that the pessimization cost is only incurred for scopes that actually use Refinements. Apparently, the sole reason why it was specified this way, is that a) it was easier to prototype this way, and b) YARV doesn't have an optimizer, so nobody even bothered to think about the implications (well, nobody except Charles Oliver Nutter).
So, for basically any question you have about Ruby's design, the answer will almost always be either "because Matz said so" or "because in 1993 it was easier to implement that way".
The implementation doesn't have the additional complexity that would be needed to allow generic definition of new operators.
Instead, Ruby has a Yacc parser that uses a statically defined grammar. You get the built-in operators and that's it. Symbols occur in a fixed set of sentences in the grammar. As you have noted, the operators can be overloaded, which is more than most languages offer.
Certainly it's not because Matz was lazy.
Ruby actually has a fiendishly complex grammar that is roughly at the limit of what can be accomplished in Yacc. To get more complex would require using a less portable compiler generator or it would have required writing the parser by hand in C, and doing that would have limited future implementation portability in its own way as well as not providing the world with the Yacc input. That would be a problem because Ruby's Yacc source code is the only Ruby grammar documentation and is therefore "the standard".
Because Ruby has "syntax sugar" that allows for a variety of convenient syntax for preset situations. For example:
class Foo
def bar=( o ); end
end
# This is actually calling the bar= method with a parameter, not assigning a value
Foo.new.bar = 42
Here's a list of the operator expressions that may be implemented as methods in Ruby.
Because Ruby's syntax was designed to look roughly like popular OO languages, and those use the dot operator to call methods. The language it borrowed its object model from, Smalltalk, didn't use dots for messages, and in fact had a fairly "weird" syntax that many people found off-putting. Ruby has been called "Smalltalk with an Algol syntax," where Algol is the language that gave us the conventions you're talking about here. (Of course, there are actually more differences than just the Algol syntax.)
Missing braces was some "advantage" for ruby 1.8, but with ruby 1.9 you can't even write method_0 method_1 some param it will be rejected, so the language goes rather to the strict version instead of freeforms.
I'm not actually going to use this in anything in case it does actually work but is it possible to redefine 0 to act as 1 in Ruby and 1 to act as 0? Where does FixNum actually hold its value?
No, I don't think so. I'd be very suprised if you managed to. If you start overriding Fixnum's methods/operators, you maaaybe might get near that (i.e. override + so that 1+5 => 5, 0+5 => 6 etc), but you will not get full replacement of literal '0' with value 1. At least marshalling to native would expose the real 0 value of the Fixnum(0).
To be honest, I'm not really sure if you can even override the core operations like + op on a Fixnum. That could break so many things..
As far as I remember from 1.8.3 source, simple integers and doubles are held right inside a 'value' and are copied all around *). There is no singular "0", "1" or "1000" value. There is no extra dereference that would allow you to swap all the values with one shot. I doubt it changed in 1.9 and I doubt anyone got any weird idea about that in 2.0. But I don't actually know. Still, that would be strange. No platform I know interns integers and floatings.. Strings, sometimes array literals, but numbers?
So, sorry, no #define true false jokes :)
--
*) clarification from Jörg W Mittag (thanks, this is exactly what I was referring to):
(..) Fixnums do not have a place in memory, their pointer value is "magic" (in that it cannot possibly occur in a Ruby program) and treated specially by the runtime system. Read up on "tagged pointer representation", e.g. here.
Assignment does not alias Fixnum objects. There is effectively only one Fixnum object instance for any given integer value, so, for example, you cannot add a singleton method to a Fixnum. Any attempt to add a singleton method to a Fixnum object will raise a TypeError. Source
That pretty much means you can't edit a Fixnum and therefor not redefine 0 or 1 in native ruby.
Though as these Fixnums are also Objects they have unique object id's that cleary reference them somewhere in the memory. See BasicObject#__id__
If you can locate the memory space where 0 and 1 objects are and switch these, you should have effectivle switched 0 and 1 behavior in ruby as now either will reference the other object.
So to answer your question: No redefining Fixnums is not possible in Ruby, switching their behaviour should be possible though.
I want to write a tiny DSL in ruby for simple arithmetic. It would look something like this:
whats 1 + 1
=> 2
whats 2 * 2
=> 4
The use case is teaching my child to program. I was showing her basic programming with irb, and when I gave her the keyboard she typed "whats 2 + 2" - possible in ruby?
Actually, it's quite simple:
def whats expr; expr end
whats 1 + 1
# => 2
What you want can’t be done all that elegantly because of Ruby’s operator precedence. In other words, because whats 1 + 1 is the same as whats(1 + 1) (and whats(2)), the whats method has no idea that an operation occurred in its arguments.
You’ll have to override Fixnum#+ (and any other operators) to return some sort of builder object. For example:
MathQuery = Struct.new(:left, :operator, :right)
class Fixnum
def + other
MathQuery.new(self, :+, other)
end
end
Then 1 + 1 would return a MathQuery instance, which whats would receive and know how to handle.
Of course, the problem with this is that you’d need to somehow also make normal math operations still work, since lots of code obviously expects them to. Not quite sure how to pull that off, though. Maybe if everything always coerced with to_int, etc.…
In which case you might be better off writing an actual mini-language and parser using something like Treetop.
Write a method called 'whats', accept any number of arguments, match the operator portion(s), and proceed.
"Inches/yard: #{12*3}"
"#{"Tora! "*3}"
The second example is confusing, unless you remember that everything is an object in
Ruby (yes, even string literals! They are of class String.). Since the string literal
creates a String object, you can act on it just like any other object. In this case,
multiplying a string by 3 simply does what you would think: makes three copies of the
string.
I read the above para in one of the ruby book. The first line says The second example is confusing, unless you remember that everything is an object in Ruby. What is there in the second example that i should remember ,everything is an object in ruby ? Isn't it just a feature that multiplying by 3 will print tora three times ?
I don't exactly understand what does the author want me to understand from the above paragraph
Well, yes you can consider it a feature maybe, but what the author is perhaps trying to explain (although not very clearly at least in this one paragraph), is that what actually is happening is this:
"Tora !" is an object of class String ("everything is an object")
"you can act on it just like any other object", meaning:
"you can call any method on it just like any other object".
In this case you are calling the method * (multiply).
So what ACTUALLY is happening is that the "Tora !" String gets called in a fashion like this:
"Tora ! ".*(3)
=> "Tora ! Tora ! Tora ! "
You see? The operator * is just a method on the String object.
In many simpler languages operators are actually "baked into" the language itself, and do not operate on the targets as method calls.
If you're not used to other languages you might not find it all that remarkable, since in Ruby it's just a normal everyday thing. You just never need to type 1.+(2), Ruby does it for you automatically when you type 1 + 2.
So this is what the author wants you to remember - all operators and operations are just essentially method calls on other objects.
"Tora! a" is an instance of the String class. You can call methods on it. This isn't possible in many languages, e.g. PHP.
('*' is just the method name)
"#{"Tora! "*3}"
"Isn't it just a feature that multiplying by 3 will print tora three times ?".
That is inexact. There is no such thing as a multiplying operator in Ruby. There is a method ".*" (and the parser treats "*" the same way) defined on both String and Numeric objects (but both don't print anything). They do very different things, but the result is what you'd expect.
Well, maybe this was not what the author wanted you to understand, it is important anyway.