3

I am trying to write a simple DSL (against Redis) and I would like to define []+= myself

I have

def []=(key,val)
  @redis.zadd(@name,val,key)
end

and I would like to define

def []+=(key,val)
  @redis.zincrby(@name,val,key)
end

But my understanding is that Ruby provides the "[]+=" operator automaticallygiven []=

Is there a way to over-ride this behavior Obviously I don't want this because I would not be able to, say, run this in pipeline mode

Charles
  • 495
  • 1
  • 5
  • 12

2 Answers2

6

No, <operator>= can not be redefined in Ruby.

You can try to get really fancy and wrap your return values in classes that delegate to the actual value. This way, they behave like the actual value, but you can play tricks, for instance with +.

Here's a simple example:

require 'delegate'
module Redis
  class Set
    class Value < SimpleDelegator
      def +(val)
        Increment.new(self, val)
      end
    end

    class Increment < SimpleDelegator
      attr_reader :increment
      def initialize(source, increment)
        super(source.__getobj__ + increment)
        @increment = increment
      end
    end

    def [](key)
      Value.new(@redis.not_sure_what(@name, key))
    end

    def []=(key,val)
      if val.is_a?(Increment)
        @redis.zincrby(@name,val.increment,key)
      else
        @redis.zadd(@name,val,key)
      end
    end
  end
end

This is just a starting point. You'll have to be more careful than this, for example by checking the key is the same. In my simplistic example, redis[:foo] = redis[:bar] + 1 would actually be equivalent to redis[:foo] += 1...

Marc-André Lafortune
  • 78,216
  • 16
  • 166
  • 166
  • 2
    +1 (because it's interesting) but I would generally advise against such an approach ... as the added complexity (and required knowledge of) the system *likely* isn't worth it. –  Jun 15 '12 at 22:49
  • I agree that messing with the operators is bad juju. It can make debugging and maintenance really difficult. – the Tin Man Jun 15 '12 at 23:16
2

Nope. x[y] += z expands to exactly x[y] = x[y] + z:

class << (object = Object.new)
  def [](key)
    puts "[#{key.inspect}]"
    key
  end

  def []=(key, value)
    puts "[#{key.inspect}] = #{value.inspect}"
    value
  end
end

# These are all equivalent
object['See?'] += " It's impossible."
object['See?'] = object['See?'] + " It's impossible."
object.[]=('See?', object.[]('See?').+(" It's impossible."))

# They all produce the same output:
# ["See?"]
# ["See?"] = "See? It's impossible."
# => "See? It's impossible."

You will have to create a separate method.

Matheus Moreira
  • 17,106
  • 3
  • 68
  • 107
  • 2
    While the conclusion is correct, this code *doesn't show* that it is impossible. That is, it *does not* preclude a special `[]+=` operator syntax or binding rules for `+=`. To "prove" this, one just has to show that such "special" operators/binding are not defined in the applicable Ruby specification. (And good luck finding a formal Ruby specification! :-/) –  Jun 15 '12 at 22:13
  • 2
    @pst: The ISO specification was officially ratified quite a while ago. – Jörg W Mittag Jun 16 '12 at 00:03
  • 1
    @pst, it really is great to see Ruby language drop the reference implementation in favor of [an international standard](http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=59579). I certainly would like to reference it in my answers; so many C questions have been answered elegantly that way. Unfortunately, I don't have a copy. :) – Matheus Moreira Jun 16 '12 at 17:41
  • 1
    @pst: In general, RubySpec is the place to look. All implementations run it, all implementations contribute to it. The ISO spec is intended to be implementable by *all* existing Ruby implementations, including *both* MRI (which can *only* run 1.8) and YARV (which can *only* run 1.9), so, it only specifies the intersection of 1.8 and 1.9. In fact, it only specifies a very small subset of the intersection of 1.8 and 1.9, in particular, the standard library is missing completely, the core library is missing quite a bit and even the language is incomplete. It's a "minimal useful subset of Ruby". – Jörg W Mittag Jun 17 '12 at 01:57
  • 1
    @pst, [the __final draft__ (September 2010)](http://www.ipa.go.jp/osc/english/ruby/) is available. – Matheus Moreira Jun 17 '12 at 16:14