I'd like the constructor of a class to automatically determine the full path to the calling function, so that that class can write a file that's guaranteed to be in the caller's directory (instead of whatever happens to be the pwd()
).
So, I have the following setup:
In some_path/test.m
:
function test
SomeClass()
end
In some_path/some_subdir/SomeClass.m
:
classdef SomeClass < handle
methods
function obj = SomeClass()
evalin('caller', 'mfilename(''fullpath'')')
end
end
end
When I call test()
, I get the following:
>> test()
ans =
'some_path/some_subdir/SomeClass.m' % <- ...why?
I expected the call to mfilename()
in evalin('caller', ...)
to evaluate inside test()
, but apparently, that doesn't happen...
Nesting evalins
doesn't seem to help:
...
function obj = SomeClass()
evalin('caller', ' evalin(''caller'', ''mfilename(''''fullpath'''')'') ')
end
...
>> test()
ans =
'some_path/some_subdir/SomeClass.m'
The only way to get this to work is the far less intuitive dbstack()
:
...
function obj = SomeClass()
S = dbstack(1, '-completenames');
S(1).file
end
...
>> test()
ans =
'some_path/test.m'
What am I missing?
It looks like you cannot use evelin
for this purpose. From the documentation:
evalin('caller', expression)
finds only variables in the caller's workspace; it does not find functions in the caller.
From that I read that not the full context of the calling function is recovered before evaluating the expression, only variables in the workspace of the calling function are made available.
That same documentation page also mentions this limitation:
evalin
cannot be used recursively to evaluate an expression. For example, a sequence of the formevalin('caller', 'evalin(''caller'', ''x'')')
doesn't work.
That is consistent with the notion that only the caller's workspace is made available, not the full context. The expression is not actually evaluated as if it were written inside the calling function.
I have repeated your experiment with a simple M-file function, just to verify this indeed is not specific to classes or constructors, but generally applies to any function, anywhere.
The dbstack
option is the way to go.