¿Es posible tener class.property = x regresar algo distinto de x?
-
22-08-2019 - |
Pregunta
Digamos que tengo una clase Ruby:
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 lo intento y hago MyClass.property=x
, el valor de retorno de toda la declaración es siempre x. Es una convención en un montón de idiomas / inspirados para devolver un valor booleano "éxito" C-basada - es posible hacer esto por un colocador utilizando el "iguales sintaxis" en Ruby
Por otra parte - si esto no es posible, ¿por qué no? ¿Hay alguna desventaja concebible que permite un "colocador es igual a" operación devuelve un valor?
Solución
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>
Considere lo siguiente:
x = MyClass.property = 3
A continuación, x
tomaría true
si esto funcionó como se había esperado (asociatividad por la derecha). Eso podría ser una sorpresa para la gente que usa la interfaz y se utiliza para la semántica típicos.
También me hizo pensar en la asignación en paralelo, por ejemplo:
x, y = 1, 2
Al parecer, el valor de retorno de esa expresión es aplicación específica ... supongo que no será encadenar tareas paralelas:)
Niza pregunta!
Otros consejos
Al igual que Martin dice, esto rompería el encadenamiento de asignación.
La forma en los métodos de asignación de rubí se definen a trabajar expande MyClass.property = 3
al equivalente de (lambda { |v| MyClass.send('property=', v); v })[3]
(no realmente, pero esto demuestra cómo funciona la cadena). 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, provoca una excepción. A continuación, todos los invocadores deben manejar la situación si algo sale 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
No soy un experto en Rubí pero yo diría que no para ese caso me temo. Un colocador propiedad es el único allí para establecer el valor de un campo privado, no tiene efectos secundarios como devolver los códigos de resultado.
Si desea que la funcionalidad luego olvidarse la incubadora y escribir un nuevo método llamado TrySetProperty
o algo que trata de establecer la propiedad y devuelve un valor lógico.