Add listener programmatically for each object method
이전 댓글 표시
Hello there!
I have the following situation: Let's say I have a class:
classdef Memoizer < handle & matlab.mixin.Heterogeneous
methods
function obj = Memoizer()
... constructor code
end
function val = veryExpensiveMethod(obj, argsAsObj)
... some very time consuming code
end
function val = calledByListener(obj, methodName, argsAsObj)
... some code to check if method was called before and there are results cached
fcn_handle = str2func(methodName);
val = fcn_handle(argsAsObj);
end
end
end
Is it possible to add a listener to the specific method veryExpensiveMethod, where the listener will have access to the input argument argsAsObj of the method and is called automatically, without using notify()? The callback should be calledByListener. Essentially, the idea would be, that I can implement the method veryExpensiveMethod without thinking about firing events, but each call to the method will automatically fire such an event, and consequently call calledByListener.
I saw that you can add listeners to object properties (preGet, postGet, preSet, postSet) - which is essentially what I need, but I need it for a method call - e.g., preCalled.
In the example it is important that the class inherits from Heterogeneous. This is crucial, thus I cannot use RedefineDot operations in order to trigger events, which is not compatible with Heterogeneous. Anyways, dumping the Heterogeneous from the class definition would not solve the problem entirely, since RedefineDot is only triggered when object methods are called publicly (from the outside), but not if one method calls another method inside the object. In addition, RedefineDot does not have access to the method call's input arguments.
So, is it possible to have automatic/programmatic listener creation based on a method name, that creates a preCalled listener for a method? I can use the call stack, if that helps.
EDIT:
I forgot to add the object's reference as first input to all the methods. This, unfortunately, changes the requirements. The input argument argsAsObj is supposed to reflect the fact, that veryExpensiveMethod can be considered as a method whos entirety of input values can be passed as an object.
Best regards and thanks a lot in advance!
TE
댓글 수: 8
Steven Lord
2024년 4월 30일
So what exactly would you hope this listener could do for your method?
If you want to avoid performing the expensive calculations repeatedly for the same set of inputs, consider storing a memoize object to a helper function in one of your object's properties. Have your expensive method call the memoize object. This will call the helper function if the inputs are not in the memoize object's cache or return the cached answer if it is.
Thomas Ewald
2024년 5월 1일
My initial thought was that I can create a <hidden> mechanic in a class file, that automatically caches results of any class method that is called.
No, there is no such attribute.
veryExpensiveMethod would in fact be a method of a class that would inherit from Memoizer, so that the listener, and the mechnic, would be part of that child class.
No. memoize is a function that accepts a function handle and returns an object that can be used to cache inputs to and outputs from that function handle. Here's an example of its use:
M = memoize(@expensiveFunction);
tic; M(5), toc % Call the function, takes a long time due to the pause() call
tic; M(6), toc % Call the function, takes a long time due to the pause() call
tic; M(5), toc % Use cached results -- much quicker, no pause()
If we clear the cache, M(5) goes back to calling the function (with its pause call, to simulate an expensive computation) again.
clearCache(M);
tic; M(5), toc % No result for M(5) in the cache, calls pause()
You could use this by creating M in the constructor using a handle to the "payload" function (whatever actually performs the computations that take a long time) and storing it in a property of your object. Your expensive function would then call its payload function via this property rather than calling it directly.
function y = expensiveFunction(x)
y = x.^2;
pause(2)
end
Catalytic
2024년 5월 2일
What exactly is the value in avoiding notify? Even if class methods did innately raise PreCall events, as you desire, the number of lines of code that it would add to your classdef file to listen for them would be the same as inserting calls to notify.
Thomas Ewald
2024년 5월 2일
편집: Thomas Ewald
2024년 5월 2일
Thomas Ewald
2024년 5월 2일
Steven Lord
2024년 5월 2일
From this statement on the documentation page, I believe it will call isequaln to determine if the inputs are the same as a cached set of inputs but I'm not 100% certain.
"The input arguments are numerically equal to cached inputs. When comparing input values, MATLAB treats NaNs as equal."
I recommend contacting Technical Support to ask this question (and asking that they file an enhancement request for the documentation to describe how determining when to use the cache is handled when one of the inputs is an object.)
Thomas Ewald
2024년 5월 2일
채택된 답변
추가 답변 (0개)
카테고리
도움말 센터 및 File Exchange에서 Performance and Memory에 대해 자세히 알아보기
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!