23

As noted here, functions in packages, as well as static methods in classes, still need to use a packagename.functionname syntax or import packagename.* for each function (since the imports are part of the function workspace and not global). This means that changing the package/class name later on can become a tedious nuisance.

Is there any way to do something like import this.*, i.e. a package/class name agnostic method to access all functions/static methods in the same package/class?

Community
  • 1
  • 1
Tobias Kienzler
  • 25,759
  • 22
  • 127
  • 221
  • I would love to hear an answer for this one... – Andrey Rubshtein Oct 19 '11 at 00:15
  • @Andrey so do I. Maybe a bounty will help finding some ingenious method for this... Gnovice found a [nice hack](http://stackoverflow.com/questions/5635413/how-to-convert-a-directory-into-a-package/5638104#5638104) for this by the way, but as he said it might be wasting lots of computation time – Tobias Kienzler Oct 19 '11 at 05:03
  • 4
    If we give this enough upvotes, maybe they'll add it to R2012a? – Andrew Janke Oct 25 '11 at 21:54
  • @Andrew sure, give it a shot ;-) Until then I guess the "correct" answer here is simply "No, but if you really need it use [this Hack](http://stackoverflow.com/questions/5635413/how-to-convert-a-directory-into-a-package/5638104#5638104) by [Gnovice](http://stackoverflow.com/users/52738/gnovice)" – Tobias Kienzler Oct 26 '11 at 05:03
  • @AndrewJanke ...or R2019a? – Rody Oldenhuis Oct 30 '18 at 19:25
  • I've got nothing. AFAIK, nothing has changed, and `import` is still scoped to a function/method, not a classdef, and there's no `import this.*`. And I haven't heard anything about a change for R2019a. Maybe R2021a? :) – Andrew Janke Nov 01 '18 at 19:35

3 Answers3

8

So... doesn't this require importthis to also be imported? Or is importthis a function you always have in your path?

It seems hardly more complex to just paste an "import this" block with this at the top of each function, and then you don't have to worry about importthis being in your path. I tend to feel that reliance on path is dangerous.

"Import This" block

%% Import own package
[~, pkgdir] = fileparts(fileparts(mfilename('fullpath')));
import([pkgdir(2:end) '.*']);

You can even put it in a try/catch block to make sure it's in a package directory, and decide what to do if it's not.

%% Import own package
try
    [~, pkgdir] = fileparts(fileparts(mfilename('fullpath'))); 
    import([pkgdir(2:end)'.*']);
catch err
    if ~strcmp(err.identifier,'MATLAB:UndefinedFunction'), rethrow(err); end
end
Randy
  • 96
  • 1
  • 2
  • 2
    Or even something like this for nested packages: `mfiledir = fileparts(mfilename); pkg_pos = strfind(mfiledir, [filesep '+']); if ~isempty(pkg_pos), import([strrep(mfiledir((pkg_pos(1)+2):end), [filesep '+'], '.') '.*']); end` – Ken Chatfield Apr 11 '13 at 14:04
4

I recently ran into a similar problem and found the following solution for packages. However it is VERY hacky.

You create a function called import this with an optional argument.

function to_eval = importthis(exclude_list)
if nargin == 0
    exclude_list = [];
end
var_name = genvarname('A', exclude_list); %avoid shadowing
to_eval = ['[~,'...
    , var_name...
    , ']=fileparts(fileparts(mfilename(''fullpath'')));'... %get containing dir
    , 'eval([''import '','...
    , var_name...
    , '(2:end),''.*'']);'... %remove '+'
    , 'clear '... %clean up
    , var_name
    ];
end

This function returns a string which can then be evaled that imports the "this" package. So in your package functions you would put the following near the top:

function B = myfunc(A)
eval(importthis);
%function body
end

You can also pass who to importhis, leaving your function's namespace clean.

function B = myfunc(A)
eval(importthis(who));
%function body
end

I can't decide whether I should feel proud or discusted by what I did.

AE426082
  • 633
  • 6
  • 11
  • 1
    nice work! I guess if you use [evalin](http://www.mathworks.de/help/techdoc/ref/evalin.html)('caller',...), you can save the outer `eval` and make it a direct call to `importthis`. This is also an answer to [How to convert a directory into a package?](http://stackoverflow.com/q/5635413/321973) – Tobias Kienzler Mar 07 '12 at 11:06
  • I tried `evalin` but it doesn't seem to work. It is also possible to get the package|directory name without `eval`. You can throw a dummy exception, catch it and inspect it as it contains a stack trace. Or you can just abuse `dbstack`. Aside from that my solution is the same as the one you linked. – AE426082 Mar 07 '12 at 11:39
3

This probably is not a bounty worthy answer but as you do not have any answers I thought I would post it anyway! You can invoke static methods via an instance of the class which you would only need to define once. You can invoke functions via a function handle but this would require one handle per function.

Using these techniques you could define all your static method and function references in one place. Then you would use these references throughout your package. Then if you decided to change the package name at a later point you would only need to update these references which are all stored in one place.

See:

Calling Static Methods

You can also invoke static methods using an instance of the class, like any method:

obj = MyClass;

value = obj.pi(.001);

function_handle (@)

The following example creates a function handle for the humps function and assigns it to the variable fhandle.

fhandle = @humps;

Mark McLaren
  • 11,470
  • 2
  • 48
  • 79
  • well, it would be a shame to let the bounty go to waste anyway :-7 but also your answer is probably the closest thing currently possible, so thanks for posting it – Tobias Kienzler Oct 26 '11 at 16:48