2011-02-10 9 views
9

Tengo una clase con algunas propiedades que son dependientes, pero que realmente me gustaría calcular solo una vez.MATLAB Lazy Evaluation en Dependent Property

Acabo de concluir que el uso de la evaluación diferida en una propiedad de clase dependiente en MATLAB es imposible o una mala idea. El plan original era tener una bandera lógica privada para cada propiedad (pública) que necesita actualización y que el constructor la establezca en verdadero. Luego, cuando se llama al descriptor de acceso a la propiedad, verifica ese indicador y calcula el valor y lo almacena (en otra propiedad privada) solo si es necesario. Si la bandera fuera falsa, simplemente devolvería una copia del valor en caché.

Creo que la dificultad radica en una restricción en el acceso a propiedades, es decir, que dejan otras propiedades no relacionadas por sí solas. En otras palabras, un método get.property (self) no puede cambiar el estado del objeto self. Curiosamente, esto falla silenciosamente en mi clase actual. (Es decir, ni el indicador de actualización ni los resultados del cálculo en caché se establecen en el método get. Por lo tanto, el cálculo costoso se ejecuta cada vez).

Mi sospecha es que cambiar la propiedad diferida de una propiedad dependiente pública a un método con GetAccess público, pero el SetAccess privado funcionaría. Sin embargo, no me gusta tener que parodiar la convención de propiedad de esta manera. Ojalá hubiera solo un atributo de propiedad "vago" que pudiera hacer todo esto por mí.

¿Me falta algo obvio? ¿Los métodos de acceso para las propiedades de clase dependientes en MATLAB tienen prohibido cambiar el estado de la instancia de la clase? Si es así, ¿definir lo que equivale a un descriptor con un efecto secundario privado es la forma menos dañina de obtener el comportamiento que deseo?

Editar: he aquí una clase de prueba ...

classdef LazyTest 
    properties(Access = public) 
    % num to take factorial of 
    factoriand 
    end 

    properties(Access = public, Dependent) 
    factorial 
    end 

    properties(Access = private) 
    % logical flag 
    do_update_factorial 
    % old result 
    cached_factorial 
    end 

    methods 
    function self = LazyTest(factoriand) 
     self.factoriand = factoriand; 
     self.do_update_factorial = true; 
    end 
    end 

    methods 
    function result = get.factorial(self) 
     if self.do_update_factorial 
     self.cached_factorial = factorial(self.factoriand); 
     % pretend this is expensive 
     pause(0.5) 
     self.do_update_factorial = false 
     end 
     result = self.cached_factorial; 
    end 
    end 
end 

Ejecutar con

close all; clear classes; clc 

t = LazyTest(3) 
t.factorial 

for num = 1:10 
    tic 
    t.factoriand = num 
    t.factorial 
    toc 
end 

Después de heredar de handle el tiempo disminuye considerablemente.

Respuesta

11

Supongo que está utilizando una clase de valor. Con un handle class (classdef myClass < handle), que se pasa por referencia, puede modificar fácilmente la clase desde dentro de un método get. Por ejemplo, uso lo que propones para cargar datos del archivo (si aún no está cargado) o de una propiedad privada y oculta.

Tenga en cuenta que utilizar una propiedad dependiente lazy de la manera que propone algo frustra el propósito de usar una propiedad dependiente, es decir, la garantía de que sus datos están siempre actualizados con el estado de las propiedades de las que se deriva. Cada vez que cambie las otras propiedades, su propiedad perezosa queda obsoleta.

Puede (debería) agregar un método de conjunto a todas las demás propiedades que establece que la propiedad privada se vacíe (isempty(obj.myPrivateProperty) es la "bandera lógica" que necesita saber si debe calcular). Pero si haces eso, ¿por qué no simplemente haces que los métodos establecidos llamen a algún método de actualización que actualice/recalcule todas las propiedades "dependientes" de inmediato?

+0

Eso parece ser el truco. –

+1

También me gusta la reducción en el desorden de usar isempty en el que me importa frente a las propiedades privadas adicionales. Gracias. –

+1

1. No puede reemplazar una bandera explícita con una implícita basada en el valor sin hacer una suposición (aquí, los valores vacíos no son válidos aquí). 2. Puede que no siempre sea apropiado tener métodos establecidos para actualizar la propiedad "dependiente", esp. si el último es costoso de calcular y depende de dos o más propiedades. Por lo tanto, en el caso general, seguiría con banderas adicionales. – user1735003