2009-04-02 6 views
12

Digamos que tengo una clase Ruby:¿Es posible que class.property = x devuelva algo que no sea x?

class MyClass 
    def self.property 
    return "someVal" 
    end 

    def self.property=(newVal) 
    # do something to set "property" 
    success = true 

    return success # success is a boolean 
    end 
end 

Si yo trato de hacer MyClass.property=x, el valor de retorno de toda la declaración es siempre x. Es una convención en muchos lenguajes basados ​​en C/inspirados para devolver un valor booleano de "éxito". ¿Es posible hacer esto para un colocador usando la "sintaxis igual" en Ruby?

Además, si esto no es posible, ¿por qué no? ¿Hay alguna desventaja concebible para permitir que una operación de "igual configurador" devuelva un valor?

Respuesta

11

Una desventaja es que usted se rompería la semántica de asignación encadenados:

$ 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> 

considerar:

x = MyClass.property = 3 

Entonces x tomaría true si esto funcionó como se había esperado (asociatividad por la derecha). Eso podría ser una sorpresa para las personas que usan su interfaz y están acostumbradas a la semántica típica.

También me hizo pensar acerca de la asignación en paralelo, por ejemplo:

x, y = 1, 2 

Al parecer, el valor de retorno de esa expresión es implementation specific ... supongo que no seré el encadenamiento de tareas paralelas :)

¡Buena pregunta!

+0

leí por primera vez esto como "si ha definido un descriptor de acceso de esa manera, se rompería la semántica de asignación encadenados ". Como la respuesta de rampion deja en claro, ese no es el caso: el valor de retorno de un método de asignación normalmente se ignora. Lo que Martin está diciendo es "el lenguaje no te permite hacer eso; si lo hiciera, romperías la semántica de asignación encadenada". –

5

No soy un experto en Ruby pero diría que no para ese caso, me temo. Un ajustador de propiedades está únicamente allí para establecer el valor de un campo privado, no para tener efectos secundarios como devolver códigos de resultado.

Si quiere esa funcionalidad, entonces olvide el setter y escriba un nuevo método llamado TrySetProperty o algo que intente establecer la propiedad y devuelva un booleano.

7

Como dice Martin, esto rompería el encadenamiento de tareas.

La forma en que se definen los métodos de asignación de ruby ​​para trabajar se amplía MyClass.property = 3 al equivalente de (lambda { |v| MyClass.send('property=', v); v })[3] (no realmente, pero esto muestra cómo funciona el encadenamiento). El valor de retorno de la asignación es siempre el valor asignado.

Si desea ver el resultado de su método de MyClass#property=, a continuación, utilizar #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 

Sin embargo, la forma de rubí de hacerlo es con excepciones - si algo va mal durante la asignación, elevar una excepción. A continuación, todos los invocadores deben manejar la situación si algo va mal, a diferencia de un valor de retorno, que puede ser fácilmente ignorado:

# 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 
Cuestiones relacionadas