Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When can I pass a literal : to a function?

Under what circumstances can I pass a literal : to a Matlab function? I have discovered through experimentation, that sometimes, a literal : is passed on as the string ':', but in other situations, an error is raised. For example:

>> type writeargs

function writeargs(varargin)

disp(varargin);

end

>> writeargs(:)
Undefined variable writeargs.

>> writeargs(:, 1)
Undefined variable writeargs.

>> writeargs(:, 1, :)
    ':'    [1]    ':'

>> writeargs(:, :, :)
    ':'    ':'    ':'

>> writeargs(1, 2, :, 4, 5)
    [1]    [2]    ':'    [4]    [5]

>> writeargs(1, 2, :, end)
Error using writeargs
Too many output arguments.

I have the impression that this syntax is permitted if at least three arguments are passed. That appears arbitrary. What is the legal syntax here?

Edit: A comment asked for a use-case. A use case may be whenever my arguments are going to be used as slices or indices. In Python code I've had cases where I passed slice-objects to a method. One use case is for a function such as inspired by this answer, where a small function is used to circumvent Matlabs inability to interpret magic(5)(3, :), and one could write a helper function and call it with paren(magic(5), 3, :).

like image 552
gerrit Avatar asked Mar 28 '13 15:03

gerrit


People also ask

Can a literal be passed as a method argument?

Is there any way to print the contents of the String literal pool? String literals passed as arguments are also String literals, so: yes.

How do you pass a string literal in C++?

If you want to pass the string literal "directly" (without constructing an std::string), the most common way is to pass the pointer to it. This code is also legal: const int& ten = 10; Is the compiler simply replacing the reference with the literal wherever it appears?

How do you pass a string value to a function?

To pass a string by value, the string pointer (the s field of the descriptor) is passed. When manipulating IDL strings: Called code should treat the information in the passed IDL_STRING descriptor and the string itself as read-only, and should not modify these values.

Can you free a string literal?

NO, you may not do that. You use free() only with memory that's been dynamically allocated with malloc( ), calloc(), or realloc( ). To clarify, string literals are not allocated on the stack, either.


2 Answers

You are not supposed to pass a literal : to a function. The colon's use for indexing only works on variables directly (see here and here). The colon is no real object and has no type. Were you supposed to use it as a function argument, it would need to be a typed object. Of course, it may be confusing that function calls and variable indexing have the same syntax. But if you ask for a legal syntax for using the colon as function argument, there is none.

That being said, it nevertheless works in some cases, as you observed. That's due to some preprocessing step MATLAB takes and only MathWorks has a handle on. It almost seems that MATLAB calls the function via subsref-like prepocessing when you give it three or more arguments (or two arguments, both being colons), but not when you give it less than that. Go figure. MathWorks will avoid giving out any decisive explanation for that. I suspect, MATLAB uses stringified colons internally after applying subsref, because that's what you see when you receive literal colons in your function, and indexing operations seems to work like that throughout. E.g. try >> m(3, ':');

My proposal for your use case is essentially this answer (also referenced in the comments to your question) but hides the indexing in a function named paren, as you suggested. Also, it uses default parenthesis syntax instead of calling subsref, but it's the same anyway. Use stringified colons!

function result = paren(variable, varargin)

    result = variable(varargin{:});

Then call something like:

>> paren(magic(5), 3, ':');

In summary, you should not count on using a literal : as function argument in MATLAB, even though it may work for special cases. Use a string colon ':'.

Side note

You can use subsref for calling functions:

>> subsref(@magic, substruct('()', {3}))

In this way you can chain function call and referencing:

>> subsref(subsref(@magic, substruct('()', {3})), substruct('()', {':'}))

But this really is just the same as using a temporary variable. The inner subsref is evaluated first, and its result passed as input argument into the outer subsref call.

Even with subsref's chaining mechanism, you can not force MATLAB to accept two succeeding pairs of parentheses, like magic(3)(:).

>> magic(3)(:)
??? Error: ()-indexing must appear last in an index expression.

>> subs(1) = substruct('()', {3});
>> subs(2) = substruct('()', {':'});
>> subsref(str2func('magic'), subs)
??? Error using ==> subsref
Only a dot field name can follow ()'s.
like image 73
Alex Avatar answered Nov 03 '22 10:11

Alex


writeargs(:) and writeargs(:,1) are treating writeargs as a locally scoped variable and trying to use the colon operator to index a "non existent" variable.

with more than three arguments the function is being called... sorry I don't understand why this behaviour exists, but I suspect it is implicitly calling subsref with one or two arguments, not with three or more.

you can test it by putting a breakpoint on the disp call in your function, you will see it is only hit when more than three arguments are given

like image 21
janh Avatar answered Nov 03 '22 09:11

janh