Call function in package from package

32 views (last 30 days)
How I can use use function present in package from the package? If i have package with:
I would that in fun1.m i can call fun2.m. I only could call fun2.m with mypkg.fun2? There are some alternative?

Accepted Answer

Sayan Saha
Sayan Saha on 11 May 2018
According to the documentation
all references to functions in the package must use the package name prefix, unless you import the package. See the example in the following link for importing package functions:
Rik on 21 Apr 2021
Comment posted as flag by @Rob Ewalds:
All responders are unanimous in their response: This is poor design, and introduces significant hassle. Could you please stop ignoring all the feedback on this, and pick this up? We don't need 1000+ new features per release, we need a programming-core that gets the basics right. It's clearly a choice: it's not that you don't have the resources.

Sign in to comment.

More Answers (3)

Danny Kumpf
Danny Kumpf on 30 Nov 2020
I also agree that this is poor design, and here is another reason why: Let's say I have a package +pkg1 that is a dependency of a couple other packages I'm working on (+pkg2 and +pkg3). If I put +pkg1 into +pkg2, then not only do I have to call pkg1's internal functions with pkg1.some_fn(), I also have to preface them with pkg2: pkg2.pkg1.some_fn(). This sucks if I want to use pkg1 as a dependency of pkg3 as well, becuase now I need two versions of pkg1: one that calls its internal functions like pkg2.pkg1.some_fn(), and one that calls them with pkg3.pkg1.some_fn().
Here's my hacky workaround.
Paste the following line to be the first line of every function within +pkg1 that calls another pkg1 function:
eval(sprintf('import %s.*', strjoin(regexp(mfilename('fullpath'), '(?<=+)\w*', 'match'), '.')));
This line:
  • Gets the full file path, eg C:\repos\+pkg2\+pkg1\some_fn.m
  • Uses regexp to find all packages on the path, ie `+<pkg_name>` sub-strings
  • Joins the package names together with '.', eg: `pkg2.pkg1`
  • Uses `eval()` to call matlab's `import` statement: `import pkg2.pkg1.*`
After executing, you can call any functions that exist in pkg1 directly, without including the package names. This means that, from within a pkg1 function, you don't need to know whether pkg1 is a package, or whether it is a sub-package of any other package(s). This works even if pkg1 itself is NOT a package, but instead is just added to the matlab path (because `import .*` does nothing). This means a user could use the same repo either as a package or on the matlab path, without changing the code.
But, some negatives are that this line:
  • Uses `eval()` which I think is frowned upon
  • Forces you to do a regexp every time you call a package function, which could be slow
  • May cause namespace collisions if the imported package shares a function name with something else?
  1 Comment
