On 10.10.2006 14:50, jens wille wrote:
> hi there!
> 
> would it be possible to modify how an object gets evaluated in
> boolean context? i know that by default only nil and false are
> evaluated as false, all others are true. however, i'd like to change
> that behaviour for a (yet unimplemented) BooleanFlag object which
> behaves just like true or false (according to its current value or
> "state") with the added ability of easily swapping state.
> 
> it's not that difficult to implement a class that provides the state
> swapping, but how to grasp that "evaluation in boolean context" kind
> of thing? is there any method getting called, so i can override it?
> 
> the idea is as follows:
> 
> b = BooleanFlag.new false  # create object, initially being "false"
> puts "true" if b           # this is the heavy part, since b (as a
>                            # regular object) is always "true"
> b.swap!                    # now b's state is "true" ...
> puts "true" if b           # ... and this *correctly* prints "true"

This has come up frequently in the past.  The short story is that there 
is no way to do exactly that because of performance reasons.  All sorts 
of things have been proposed including a method to_b defined in Object 
as "return self" and which is automatically called in every boolean context.

> any insights? additionally, hints on how to address such issues on
> my own are very welcome. i'm quite new to ruby (coming from perl),
> but i definitely love it - especially the metaprogramming stuff ;-)
> so maybe there's a means of digging into such internals i'm not yet
> aware of.

You can still use the #to_b pattern explicitly.  This is probably the 
cleanest solution:

BooleanFlag = Struct.new(:flag) do
   def swap!() self.flag = !flag end
   alias :to_b :flag
end

 >> f = BooleanFlag.new false
=> #<struct BooleanFlag flag=false>
 >> f.to_b
=> false
 >> f.swap!
=> true
 >> f.to_b
=> true

Alternatively / additionally you can define methods on your flag class 
similar to what Smalltalk does:

BooleanFlag = Struct.new(:flag) do
   def swap!() self.flag = !flag end
   alias :to_b :flag
   def iff() yield if to_b; self end
   def els() yield unless to_b; end
end

 >> f=BooleanFlag.new false
=> #<struct BooleanFlag flag=false>
 >> f.iff do puts "yes" end.els do puts "no" end
no
=> nil

Frankly, I never felt the need for any of these.  Maybe you present your 
business case and we can propose some other solution.

Kind regards

	robert