Is it possible to have class.property = x return something other than x?

前端 未结 3 435
野的像风
野的像风 2020-12-04 01:42

Let\'s say I have a Ruby class:

class MyClass
  def self.property
    return \"someVal\"
  end

  def self.property=(newVal)
    # do something to set \"prop         


        
相关标签:
3条回答
  • 2020-12-04 01:52

    One downside is that you would break the chained assignment semantics:

    $ irb 
    irb(main):001:0> x = y = 3
    => 3
    irb(main):002:0> p x
    3
    => nil
    irb(main):003:0> p y
    3
    => nil
    irb(main):004:0> 
    

    Consider:

    x = MyClass.property = 3
    

    Then x would take true if this worked as you had expected (right-associativity). That could be a surprise for people using your interface and used to the typical semantics.

    You also got me thinking about parallel assignment, eg:

    x, y = 1, 2
    

    Apparently the return value from that expression is implementation specific... I guess I won't be chaining parallel assignments :)

    Nice question!

    0 讨论(0)
  • 2020-12-04 01:59

    Like Martin says, this would break assignment chaining.

    The way ruby assignment methods are defined to work expands MyClass.property = 3 to the equivalent of (lambda { |v| MyClass.send('property=', v); v })[3] (not really, but this shows how chaining works). The return value of the assignment is always the value assigned.

    If you want to see the result of your MyClass#property= method, then use #send:

    irb> o = Object.new
    => #<Object:0x15270>
    irb> def o.x=(y)
    irb>   @x = y+1
    irb>   puts "y = #{y}, @x = #@x"
    irb>   true
    irb> end
    => nil
    irb> def o.x
    irb>   puts "@x = #@x"
    irb>   @x
    irb> end
    => nil
    irb> o.x = 4
    y = 4, @x = 5
    => 4
    irb> o.x
    @x = 5
    => 5
    irb> o.send('x=', 3)
    y = 3, @x = 4
    => true
    

    However, the ruby way to do this is with exceptions - if something goes wrong during the assignment, raise an exception. Then all invokers must handle it if something goes wrong, unlike a return value, which can be easily ignored:

    # continued from above...
    irb> def o.x=(y)
    irb>   unless y.respond_to? :> and (y > 0 rescue false)
    irb>     raise ArgumentError, 'new value must be > 0', caller
    irb>   end
    irb>   @x = y + 1
    irb>   puts "y = #{y}, @x = #@x"
    irb> end
    => nil
    irb> o.x = 4
    y = 4, @x = 5
    => 4
    irb> o.x = 0
    ArgumentError: new value must be > 0
        from (irb):12
        from :0
    irb> o.x = "3"
    ArgumentError: new value must be > 0
        from (irb):13
        from :0
    irb> o.x
    @x = 5
    => 5
    
    0 讨论(0)
  • 2020-12-04 02:19

    I'm not a Ruby expert but I'd say no for that case I'm afraid. A property setter is solely there to set the value of a private field, not to have any side effects like returning result codes.

    If you want that functionality then forget the setter and write a new method called TrySetProperty or something which tries to set the property and returns a boolean.

    0 讨论(0)
提交回复
热议问题