Anonymous Function : asymmetric read/write behaviour

3 views (last 30 days)
I'm trying to use function handles to create an equivalent to a "with" statement in VBA or a alias in Python but I find myself facing a behaviour I don't understand. maybe some of you could help me understand why I get an error.
Boiled down to the simplest, here's what I get:
a=@(x)x{1};
y={10};
a(y)
ans = 10
try a(y)=100
catch ME
ME
end
ME =
MException with properties: identifier: 'MATLAB:matrix:unableToUseTypeAsIndex' message: 'Unable to use a value of type cell as an index.' cause: {} stack: [3×1 struct] Correction: []
The reading part works well but the next line results in an error. Why is there an asymmetry while evaluating the parentasis?
EDIT :
The most efficient to create a VBA:with or Python:alias equivalent in Matlab I found is to do an actual copy of a structure subpart, make modifications and reassign the edited branch copy to its original structure as:
S=struct();
S.Branch0 = "Just Some Data";
S.Branch1=struct();
for i=1:10
% Setting up preexisting values in the structure
for j=1:10
S.Branch1(i).NotCopiedProperty{j} = i;
end
S.Branch1(i).CopiedProperty = 10:-1:1;
% Create a phantom copy of the whole branch
with = S.Branch1;
% Add properties to the phantom branch
with(i).NewProperty1='Some Text';
with(i).NewProperty2={'A1','A2'};
% Create a copy of the original data and the edit it
with(i).CopiedProperty(i) = 0;
% Overwrite the original subBranch with the phantom branch
S.Branch1=with;
end
disp(S)
Branch0: "Just Some Data" Branch1: [1×10 struct]
disp(S.Branch1)
1×10 struct array with fields: NotCopiedProperty CopiedProperty NewProperty1 NewProperty2
Limitations : If new fields are to be added in a loop, the "with" structure must capture all instances at looping level.
% DOES NOT WORK
with = S.Branch1(1); % Points to ELEMENT
with.NewProperty1='New Text';
S.Branch1(1)=with;
% DO INSTEAD :
with = S.Branch1; % Points to ARRAY
with(i).NewProperty1='New Text';
S.Branch1=with;
% STILL WORKS
with = S.Branch1(1);
with.ExistingProperty1='Replacement Text';
S.Branch1(1)=with;
  2 Comments
Steven Lord
Steven Lord on 8 Nov 2023
What exactly are you hoping to do with that last line? If a(y) returned 10 on both sides, what would you expect this command to do in MATLAB?
10 = 100
Walter Roberson
Walter Roberson on 8 Nov 2023
They are trying to create an alias. So they would like a(y) to be an alias for y{1} including for assignment purposes. They would like a(y)=100 to act the same as y{1} = 100

Sign in to comment.

Accepted Answer

Walter Roberson
Walter Roberson on 8 Nov 2023
a(1) = @(x)x{1}
a = function_handle with value:
@(x)x{1}
a(1) = @(x)x{1}.^2 + 3
a = function_handle with value:
@(x)x{1}.^2+3
a
a = function_handle with value:
@(x)x{1}.^2+3
When an anonymous function appears on the left of an = then it is a request to modify the anonymous function. If the anonymous function already exists then the request will fail unless the subscript is one of 1 or true or false or []
If you want to be able to use a syntax like a(y)=100 to mean y{1}=100 then you would need to define a class to do the operations, and y would have to be a handle class
There is no simple "syntactic sugar" in MATLAB that can emulate with
  6 Comments
Steven Lord
Steven Lord on 10 Nov 2023
If you only extract the Parent property once (since you're not modifying it in your second loop) the times tell a different story:
%%Creating a structure
s=struct();
s.Parent.Property1=100000;
s.Parent.Property2=1:s.Parent.Property1;
%% Measuring ct with direct access (pointer like)
tic
for i=1:s.Parent.Property1
% this line writes zeros, to the array while requiring some calculation
% time
s.Parent.Property2(i)=abs(s.Parent.Property2(i))-i;
end
m.direct=seconds(toc);
%% Measuring ct creating a copy of the sub-structure for every calculation
% "with" statement inside the loop to evaluate the impact on a sample greater
% than 1
s.Parent.Property2=1:s.Parent.Property1;
tic
with=s.Parent;
for i=1:with.Property1
with.Property2(i)=abs(with.Property2(i))-i;
end
s.Parent=with;
m.with=seconds(toc);
disp(m);
direct: 0.075196 sec with: 0.022997 sec
More time also means a greater memory usage as there are 2 instances of the structure or object at any time in the loop using the "With" variation.
It's not that simple. MATLAB does something known as copy-on-write, in which it only makes copies of an array when it needs to.
tic
A = ones(1e4);
toc
Elapsed time is 0.256635 seconds.
tic
B = A;
toc
Elapsed time is 0.001599 seconds.
If the statement B = A; made a copy of A, it would have taken a similar amount of time as the line that created A. Instead, the copy's only made when B is modified.
tic
B(1) = 2;
toc
Elapsed time is 0.356562 seconds.
How does this work with struct arrays?
tic
S = struct('A', ones(1e4), 'C', 1);
toc
Elapsed time is 0.252987 seconds.
tic
T = S.C;
T(1) = 2;
toc
Elapsed time is 0.002666 seconds.
tic
S.C = T;
toc
Elapsed time is 0.001336 seconds.
The lines that create or manipulate T don't interact with S.A at all.
Benoit Beaulieu
Benoit Beaulieu on 11 Nov 2023
These are very interresting findings!
In my case, the idea is to iterate through an index that would be applied at the with definition level and modify the data. That said, with only modified parts of the substructure being actively copied only when they are being modified, the workaround may seem more efficient than I expected.
Thanks for the insight!
I foresee the possible useage of a "with" cells array pointing to various subpart in the structure, allowing for intricate "with". It has to be tested.

Sign in to comment.

More Answers (0)

Categories

Find more on Environment and Settings in Help Center and File Exchange

Products


Release

R2023b

Community Treasure Hunt

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

Start Hunting!