I would like to know if it's possible to use a colon ":" as argument of a function.
Something like that:
function y=func(x)
if x is a colon
do this
else
do that
end
Also is it possible to pass the key work end as argument of a function, and also 1:end, 3:end-5, etc...
I doubt it's possible, but I would like to be sure.
Also, I get a weird error when I pass "1:end" as argument of a function, it produces no error, but inside the function, no argument is assigned (not even the other arguments). Do someone know what happens?
You can override both for your own classes:
classdef MyClass
properties(Access=public)
data
end
methods
function out = end(A,k,n)
disp(A);
disp(k);
disp(n);
out = [];
end
function B = subsref(A,S)
disp(S);
B = [];
end
end
end
As for functions, I never heard of such a functionality.
No, it's not possible to pass a colon as an argument (it doesn't make any sense).
Related
I am having some trouble with matlab. I am working with b-splines. Sometimes I want to work with the actual spline, while other times I only want to use the so-called basis functions. Without diving into the theory of b-splines, the practical difference is that the when I want to work with the b-spline, I need an extra method and property. I want this property to be initialized by passing it in the constructor.
What I have so far (with most irrelevant methods and properties removed) hopefully roughly demonstrates the behavior that I want:
bsplinespace.m:
classdef bsplinespace < handle
properties
p % polynomial degree
end
methods
function result = bsplinespace(p)
result.p = p;
end
end
end
bspline.m:
classdef bspline < bsplinespace
properties
controlpoints
end
methods
function result = bspline(p, controlpoints)
result.controlpoints = controlpoints;
end
function result = getp(this)
result = this.p;
end
end
end
However, in this scenario the bspline constructor calls the bsplinespace constructor without passing any arguments, causing it to crash:
Not enough input arguments.
Error in bsplinespace (line 8)
result.p = p;
Error in bspline (line 7)
function result = bspline(p, controlpoints)
To be more explicit, what I want is:
One class bsplinespace, which has a constructor which accepts one parameter p
A class bspline, which is the same, but has an extra property and method
Is there an elegant way to implement this?
In your constructor method for bspline, you need to explicitly call the superclass constructor with input argument p:
function result = bspline(p, controlpoints)
result#bsplinespace(p)
result.controlpoints = controlpoints;
end
Otherwise MATLAB will call the superclass constructor with zero input arguments, and you'll get the error you're seeing.
It's a perfectly sensible design, and allows you to control the details of how arguments to the subclass constructor are passed through to the superclass constructor (or not, if you'd like to provide default arguments instead).
I know that, inside a MATLAB function, inputname(k) will return the k-th argument iff the argument is a variable name. Is there any way to write some parsing code that can retrieve the full input argument when that argument is a structure, e.g. foo.bar ? The reason I want to be able to do this is that I'm writing some tools for generic use where the input could be either a named variable or a named structure element.
My primary intent is to be able to store and return the input argment(s) as part of a structure or other variable that the function returns. This is a 'chain of custody' feature which makes it easier for me or others to verify the source data sets used to generate the output data sets.
I don't want the user to have to self-parse externally, or to have to deal with some kludge like
function doit(name,fieldname)
if(exist('fieldname','var'))
name = name.(fieldname);
myinput = [inputname(1),inputname(2)];
else
myinput = inputname(1);
end
% do the function stuff
(I call this a kludge because it both requires the user to enter strange arguments and because it fouls up the argument sequence for functions with multiple inputs)
There is no support from the language to get the input names when passing structs. The reason is probably x.a is internally a call to subsref which returns a new variable, all context is lost. The only possibility you have is using the debug tools and parse the code. There is no other option.
function x=f(varargin)
[ST, I] = dbstack('-completenames', 1);
if numel(ST)>0
fid=fopen(ST(1).file,'r');
for ix=2:ST(1).line;fgetl(fid);end
codeline=fgetl(fid);
fclose(fid);
fprintf('function was called with line %s\n',codeline);
else
fprintf('function was called from base workspace\n');
end
end
From there you may try to parse the code line to get the individual argument names.
Far uglier than Daniel's approach, and probably will crash on the wrong OS, but here's a hack that works to retrieve the first argument; easily adjusted to retrieve all arguments.
[~,myname] = system('whoami');
myname = strtrim(myname(4:end)); % removes domain tag in my Windows envir
% sorry about " \' " fouling up SO's color parsing
myloc = ['C:\Users\' , myname , '\AppData\Roaming\MathWorks\MATLAB\R2015a\History.xml'] ;
f = fopen(myloc,'r');
foo = fscanf(f,'%s');
fclose(f);
pfoo = findpat(foo,'myFunctionName');
% just look for the last instance
namstart = find(foo(pfoo(end):(pfoo(end)+30)) =='(',1) +pfoo(end);
% catch either ')' or ','
namend(1) = find(foo((namstart):end)== ')',1) -2 +namstart;
if numel(find(foo((namstart):end)== ',',1)),
namend(2) = find(foo((namstart):end)== ',',1) -2 +namstart;
end
thearg = foo(namstart:(min(namend)) );
I have written a simple class in MATLAB to manage a set of key-value pairs. I would like to be able to access the keys using a dot after the object name like:
params.maxIterations
instead of:
params.get('maxIterations')
Is it possible to override the dot operator so that it calls my get() method?
I have tried to override the subsasgn() method as suggested here but I couldn't figure out how I should write it.
You could use dynamic properties. Then instead of adding a list of strings, you add a new property for each 'key'. Get all keys with properties(MyClass) (of just fieldnames(MyClass)
However, I think it's indeed best to overload subsref, but note that doing that properly can eat away the majority of a work week if you do it for the first time...It's not that it's really difficult, it's just that the () operator does so much :)
Luckily, you don't have to. Here's how:
classdef MyClass < handle
methods
function result = subsref(obj, S)
%// Properly overloading the () operator is *DIFFICULT*!!
%// Therefore, delegate everything to the built-in function,
%// except for 1 isolated case:
try
if ~strcmp(S.type, '()') || ...
~all(cellfun('isclass', S.subs, 'char'))
result = builtin('subsref', obj, S);
else
keys = S.subs %// Note: cellstring;
%// could contain multiple keys
%// ...and do whatever you want with it
end
catch ME
%// (this construction makes it less apparent that the
%// operator was overloaded)
throwAsCaller(ME);
end
end % subsref method
end % methods
end % class
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
I'm making a generic subsref for my classA, which has an attribute attrA that is a classB instance.
So far, it's working, it lets me do things like
x = objA.attr1.methB(),
which was what I was trying to do to do in the first place.
function this = Class1(varargin)
this.attrA = ClassB()
this = class(this,'ClassA')
function this = ClassB()
this.AttrB1 = 'valueB1'
this.AttrB2 = 'valueB2'
function out = methB
out = this.AttrB2
The problem I stumbled upon is this:
when the call to a method is executed in my subsref, I do it like this (detecting that it's a method etc is done before):
methName = index(1).subs;
args = index(2).subs;
if iscell(args)
varargout = {feval(methName,this,args{:})};
else
varargout = {feval(methName,this,args)};
end %end if iscell
The problem is that when the methName method supports variable number of outputs, this varargout is not equivalent to [x,y,...] (the number of outputs should be assigned in the call to subsref, so methName always returns a single output, which is not always what I want (almost, but not always).
How would I let methName know how many outputs I want? (I don't want to have to pass N as a parameter).
I'm thinking something like creating a string str='[out1,out2,out3...]'
and then doing something like
eval([
str ...
'= {feval(methName,this,args{:})};'...
])
But I keep thinking there must be a more elegant way of doing it.
If the number of outputs you expect is dependent on the output arguments requested from your subsref, you can simply use nargout like this:
[varargout{1:nargout}] = feval(methName,this,args{:});
This solution worked, but I needed to add a little something for single outputs:
if iscell(args)
[argout{:}] = feval(methName,this,args{:});
else
[argout{:}]= {feval(methName,this,args)};
end %end if iscell`
if isSingleCell(argout) && iscell(argout{1})`
v = argout{1};
argout{1}=v{1};
end
I'm not sure, but it may be that the last bit was only necessary to fix something else ( I had to fix a lot of other things to make this work). I'll get back to it when I finish what I was trying to do with this class