Dimitrii Nikolaev
Dimitrii Nikolaev on 13 Oct 2021
Qiute the usefulliest comment over here.
Situations, when you need to subclass some class, nested in a package like:
classdef some_subclass < pkg2.pkg1.some_class
or check argument of a function using arguments syntax for validation like:
arguments %<--BTW, funny, that this keyword is not highlighted now :/
someargument (1,1) pkg2.pkg1.some_class
will remain a unsolveable problem :(

Sign in to comment.

Burcin Bektas
Burcin Bektas on 13 Aug 2020
Edited: per isakson on 13 Aug 2020
Agree with everyone above that this is poor design. I did find a hack that seems to work:
can be written as
eval(['someObject = ', metaclass(obj).ContainingPackage.Name, '.SomeClass;', ]);
if calling from a class. "obj" above is the object variable SomeClass constructor returns.

Steven Lord
Steven Lord on 21 Apr 2021
Everything I'm writing here is my own opinion about what would happen if we made the change requested in this discussion thread.
Let's assume that package functions could call other functions in the same package without using the package name. What impact would that have? In particular how would you call a function from outside any package if there's a function by the same name in the package? Could I call the built-in bar function from within if I had a function?
In order to insulate yourself from files being added to the package breaking your code, each and every "global" function that you call would need to be called in that way. If foo is a function in a package:
function y = foo(x)
y = sin(x).^2-2*cos(x).^3;
Does that call the built-in sin function? It would be impossible to say without knowing if there's a sin function in the package. The answer to that question could change with no modification to the foo package function! So to safeguard and assure you're calling the built-in sin function let's assume that all the "global" functions were treated as being in a package named globalfuns. Do you want to have to write the following?
function y = foo(x)
y = globalfuns.sin(x).^2-2*globalfuns.cos(x).^3; % Calls the built-in sin and cos functions
That's a lot more verbose than the first version of the function. But that's not the whole story. The .^ operator has another name: it is the power function. So if you had a power function in your package would .^ call that function? Again, that would be impossible to say. To be sure it wouldn't you'd need:
function y = foo(x)
y = globalfuns.power(globalfuns.sin(x),2)-2*globalfuns.power(globalfuns.cos(x),3);
But the * operator is also called mtimes.
function y = foo(x)
y = globalfuns.power(globalfuns.sin(x),2)-globalfuns.mtimes(2,globalfuns.power(globalfuns.cos(x),3));
That's a lot less readable than the first case. But that's what you would need to do to make sure that people can't break your function by adding power, sin, mtimes, or cos functions to your package.
With the current system and the original function:
function y = foo(x)
y = sin(x).^2-2*cos(x).^3;
you would have to opt into calling the package sin or cos functions if you wanted to call them. Otherwise you get the built-in functions. People could add functions to or remove functions from the package without affecting the foo function above.
How do you opt in?
function y = foo(x)
y = mypackage.sin(x).^2-2*cos(x).^3; % Use the package sin, built-in cos
% or
function y = foo(x)
import mypackage.*
y = sin(x).^2-2*cos(x).^3; % Use mypackage.sin and/or mypackage.cos if they exist, built-ins if not
For package functions, the package name is effectively part of the function's name. [Not for purposes of a function like isvarname but it is for purposes of calling the function.] Just as you would have to update the callers of a regular function myfun if you changed then name from myfun to mybar to ensure they keep calling the correct function, if you change the name of mypackage.myfun to mynewpackage.myfun you need to update the callers whether they be in the mypackage package, the mynewpackage function, or outside any package.
In my opinion, changing either the file name or the package name should be a rare occurrence representing a major change in the organization and architecture of your code. It's not something you should do on a whim, and you should allocate time to react to the major reorganization / rearchitecting of the code.
Ashley Trowell
Ashley Trowell on 14 Jul 2021
This is also a big issue for me. Mathworks shouldn't actively discourage good coding style in their design choices.
I'm not convinced by the argument that making packages hard to use prevents name collisions. In fact, this is the opposite of the truth, packages PREVENT collisions, that's what a namespace IS. Clear example: I created an object oriented simulation architecture, which among other things, has class names like Platform, Antenna, and Radar. This suite of classes is many thousands of lines of code, and perhaps a hundred m-files I use these a lot, so they sit in my path. Now it turns out, I'm not the only person who like names like Platform, Radar, and Antenna, and before long, I'm experienceing collisions. The sensible thing would be to wrap my project in a package. It wouldn't be too bad for me to have to type radar = myPackage.Radar() in the future. However... now I have thousands of lines of code that need to be checked for references between classes. In some cases, there is a major ergonomics challenge, since a line of code might have called a few disparate functions and been fine before
obj.newValue = fun1(1,2,3) * fun2(1,2,3) + fun3(1,2,3)
But now:
obj.newValue = myPackage.fun1(1,2,3) * myPackage.fun2(1,2,3) + myPackage.fun3(1,2,3)
This is suddenly not so fun. It encourages using a shorter package name than would really be advisable. It also makes simple find/replace refactoring hard to implement.
I don't see why be can be worried that I might have myPackage.plot defined when I can at anytime overwrite the default plot function with an accidental plot = 1.
Furthermore, this leads to several IDE issues which make a bad situation worse. First, there is a distinct lack of refactoring tools. Even if changing a package name is considered a big change, to be honest, I like to make big changes quickly. I've got other things to do than rename import statements.
Secondly, using import statements breaks my ability to use Ctrl+D to trace to a functions definition. Folks trying to understand the code can end up perplexed for a while until they go looking for an import, which they rarely ever do.

Sign in to comment.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by