Est-il possible d'avoir class.property = x retourner autre chose que x?
-
22-08-2019 - |
Question
Disons que j'ai une classe 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 j'essaie de faire MyClass.property=x
, la valeur de retour de la déclaration dans son ensemble est toujours x. Il est une convention dans beaucoup de langues C-base / inspiré pour retourner une valeur booléenne « succès » - est-il possible de le faire pour un poseur en utilisant la « syntaxe est égal à » Ruby
De plus - si cela est impossible, pourquoi pas? Y at-il concevable inconvénient de permettre une opération « égale setter » retourne une valeur?
La solution
Un inconvénient est que vous briser la sémantique d'affectation enchaînées:
$ 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>
Considérez:
x = MyClass.property = 3
Alors x
prendrait true
si cela a fonctionné comme vous l'aviez prévu (droit associativité). Cela pourrait être une surprise pour les personnes utilisant l'interface et utilisée pour la sémantique typique.
Vous avez aussi m'a fait penser à l'affectation parallèle, par exemple:
x, y = 1, 2
Apparemment, la valeur de retour de cette expression est mise en œuvre spécifique ... Je suppose que je ne seront pas enchaînant des missions parallèles:)
Nice question!
Autres conseils
Comme le dit Martin, cela casserait Enchaînement d'affectation.
La façon dont les méthodes d'affectation rubis sont définis au travail se développe MyClass.property = 3
à l'équivalent de (lambda { |v| MyClass.send('property=', v); v })[3]
(pas vraiment, mais cela montre comment enchaînant les travaux). La valeur de retour de la mission est toujours la valeur attribuée.
Si vous voulez voir le résultat de votre méthode de MyClass#property=
, puis utilisez #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
Cependant, la manière rubis de le faire est avec des exceptions - en cas de problème au cours la mission, soulever une exception. Ensuite, tous les invocateurs doivent manipuler si quelque chose va mal, à la différence d'une valeur de retour, qui peut être facilement ignoré:
# 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
Je ne suis pas un expert Ruby mais je dirais que non pour ce cas, j'ai peur. Un poseur de propriété est uniquement là pour définir la valeur d'un champ privé, de ne pas avoir des effets secondaires tels que des codes de résultat retour.
Si vous voulez que la fonctionnalité puis oublier le poseur et d'écrire une nouvelle méthode appelée TrySetProperty
ou quelque chose qui tente de définir la propriété et renvoie une valeur booléenne.