¿Cómo debo evitar la memorización que causa errores en Ruby?
¿Existe un consenso sobre cómo evitar la memorización que causa errores debido al estado mutable?
En este ejemplo, un resultado almacenado en caché tenía su estado mutado 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
Los enfoques que 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 agrega hilos.Verifique todo el código que usa el resultado degreeting
para asegurarse de que nada de eso mute la cadena.¿Existe consenso sobre el mejor enfoque? ¿Es la única desventaja de hacer (1) o (2) disminución del 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: comoFixnum
s son inmutables, calcular secuencias de Fibonacci no tiene problemas con el estado mutable. :)