How to create an operator for deep copy/cloning of

2020-03-08 02:44发布

问题:

I would like to achieve the following by introducing a new operator (e.g. :=)

a := b = {}
b[1] = 2
p a # => {}
p b # => {1=>2}

As far as I understand, I need to modify the Object class, but I don't know what to do in order to get what I want.

require 'superators'
class Object
  superator ":=" operand # update, must be: superator ":=" do |operand|
    # self = Marshal.load(Marshal.dump(operand)) # ???
  end
end

Could you help me with this?


Update

Ok, superators will probably not help me here, but I still want such operator. How can I (or you) create an extension for Ruby, which I could load as a module?

require 'deep_copy_operator'
a !?= b = {} # I would prefer ":=" but don't really care how it is spelled
b[1] = 2
p a # => {}
p b # => {1=>2}

回答1:

First of all, the syntax for superators is

superator ":=" do |operand|
  #code
end

It's a block, because superator is a metaprogramming macro.

Secondly, you have something going their with Marshal...but it's a bit of magic-ish. Feel free to use it as long as you understand exactly what it is you're doing.

Thirdly, what you are doing isn't quite doable with a superator (I believe), because self cannot be modified during a function. (if someone knows otherwise, please let me know)

Also, in your example, a must first exist and be defined before being able to call the method := in it.

Your best bet is probably:

class Object
  def deep_clone
    Marshal::load(Marshal.dump(self))
  end
end

to generate a deep clone of an object.

a = (b = {}).deep_clone
b[1] = 2
p a # => {}
p b # => {1=>2}


回答2:

wow, superators look neat! But unfortunately, this won't work for you, for two reasons. First, your operator does not match the regex (you cannot use a colon). Easy enough, find a new operator. But the second one I don't think can be overcome, the superator is basically a method name defined on the object to the left. So you can't use it for assignment statements. If your variable is not defined, then you cannot use it, that would raise an error. And if it is defined, then you can't change its type in any way that is obvious to me (maybe with some level of reflection and metaprogramming that is way beyond anything I know, but it honestly seems unlikely... of course, I would have never expected it to be possible to create superators, so who knows).

So I think you're back to hacking parse.y and rebuilding your Ruby.