Unexpected result using cellfun with 'size' as first argument on string array

1 view (last 30 days)
The title of the topic says it all, but here is the result I would not expected.
Is this behaviour intended? or is it a bug?
s=["1"; "2"; "3"]
s = 3×1 string array
"1" "2" "3"
size(s,1)
ans = 3
cellfun(@(s) size(s,1), {s}) % correct
ans = 3
cellfun('size', {s}, 1) % this returns 1, that is not as I expected (not correct), 3 is correct answer
ans = 1
  4 Comments
Matt J
Matt J on 21 Oct 2023
I had forgotten that one could even call cellfun with this syntax!
For good reason. It doesn't appear to be documented.
Bruno Luong
Bruno Luong on 21 Oct 2023
Edited: Bruno Luong on 21 Oct 2023
Yes it is documented:
"Backward Compatibility
You can specify func as a character vector or string scalar, rather than a function handle, but only for a limited set of function names. func can be: 'isempty', 'islogical', 'isreal', 'length', 'ndims', 'prodofsize', 'size', or 'isclass'.
If you specify a function name rather than a function handle:
  • cellfun does not call any overloaded versions of the function.
  • The size and isclass functions require additional inputs to the cellfun function:A = cellfun('size',C,k) returns the size along the kth dimension of each element of C.A = cellfun('isclass',C,classname) returns logical 1 (true) for each element of C that matches the classname argument. This syntax returns logical 0 (false) for objects that are a subclass of classname."

Sign in to comment.

Answers (1)

Steven Lord
Steven Lord on 21 Oct 2023
Not a bug.
On the documentation page for the cellfun function, in the description of the func input argument, there is a section titled "Backward Compatibility". The relevant parts of that section: "If you specify a function name rather than a function handle:
  • cellfun does not call any overloaded versions of the function.
  • The size and isclass functions require additional inputs to the cellfun function"
Essentially, in that case cellfun will call the built-in size function rather than the string class's overload.
s=["1"; "2"; "3"]
s = 3×1 string array
"1" "2" "3"
which size(s) % string overload
size is a built-in method % string method
which size({s}) % built-in function
built-in (/MATLAB/toolbox/matlab/elmat/size)
cellfun(@size, {s}, 'UniformOutput', false) % calls string overload
ans = 1×1 cell array
{[3 1]}
cellfun('size', {s}, 1) % calls built-in
ans = 1
builtin('size', s)
ans = 1×2
1 1
Internally, a string array is a scalar object. It just tells MATLAB (via its size overload) that it has the size of its contents.
This is why I don't recommend calling cellfun (or arrayfun or structfun) with the name of the function to be applied. Use a function handle (could be anonymous) instead.
  1 Comment
Bruno Luong
Bruno Luong on 21 Oct 2023
How many people would know string class overloads size? string is after all stock function and users should not question how it was built.
I'm not convinced the cellfun doc states that clearly the string exception.
Those specific "backward compatible" specific implemented functions for cellfun still have speed advantage over anonymous functions, when it works (on non-string arrays). I rather recommend not use STRING instead. :)

Sign in to comment.

Categories

Find more on Matrices and Arrays 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!