Clear Filters
Clear Filters

Using function handles with private properties and private methods

7 views (last 30 days)
Hello, everyone. I have been experimenting with the use of function handles on classes with private methods and/or have private properties. I have provided a simple example class below. I am currently using Matlab R2023a, but I also got the same results using Matlab R2019b.
classdef test % < handle
properties (Access = private)
this
that
testVar
end
properties (Access = private)
fn
end
methods (Access = public)
function obj = test( accessSwitch )
obj.this = 'This';
obj.that = 'That';
obj.testVar = 2;
if ( accessSwitch )
obj.fn = @obj.takeThat;
obj.testVar = 1;
obj.that = '123';
elseif (~accessSwitch)
obj.fn = @obj.considerThis;
obj.testVar = 2;
obj.this = '456';
else
error('not hitting the above cases');
end
end
function processTest(testObj)
testObj.fn();
end
end
methods (Access = private)
function takeThat( obj )
fprintf( '%s\n', obj.that );
end
function considerThis( obj )
fprintf( '%s\n', obj.this );
end
end
end
I tested this class with the accessSwitch set both to 0 and 1. I set a breakpoint in the debugger at the point where the "takeThat" or "considerThis" function is called. In both cases, the private properties are not updated. "testVar" remains as 2, even if the accessSwitch is 1. Additionally, the "that" and "this" properties are not modified to "123" or "456" either. It appears that when the function handle is defined, it saves the current values of the properties and does not account for further modifications of the properties.
Correct me if I am mistaken, but creating a function handle shouldn't restrict any further modifications to the values of the private properties, correct? I continued to experiment and noticed that creating the function handle after changing the property values instead results in "testVar" and "that" using "1" and "123" respectively when calling the "processTest" function (see code block below). This is the result I would have expected from the original implementation above.
if ( accessSwitch )
obj.testVar = 1;
obj.that = '123';
obj.fn = @obj.takeThat;
Is this importance of where you create your function handle intentional? If so, why?
Lastly, I am aware that uncommenting the section in the classdef line (i.e., making it a handle class) effectively prevents the problem. However, I would prefer not to define a handle class, as the ability to assign a handle object to multiple variables can be dangerous. I would like to mitigate this risk.
Thank you for your help.
.

Accepted Answer

Neha
Neha on 31 May 2023
Hi Austin,
I understand that you want to know if subsequent modifications to the object's properties affect the captured state stored in the function handle. Since the current state is captured when a function handle is created, changes in object properties are not reflected.
To address this issue, one approach is to use an anonymous function to create the function handle instead of directly capturing the object's method.
obj.fn = @(obj) obj.takeThat();
By using an anonymous function, the object "obj" is passed as an argument to the function handle, ensuring that it accesses the current state of the object's properties when called, rather than at the time of creation. The same can be implemented for the "considerThis" function.
Hope this helps!
  6 Comments
Eric Klingler
Eric Klingler on 1 Jun 2023
If I understand this correctly, there really is no such thing as a "simple" function handle. All function handles are treated as anonymous function handles with varargin as the argument. Is this detail mentioned in the documentation?
Thanks again for the clarification,
Eric
Walter Roberson
Walter Roberson on 1 Jun 2023
h1 = @sin
h1 = function_handle with value:
@sin
h2 = @(x) sin(x+0)
h2 = function_handle with value:
@(x)sin(x+0)
c = 0; h3 = @(x) sin(x+c)
h3 = function_handle with value:
@(x)sin(x+c)
info1 = functions(h1)
info1 = struct with fields:
function: 'sin' type: 'simple' file: ''
Notice the 'type', 'simple'
info2 = functions(h2)
info2 = struct with fields:
function: '@(x)sin(x+0)' type: 'anonymous' file: '/tmp/Editor_xjbdm/LiveEditorEvaluationHelperEeditorId.m' workspace: {[1×1 struct]} within_file_path: ''
info2.workspace{1}
ans = struct with no fields.
this anonymous function has no captured variables
info3 = functions(h3)
info3 = struct with fields:
function: '@(x)sin(x+c)' type: 'anonymous' file: '/tmp/Editor_xjbdm/LiveEditorEvaluationHelperEeditorId.m' workspace: {[1×1 struct]} within_file_path: ''
info3.workspace{1}
ans = struct with fields:
c: 0
This anonymous function has captured variable 'c'

Sign in to comment.

More Answers (0)

Categories

Find more on Graphics Object Programming in Help Center and File Exchange

Products


Release

R2023a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!