Is the Order of Function Evaluation Guaranteed when Function Outputs are Concatenated into an an Array?

11 views (last 30 days)
Suppose I call two functions within concatenation into an array
A = [ones(1,2),zeros(1,2)]
A = 1×4
1 1 0 0
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
In this case, the order in which ones and zeros are evaluated doesn't matter as far as the result is concerned.
But what about when there is dependence between the two (or more) functions whose outputs are being concatenated:
A = [figure,plot(1:3)]
A =
1×2 graphics array: Figure Line
Is there any guarantee that the call to figure is evaluated and the figure created before the call to plot so that the plotted result is in the newly created figure?
Does the answer change if creating a cell array?
A= {figure,plot(rand(2))}
A = 1×2 cell array
{1×1 Figure} {2×1 Line}

Accepted Answer

Walter Roberson
Walter Roberson on 10 Jan 2026
The order is guaranteed to be "as-if" it were left to right,
It appears that values are stored temporarily for processing according to order of operations
A(1)^-A(2)^-A(3)^-1
function called 1 times with parameter 1 function called 2 times with parameter 2 function called 3 times with parameter 3
ans = 1.0086
Notice the function calls are reported in left to right order.
But
2^-3^-4^-1
ans = 1.0086
(2^-3)^-4^-1
ans = 2.4414e-04
2^-(3^-4)^-1
ans = 1.0086
This illustrates that the ^- operator,
"Although most operators work from left to right, the operators (^-), (.^-), (^+), (.^+), (^~), and (.^~) work from second from the right to left. "
if the order of operations was strictly left to right then the output value would be the 2.4414e-04 of (2^-3)^-4^-1, but instead it is in line with 2^-(3^-4)^-1 indicating that indeed chains of ^- proceed from second to the right. But since the order of function calls was not parameter 2 followed by parameter 3 followed by parameter 1, it followed that the calls took place left to right and the intermediate values were buffered.
2^(-3^-4)^-1
ans = 1.0086
2^-3^-(4^-1)
ans = 1.6818
((2^-3)^-4)^-1
ans = 2.4414e-04
function ret = A(in)
global order
if isempty(order); order = 0; end
order = order + 1;
fprintf("function called %d times with parameter %g\n", order, in);
ret = in+1;
end
  12 Comments
Paul
Paul on 10 Jan 2026
BTW, this thread and threads linked therefrom may be of interest to anyone interested in the mess between the implementation and the documentation of how expressions involving "power operators" (quotes because that thread indicates that what the doc identifies as a single "operator" might in some cases actually be treated as two operators, IIRC) are evaluated, at least back in 2024a. Don't know if doc or implementation has changed since then, but I doubt it on both.
Matt J
Matt J on 10 Jan 2026
Edited: Matt J on 10 Jan 2026
OK, disregard my last comment. Here's what I was really trying to show. In the version below, the two computations of A are now equivalent, but f(1) is used last in both cases:
f=@(x) rand(512,512,512);
%Single statement
A=f(1).^(f(2).^f(3));
clear A
%Multi-statement
tmp=f(2).^f(3);
A=f(1).^tmp;
clear tmp; clear A
The Task Manager profile shows that the single statement version consumes more memory, because it buffers f(1) unnecessarily. In the multi-statement version, no buffering is required. In other words, the left-to-right rule makes it so that you are obliged to break up expressions, if you want to optimize memory.

Sign in to comment.

More Answers (1)

Matt J
Matt J on 9 Jan 2026
Edited: Matt J on 10 Jan 2026
This reasoning might not be bulletproof, but I think the order of funtion calls in any expression has to always go left to right due to rules of precedence. In other words, in an expression like this,
ans = funcA()+funcB()+funcC()
we know that the first addition on the right hand side has to be evaluated first, and therefore funcA() and funcB() have to be available for that. There are ways you can satisfy rules of precedence with the funcx() evaluated in an arbitrary order, but only by temporarily storing all three funcx() outputs simultaneously. But I just don't think they would do that. Programmers want to be able to count on the result of funcA()+funcB() being transient, so that they can predict peak RAM consumption. Tempory caching of all function calls would upset that, especially if the outputs of the funcx() happen to be large arrays.
In addition, there is the test below. No matter how many times I run, I cannot generate an occurence of non-consecutive evaluations.
h=subtest;
f=@() issorted(cell2mat({h(),h(),h(),h(),h(),h(),h(),h(),h(),h(),h(),h(),h()}));
N=2e4;
isConsecutive=false(N,1);
for i=1:N
isConsecutive(i)=f();
end
tf=all(isConsecutive) %Check if result was conseuctive in all cases
tf = logical
1
function h=subtest
i=0;
h=@increment;
function j=increment()
i=i+1;
j=i;
end
end
  1 Comment
Paul
Paul on 10 Jan 2026
I don't understand how the funcA()+funcB()+funcC() example relates to matrix construction.
I confess to not fully understanding how that code works, but I get what it shows.
If I had to guess, I'd guess that the matrix ( [] or {} )elements are constructed in linear index order. OTOH, maybe a smart interpreter could do some things in parallel (like the [eig,svd] example) and not guarantee anything about order (much like how cellfun et. al. explicitly say to not assume the order in which the outputs are computed). Unfortunately, I can't find anything in the doc on this question.

Sign in to comment.

Products


Release

R2025b

Community Treasure Hunt

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

Start Hunting!