Limitations

Hi,

Is there any way to somehow redefine operations like ‘&&’ between my
objects?
‘&&’ is not defined as a method so I can’t just overload it. (Ruby does
not care
if an object responds to :&&, it is simply not used.) Operators with
higher precedence
than ‘&&’ usually work fine – except ‘[]=’. Seems like above ‘&&’ it
is
the object’s
responsibility to do operations and below that line it is the language
itself that
enforces the rules. But is there a way to define custom code what
should
de done by
an expression like ‘x && y’?

The same limitation bothers me with ‘||’, and with ‘and’, ‘or’ and
‘not’.
(Yes, I know that they are not operators but designed to be flow control
keywords,
however they are often used as operators…)

At the same time I’m struggling with the []=. The strange thing with
this
is
that the return value of the []= method is abandoned by Ruby but I
expected
it to be the value of the expression that the []= method returns:

class X
def []=(key, value)
“I want to be the value!!”
end
end
x = X.new
x[123] = 456 #=> 456

The value of the last expression is 456, and not the string. I’d like
to
get back the whole
x object instead of the right hand side value here. Yes, I know that
the
value of assignments
is the rhs value, but assignments in general are out of the scope of an
object, while []=
is an exceptional one. It is done by the object itself, so it would be
logical to give the
power to the object to decide the value of the operation. Is this a
deliberate behaviour or
just nobody cares the value of it?

On Fri, 25 Jan 2013 23:52:51 +0100, Nokan E. [email protected]
wrote:

responsibility to do operations and below that line it is the language
itself that
enforces the rules. But is there a way to define custom code what should
de done by
an expression like ‘x && y’?

The same limitation bothers me with ‘||’, and with ‘and’, ‘or’ and ‘not’.
(Yes, I know that they are not operators but designed to be flow control
keywords,
however they are often used as operators…)

Since I think Ruby 1.9 you can redefine the unary ! operator (class A;
def !; true; end end). This will also change the behavior of not.

|| and && are part of the language and you can’t redefine them.
(These short-circuit, which would be impossible to do if they were
redefined.) They’re handled separately throughout the parser.

At the same time I’m struggling with the []=. The strange thing with this
is
that the return value of the []= method is abandoned by Ruby but I expected
it to be the value of the expression that the []= method returns:
[…]
Is this a
deliberate behaviour or
just nobody cares the value of it?

This is intended, to make assignments sane. The same applies to every
method with name ending with ‘=’. This is intended to make code like
a[0] = b[0] = c or a[0], b[0] = c, d behave according to coders’
expectations.

On Fri, Jan 25, 2013 at 11:52 PM, Nokan E. [email protected]
wrote:

Is there any way to somehow redefine operations like ‘&&’ between my
objects?

See Matma’s reply. Why do you think you need to redefine behavior of
these operators?

Kind regards

robert

Hi Robert,

Why do you think you need to redefine behavior of these operators?

Because I’m working on a type that behaves like any other Ruby class (in
terms that it accepts all operations and messages that a Numeric, an
Array,
a Hash or anything else), but it collects all it’s history into a huge
Ruby
expression for further evaluation. It works charmingly with the normal
ops like :+, :-, :*, :/, :[], :<< etc., but, of course, it fails with
those
outside
of an object’s own world.

irb(main):001:0> x = Accumulator.new :x
=> <<< x >>>
irb(main):002:0> y = x + 123
=> <<< x + 123 >>>
irb(main):003:0> z = 2 * y
=> <<< 2 * (x + 123) >>>
irb(main):004:0> q = 1 - z ** 2
=> <<< 1 - (2 * (x + 123)) ** 2 >>>
irb(main):005:0> q+z+y
=> <<< 1 - (2 * (x + 123)) ** 2 + 2 * (x + 123) + x + 123 >>>
irb(main):006:0>

It may be useful to drop in “spy objects” (like the x above) into black
box
functions,
like crypto functions, hash calculations, numerical approximations, or
even
well-known
calculations, just to wrap them up in a huge expression instead of
looking
at them as
the code of a long method, or just look for algebric simplifications on
the
result. It can
help improving the original calculation or finding out more about the
method’s internals.

There are two huge limitations of this. One is that if the function
makes
decision
based on the value of the input, this will fail. For instance, the
expression x > 0
does not have a boolean value, but the expression <<< x > 0 >>>
itself,
which
is an Accumulator object, and has a logical value of true in conditional
expressions,
since it’s not nil nor false. The second limitation is that methods can
contain
lines like x = y && z, or with other words I have no control over them
and
they
can use &&, ||, and, or, and not in calculations that I can incorporate
into the
object’s internal expression describing it’s calculation history. The
solution for
the first one could be to break the calculation and ask the user what to
answer
for a relation like x > 0, or the Accumulator could do a parallel
calculation with
normal values (Numerics, Arrays, etc) just to return acceptable values
for
the
tested function. That’s the easier part. But it seems that it’s
impossible
to grab
“operations” like &&… :frowning:

irb(main):001:0> x = Accumulator.new :x
=> <<< x >>>
irb(main):002:0> y = x && 123
=> 123
irb(main):003:0> y
=> 123 <<<--------- this should be <<< x && 123 >>>
somehow…
irb(main):004:0> x
=> <<< x >>>
irb(main):005:0> def fib(n)
irb(main):006:1> n < 2 ? 1 : fib(n - 2) + fib(n - 1)
irb(main):007:1> end
=> nil
irb(main):008:0> (0…6).each { |i| p fib i }
1
1
2
3
5
8
13
=> 0…6
irb(main):009:0> fib x
=> 1 <<<<--------------- Well, this is because x < 2 is <<< x < 2

, which is true (at least not false or nil), so the ?: in fib()
returns
1 :frowning:
irb(main):010:0> x < 2
=> <<< x < 2 >>>
irb(main):011:0>

On Sat, Jan 26, 2013 at 6:12 PM, Nokan E. [email protected]
wrote:

of an object’s own world.
=> <<< 1 - (2 * (x + 123)) ** 2 + 2 * (x + 123) + x + 123 >>>
irb(main):006:0>

Ah, I see.

It may be useful to drop in “spy objects” (like the x above) into black box
functions,
like crypto functions, hash calculations, numerical approximations, or even
well-known
calculations, just to wrap them up in a huge expression instead of looking
at them as
the code of a long method, or just look for algebric simplifications on the
result. It can
help improving the original calculation or finding out more about the
method’s internals.

Are you aware of set_trace_func? That can also be used for spying
although getting at return values is at least difficult.

I’m afraid, without hacking the interpreter you probably won’t be able
to change behavior of && and ||. The only other alternative I can
think of right now is to parse the Ruby code yourself and execute the
AST “manually”.

Kind regards

robert