¿Existe un consenso sobre cómo evitar que las memorias causen errores debido al estado mutable?¿Cómo debo evitar las causas de errores en Ruby?
En este ejemplo, un resultado almacenado en memoria caché ha mutado su estado, y por lo tanto dio el resultado incorrecto la segunda vez que se llamó.
class Greeter
def initialize
@greeting_cache = {}
end
def expensive_greeting_calculation(formality)
case formality
when :casual then "Hi"
when :formal then "Hello"
end
end
def greeting(formality)
unless @greeting_cache.has_key?(formality)
@greeting_cache[formality] = expensive_greeting_calculation(formality)
end
@greeting_cache[formality]
end
end
def memoization_mutator
greeter = Greeter.new
first_person = "Bob"
# Mildly contrived in this case,
# but you could encounter this in more complex scenarios
puts(greeter.greeting(:casual) << " " << first_person) # => Hi Bob
second_person = "Sue"
puts(greeter.greeting(:casual) << " " << second_person) # => Hi Bob Sue
end
memoization_mutator
Enfoques puedo ver para evitar esto son:
greeting
podría devolver undup
oclone
de@greeting_cache[formality]
greeting
podríafreeze
el resultado de@greeting_cache[formality]
. Eso provocaría una excepción cuandomemoization_mutator
le agregue cadenas.- Revise todo el código que usa el resultado de
greeting
para asegurarse de que ninguna parte mute de la cadena.
¿Existe un consenso sobre el mejor enfoque? ¿La única desventaja de hacer (1) o (2) disminuir el rendimiento? (También sospecho que congelar un objeto puede no funcionar completamente si tiene referencias a otros objetos)
Nota al margen: este problema no afecta la aplicación principal de la memorización: como Fixnum
s son inmutables, el cálculo de las secuencias de Fibonacci no tiene problemas con el estado mutable. :)
Un pequeño comentario sobre el estilo: puede simplificar el método de saludo con el operador || =. De esta manera: def saludo (formalidad); @greeting_cache [formalidad] || = expensive_greeting_calculation (formalidad); end – zaius
@zaius: Eso funciona en la mayoría de los escenarios, pero no funcionaría si 'nil' o' false' fueran un valor válido. –
Ah, cierto. Mi error. – zaius