nargin on matlab class method returns -1 - matlab

I have the following scenario. In myClass.m I have defined
classdef myClass
...
methods
function y = foo(this, x)
...
end
end
end
Then I execute
obj = myClass();
nargin(#obj.foo)
and get as a result -1 while I would expect 1. The function nonetheless accepts only one argument.
I actually want to pass the handle to another function (in which I don't have access) which checks the number of arguments and I want the check nargin(f)==1 to succeed. Is there a way to do that?
PS
I know that if I define the method as static I will get the correct result by calling nargin(#(x)Test.foo) but the method accesses class variables.

Even though this question got answered and accepted, I think it is worth to show a working approach, which works even without creating an instance of the class. Reference to metaclass: https://ch.mathworks.com/help/matlab/ref/metaclass.html
metaClass = ?myClass
numArgIn = zeros(length(metaClass.MethodList), 1);
names = strings(length(metaClass.MethodList), 1);
for i=1:length(metaClass.MethodList)
names(i) = string(metaClass.MethodList(i).Name);
numArgIn(i) = numel(metaClass.MethodList(i).InputNames);
end
disp(numArgIn(names=="foo"))
When you create a folder with the class and some modules, you can use the following one-liner notation:
nargin('#myClass/foo.m')
In the latter example, the file ending can be removed without effect.

I can no longer verify the validity of this answer. See more recent answer(s) and comments.
Original answer
I fixed the problem by defining my own wrapper something like
function y = mywrapper(f, x)
%MYWRAPPER nargin(#(x)mywrapper(f, x)) is 1 as it should be
y = f(x);
end
I realised that nargin(#(x)#obj.foo), also does what I wanted

Related

Call a script with definitions in a function

We have a script that defines values to names similar to #define in c. For example:
script.m:
ERR_NOERROR = 0;
ERR_FATAL = 1;
This script already exists and is used for value replacement when reading data from files.
Now we have a function (or more) that does some analysis and we would like to use the same definition in this function to avoid magic numbers. But when the script is called from the function we get an error.
Attempt to add "ERR_NOERROR" to a static workspace.
See MATLAB Programming, Restrictions on Assigning to Variables for details.
And this does not help much in the understanding of the problem.
The question is how can we make these definitions visible/usable in the functions with having to copying it every time.
Example:
function foo = bar(a)
run(script.m) %also tried running it without the run command
if a == ERR_NOERROR
foo = 5;
else
foo = 6;
end
end
edit:
There was a nested function,below in the function which I was not aware of. This explains the problem.
This kind of scoping error happens when you use nested or anonymous function within a function. The solution is well documented.
To your case, you can avoid nested function, or "Convert the script to a function and pass the variable using arguments", as the documentation suggests.
EDIT: I should have made it clear that the error occurs even if the script is not called within the nested function. Similar scenario is that, in debug mode (by setting up a break point), it will be an error if one tries to create a temporal variable to test something.
This is not a direct answer, rather a recommendation to switch to another method, which will not be mixing scope and workspace.
Instead of defining your constant in a script, you could make a class containing only constant properties. ex: code for error_codes.m:
classdef error_codes
% ---------------------------------------------------------------------
% Constant error code definition
% ---------------------------------------------------------------------
properties (Constant = true)
noerror = 0 ;
fatal = 1 ;
errorlvl2 = 2 ;
errorlvl3 = 3 ;
warning = -1 ;
% etc ...
end
end
I use this style for many different type of constants. For tidiness, I groups them all in a Matlab package directory (The directories which starts with a + character.
The added benefit of using constant class properties is the safety that the values cannot be changed in the middle of the code (your variables defined in a script could easily be overwritten by a careless user).
So assuming my file error_codes.m is placed in a folder:
\...somepath...\+Constants\error_codes.m
and of course the folder +Constants is on the MATLAB path, then to use it as in your example, instead of calling the script, just initialise an instance of the class, then use the constant values when you need them:
function foo = bar(a)
ERR = Constants.error_codes ;
if a == ERR.noerror
foo = 5;
else
foo = 6;
end
or it can works in switch statement too:
switch a
case ERR.noerror
foo = 5 ;
case ERR.warning
foo = 42 ;
case ERR.fatal
foo = [] ;
end

custom class calling function - too many input arguments

I'm learning about MATLAB classes they certainly seem different to what I'm used to. Below is an example class I'm using.
I initialise my class with the line below,
myClass = ClassTest(3);
This is fine. The issue I have is calling the RunMain function.
First call
myClass.RunMain(myClass)
I get the error message too many inputs.
Second call
myClass.RunMain(myClass, anything)
This call works. However, I find it strange I need to supply a second parameter which is never used - just seem messy. Sure I'm missing something here.
classdef ClassTest < handle
properties
myNum;
myDate = datenum(date);
end
methods
function ct = ClassTest(someNum)
ct.myNum = someNum;
end
% this function does not work when called
%function RunMain(obj)
% obj.myNum = obj.myNum * 2;
% disp(obj.myNum);
%end
% this works
function RunMain(obj, anything)
obj.myNum = obj.myNum * 2;
disp(obj.myNum);
end
end
Update
I can see when I debug that the anything parameter is exactly the same as obj even obj.myNum has changed value.
Correct syntax for calling a method where myClass is an object of the class defining the method RunMain is:
In case of function RunMain(obj) it is one of these:
myClass.RunMain()
RunMain(myClass)
In case of function RunMain(obj, anything) it is one of these:
myClass.RunMain(anything)
RunMain(myClass, anything)
You can find more details regarding syntax here:
http://de.mathworks.com/help/matlab/matlab_oop/ordinary-methods.html

MATLAB CLASSES getter and setters

I come from a Java background. I am having issues with classes in Matlab particularly getters and setters. getting a message saying conflict between handle and value class I'm a little lost with what to do so any help for lack of a better word will be helpful.
classdef Person
properties(Access = private)
name;
age;
end
methods
% class constructor
function obj = Person(age,name)
obj.age = age;
obj.name = name;
end
%getters
function name = get.name(obj)
end
function age = get.age(obj)
end
%setters
function value = set.name(obj,name)
end
function value = set.age(obj,age)
end
end
end
Implementation
Since your class is currently a subclass of the default Value class, your setters need to return the modified object:
function obj = set.name(obj,name)
end
function obj = set.age(obj,age)
end
From the documention: "If you pass [a value class] to a function, the function must return the modified object." And in particular: "In value classes, methods ... that modify the object must return a modified object to copy over the existing object variable".
Handle classes (classdef Person < handle) do not need to return the modified object (like returning void):
function [] = set.name(obj,name)
end
function [] = set.age(obj,age)
end
Value vs. Handle
Going a bit deeper, the difference between a Value class and a Handle class lies mostly in assignment:
Assigning a Value class instance to a variable creates a copy of that class.
Assigning a Handle class instance to a variable create a reference (alias) to that instance.
The Mathworks has a good rundown on this topic.
To paraphrase their illustration, the behavior of a Value class is
% p is an instance of Polynomial
p = Polynomial();
% p2 is also an instance of Polynomial with p's state at assignment
p2 = p;
and of a Handle class is
% db is an instance of Database
db = Database();
% db2 is a reference to the db instance
db2 = db;
Quick'n Dirty from the Java perspective:
- "handle" classes are what your mind is set to. proper object instances with pointers to them. use them.
- "value" classes are always returning a full clone of whatever object (which has been modified by what you just did, e.g. setting a name).
the reason they have both in Matlab is that in Matlab you would expect the "value" behaviour natively. Imagine you have a matrix A = [1 2; 3 4], then assign that via B = A. if you now set B(1) = -1 you'd hope that A(1) is still 1, right? this is because matlab keeps track of "copies" and truly creates them as you modify different variables initially set to the same matrix. in OOP you'd have A(1)=-1 now as everythings an object reference.
furthermore, "native" matlab routines dont have a "this/self/me" variable that contains the instance reference to access from within functions. instead, the convention is that the class instance will be prepended to the function's argument list.
so for a function call myclass.mymethod(arg1,arg1), the declaration must be
function mymethod(this, arg1, arg2)
% Note that the name you choose for "this" is arbitrary!
end
mind you, this is the java-perspective (and also my favourite one), the above function call is equivalent to mymethod(myclass,arg1,arg1). this is more native to matlab-style, but somehow makes it harder to see you're calling an objects method.
now, regarding setters/getters: for handle classes, everything feels java-ish now:
classdef MyClass < handle
properties
MyProp;
end
methods
function set.MyProp(this, value) %Note: setMyProp is also valid!
... % do checks etc, trigger calls,
this.MyProp = value;
end
function value = get.MyProp(this)
... % notify, update, triggers etc
value = this.MyProp;
end
end
Of course it goes without saying that you dont need to define a getter if you just want to return the value, i.e. myclassinstance.MyProp will work without any just as well.
Finally, getters/setters for value classes are something that [never encountered me/i never needed] in my 7 years of matlab oop, so my advise would be to go with handle classes and enjoy happy matlab coding :-)
otherwise, the above explanation & official matlab docs is doing the job for value class getter/setters.

Is it possible in one line to get a class value from a function and modify it?

If I have a class
classdef foo
properties
a = 0;
end
methods
function obj foo(obj)
obj.a = 5;
end
end
end
And a function
function result = GetFoo()
result = foo();
end
At the command interpreter:
>> x = GetFoo()
x =
foo
Properties:
a: 5
Methods
>> x.a = 10
x =
foo
Properties:
a: 10
Methods
this yields an instance of foo and the value 'a' can be assigned. However, doing the same in one step:
>> GetFoo().a = 10
GetFoo =
a: [1x1 struct]
This creates a new structure called GetFoo that overrides the class and gives it a member called 'a'. Rather than the code getting the result of GetFoo() (the class instance) and settings its property 'a' = 10, it does this instead. I can see that it is likely a hangover from the ability to create weakly typed structures on the fly and the code having to be backward compatible It also seems to be related to the fact that MATLAB has no concept of a pointer so every input/output argument is a deep copy and that the above even if it would work would be setting the value of a copy of the value GetFoo() is using to source its return object, then throwing it away.
Nonetheless the goal really is to be able to do all the work I need without creating and requiring to clear temporary variables. The intent is code maintainability as much as cosmetic style.
You're mixing together quite a few different issues/complaints in your question, but I suspect what you're looking for is a handle class. Inherit your class from handle (i.e. write classdef foo < handle, and your class will have what is basically pass-by-reference behavior. You're right that MATLAB doesn't use pointers, but with handle classes it does have references.
Separately, it's not possible in MATLAB to index in to the output of a function (i.e. to write GetFoo.a or GetFoo().a - you do need a temporary variable for that, whether or not it returns a value or handle class.
Note that in your example above, the result of the GetFoo().a = 10 is not an instance of foo with the property a equal to 10 - it is a structure with a field a equal to 10. Type class(GetFoo), and you'll see it's a struct, not a foo.
This is really ugly, but is just to raise the glove that was thrown about doing it in one line. :-)
First of all, I'll modify a bit the class so you'll see that the constructor is called:
classdef foo
properties
a = 0;
end;
methods
function obj = foo()
obj.a = 5;
display('foo!');
end;
end;
end
And the one-liner, ran in Command Window:
>> subsasgn(GetFoo(), struct('type', '.', 'subs', 'a'), 10);
foo!

When can I pass a function handle?

I have a function for cached evaluation. As one of the arguments, it takes a function handle. Under some circumstances, the function handle is unaccessible, and I don't quite understand why. The example below shows what got me stumped:
>> A.a = #plus; feval(#A.a, 1, 1)
ans =
2
>> clear A
>> A.a.a = #plus; feval(#A.a.a, 1, 1)
Error using feval
Undefined function 'A.a.a' for input arguments of type 'double'.
So, if I have a function handle stored as a structure member, I can pass it along fine if it's one level deep, but not if it's two levels deep. In my real use case, I have a structure D that holds many (117) instances of various classes, so I actually have stct.obj.meth, where stct is a structure, obj is a class instance/object, and meth is a method. Passing #stct.obj.meth fails, but if I assign A = stct.obj, then passing #A.meth succeeds.
Under what conditions can I pass a function handle as an argument, so that it's still accessible down the stack?
Edit: Although in the use case above, I could simply remove the # because #plus is already a function handle. However, consider the situation here:
>> type cltest.m
classdef cltest < handle
methods
function C = mymeth(self, a, b)
C = a + b;
end
end
end
>> A.a = cltest();
>> feval(#A.a.mymeth, 1, 1)
Error using feval
Undefined function 'A.a.mymeth' for input arguments of type 'double'.
>> b = A.a;
>> feval(#b.mymeth, 1, 1)
ans =
2
In this case, I need the # before A.a.mymeth...
Introducing classes was a big deal for MATLAB. So big, in fact, that they still do not work properly today. Your example shows that structure access and class method access conflict, because they had to overload the the meaning of dot '.' and didn't get it to work seamlessly. It all more or less works fine when you are calling class methods explicitly by their name on the MATLAB console, e.g. in your example >> A.a.mymeth(1,1). But when you have any type of indirection, it soon breaks.
You tried getting the function handle by >> #A.a.mymeth, which MATLAB cannot make sense of, probably because it gets confused by the mixed structure/class thing. Trying to work around using str2func doesn't work either. It works, again, only for explicit name access, as shown here. It breaks for your example, e.g. >> str2func('b.mymeth'). It does not even work inside the class. Try other indirections and watch them fail.
Additionally, MATLAB does not like giving you a class method's handles. There's no function for it. There's no way to get all function handles in one go, or even dynamically by a name string.
I see three options here. First, try changing your program, if possible. Do these functions need to sit in a classdef?
Second, follow your or nispio's workaround. They both create a temporary variable to hold a reference to the class instance in order to create a non-mixed access to its member methods. The problem is, they both require explicitly naming the function. You have to explicitly put this code for every function involved. No way to abstract that out.
Third, cheat by giving out your class' method handles from the inside. You can give them out in a structure.
classdef cltest < handle
methods
function C = mymeth(self, a, b)
C = a + b;
end
function hs = funhandles(self)
hs = struct('mymeth', #self.mymeth, ...
'mymeth2', #self.mymeth2);
end
end
end
You can then access the handles by name, even dynamically.
>> A.a = cltest;
>> feval(A.a.funhandles.mymeth, 1, 1);
>> feval(A.a.funhandles.('mymeth'), 1, 1)
ans =
2
But be careful, by using this you can access Access=private methods from outside.
Try this:
feval(#(varargin)A.a.mymeth(varargin{:}),1,1);
It is a little kludgy, but it should work.
EDIT:
The way it works is by creating an Anonymous Function that takes a variable number of arguments, and dumps those arguments into the method A.a.mymeth(). So you are not actually passing a pointer to the function A.a.mymeth, you are passing a pointer to a function that calls A.a.mymeth.
An alternative way of achieving the same thing without using varargin would be:
feval(#(x,y)A.a.mymeth(x,y),1,1);
This creates an anonymous function that accepts two arguments, and passes them along to A.a.mymeth.
<speculation> I think that it must be inherent in the way that the unary function handle operator # works. The Matlab parser probably looks at #token and decides whether token is a valid function. In the case of a.mymeth it is smart enough to decide that mymeth is a member of a, and then return the appropriate handle. However, when it sees A.a.mymeth it may discover that A is not a class, nor does A have a member named a.mymeth and therefore no valid function is found. This seems to be supported by the fact that this works:
A.a.a = #plus; feval(A.a.a,1,1)
and this doesn't:
A.a.a = #plus; feval(#A.a.a,1,1)
</speculation>
You can get around it by introducing a separate function that corrects what # operator is not doing:
function h=g(f)
x = functions(f);
if ~strcmp(x.type, 'anonymous')
h = evalin('caller', ['#(varargin)' x.function '(varargin{:})']);
else
h = f;
end
end
Now for your example:
>> feval(g(#A.a.mymeth), 1, 1)
ans =
2
>> feval(g(#b.mymeth), 1, 1)
ans =
2
I think this will have the smallest impact on your code. You can make it a bit more elegant but less robust and/or readable. The uplus method is not defined for function_handle class so you can create uplus.m in folder #function_handle somewhere in your path with this content:
function h=uplus(f)
x = functions(f);
if ~strcmp(x.type, 'anonymous')
h = evalin('caller', ['#(varargin)' x.function '(varargin{:})']);
else
h = f;
end
end
Now you just need to use +# instead of #. For your examples:
>> feval(+#A.a.mymeth, 1, 1)
ans =
2
>> feval(+#b.mymeth, 1, 1)
ans =
2