Can Same Commands in Debugger and Command Window Exhibit Different Behavior?

I was debugging what I'm pretty sure is a bug (or at least an inconsistency) in @doc:subs and came across a behavior that I don't understand. I see a different result in the debugger than in the command window for what looks like the exact same sequence of commands. Everything below is copy/paste from the Matlab window w/ annotations added here. If it matters, the sequence in the debugger was executed while in ...\symbolic\@sym\subs.m
First, in the debugger:
Get roots of polynomial
K>> r = roots([1,1,1]);
Concatenate into a row
K>> X=[r(1),r(2)];
Check the class and size of X
K>> {class(X),size(X)}
ans =
1×2 cell array
{'double'} {[1 2]}
Convert to sym
K>> foo = sym(X);
Check which constructor is called.
K>> which sym(X)
C:\Program Files\MATLAB\R2024a\toolbox\symbolic\symbolic\@sym\sym.m % sym constructor
Check class and size of foo.
K>> {class(foo),size(foo)}
ans =
1×2 cell array
{'sym'} {[1 2]}
Apparently foo is (an ordinary?) 1x2 sym (I went back afterwards and verified that numel(foo) == 2).
So why does foo(1) return the entire array?
K>> foo(1)
ans =
[(3^(1/2)*1i)/2 - 1/2, - (3^(1/2)*1i)/2 - 1/2]
And foo(2) results in error?
K>> foo(2)
Index exceeds the number of array elements. Index must not exceed 1.
Quit debugger
K>> dbquit
Repeat sequence in command window
>> r = roots([1,1,1]);
>> X=[r(1),r(2)];
>> {class(X),size(X)}
ans =
1×2 cell array
{'double'} {[1 2]}
>> foo = sym(X);
>> which sym(X)
C:\Program Files\MATLAB\R2024a\toolbox\symbolic\symbolic\@sym\sym.m % sym constructor
Note that exact same constructor is called as above from the debugger.
>> {class(foo),size(foo)}
ans =
1×2 cell array
{'sym'} {[1 2]}
Here we get the expected indexing behavior.
>> foo(1)
ans =
(3^(1/2)*1i)/2 - 1/2
>> foo(2)
ans =
- (3^(1/2)*1i)/2 - 1/2
>>
What's different between command window and debugger?
Can anyone replicate (or not) this behavior in a more recent release than 2024a?

2 Comments

r = roots([1,1,1]).'
r =
-0.5000 + 0.8660i -0.5000 - 0.8660i
size(r)
ans = 1×2
1 2
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
foo = sym(r);
size(foo)
ans = 1×2
1 2
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
foo(1), foo(2)
ans = 
ans = 
Confirms same behavior at command window in R2026a; don't have Symbolic TB to check in debugger and haven't yet moved beyond R2024b, either, anyway.
The examples before are possibly just a tad confusing in looking at the results if don't keep straight that the ans variable is the combination of the class and size calls into one cell array, but that's pretty-much immaterial to the conclusion.
Why the debugger acts differently is probably a Q? for MathWorks support, doubt can answer without more access to the internals.
I'll probably open a support case. Just want to make sure that I'm not doing/interpreting something crazy before I do. Also hoping a kind soul with a later version can either confirm or refute the behavior observed in 2024a before involing Tech Support.

Sign in to comment.

 Accepted Answer

Matt J
Matt J on 6 Sep 2026 at 21:34
Edited: Matt J on 6 Sep 2026 at 21:49
I suspect the only reason size() reports that foo is 1x2 in the first place is because size() is overloaded by class sym to do so. In fact, foo is just a 1x1 scalar object masquerading as a vector.
Addiitionally, overloaded subsref methods are not active within the class folder. Hence, when you execute commands in debug mode, from within the @sym folder, the indexing operation foo(2) is processed using builtin subsref, which sees foo as the scalar object it truly is, not a 1x2 vector.

5 Comments

Paul
Paul on 6 Sep 2026 at 21:48
Edited: Paul on 6 Sep 2026 at 21:56
Yes, in the debugger I am in @sym/.
Is there a way to definitively determine that foo is a scalar object masquerading as a vector?
More importantly, how does one get to the correct subsref in the debugger if in @sym?
If that's not possible, isn't it an impediment to debugging inside class @ folders?
If so, is there a way to determine that definitively?
Yes, you can call the built-in size or numel method:
r = roots([1,1,1]);
X=[r(1), r(2)];
foo = sym(X);
size(foo)
ans = 1×2
1 2
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
builtin('size',foo)
ans = 1×2
1 1
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
numel(foo)
ans = 2
builtin('numel',foo)
ans = 1
If that's not possible, isn't it an impediment to debugging inside class @ folders?
It has been seen by some users as an impediment, which I imagine is one motivation for introducing Modular Indexing in lieue of subsref.The legacy method of accessing subsref functionality inside the class definition is to call subsref() directly.
Hi Paul,
Thank you for your question. I'm glad to see that Matt was able to help you get the answer you were looking for.
I wanted to add that this is more of a quirk of legacy subsref/subsasgn, rather than a quirk with the debugger. If you were to insert the same expression as a diagnostic line of code in the sym constructor, you would get the same behavior. The legacy subsref and subsasgn overloads are only called for indexing syntax in expressions outside of the class.
As Matt points out, this is part of the reason that MathWorks suggests new classes use the newer Modular Indexing mixins to implement overloaded indexing. It is not intuitive that foo(1) should behave differently depending on which class executes the expression.
isn't it an impediment to debugging inside class @ folders?
On the other hand, if you are debugging code inside the class, there is an argument to be made that you want objects to behave the same in the debugger as when code is running normally in that same workspace, including the behavior of indexing operations.
If you want overloaded indexing to be operative inside a particular function, e.g.,
function y=func(obj,x)
y=x+obj(2); %overloaded indexing expression
end
then perhaps that function shouldn't be a method at all, and should reside outside the class. Doing so wouldn't prevent you from invoking the function via class method syntax,
y=obj.func(x)
You would just need to make sure dot-indexing was appropriately overloaded in your subsref/subsasgn methods appropriately.
As an aside, I once proposed a new method attribute to let the user decide whether builtin or overloaded indexing is operative inside particular methods, e.g.,
classdef myclass
methods (Indexing=builtin)
function y=func1(obj,x)
end
function y=func2(obj,x)
end
end
methods (Indexing=overloaded)
function y=func3(obj,x)
end
end
end
with the obvious restriction that subsref,subsasgn, and maybe also size and numel, must be inside a block with Indexing=builtin. I was told there are problems with that proposal, but the explanation was beyond my software engineering acumen.

Sign in to comment.

More Answers (0)

Products

Release

R2024a

Asked:

on 6 Sep 2026 at 17:56

Edited:

about 5 hours ago

Community Treasure Hunt

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

Start Hunting!