¿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: comoFixnums son inmutables, calcular secuencias de Fibonacci no tiene problemas con el estado mutable. :)

Respuestas a la pregunta(2)

Su respuesta a la pregunta