Simple Namespaces and Brilliant Function Handles
Greg's pick this week is module - encapsulate MATLAB package into a name space module by Daniel Dolan.
The concept of namespaces has been available in MATLAB for a number of years at this point. While the technology is very mature at this point, a common feature of namespaces was not included in the MATLAB implementation. You cannot call one function in the same namespace from another function in the same namespace without including the namespace definition somewhere. Most namespaces in other languages permit functions to call each other within the namespace without needing to identify the namespace.
Daniel’s “MODULE” function provides an interesting means to work around that constraint using a method that demonstrates the powerful concept of function handles in MATLAB.
The nature of Daniel’s solution also provides a means to create namespace specifiers, without needing to continually reference the full namespace.
Finally Daniel makes it possible to have what one might call “dynamic namespaces”.
I selected this submission because it demonstrates the powerful feature of function handles, advertises the use of namespaces in MATLAB, and uses the “DBSTACK” function in a way that surprised me.
Contents
Before you use this function, be sure to fix the bug
Yes, it happens. There’s what appears to be a bug in this File Exchange submission. Change line 110 from
root=sprintf('%s.',root{:});
to
root=sprintf('%s.',root{end:-1:1});
The order in which package namespaces is being constructed is backward. Changing this line reverses the construction and resolves the issue.
What is a namespace?
If you’re not familiar with namespaces, don’t fret. It is an advanced software engineering concept. I work with a lot of software engineers all over the world, and many of them are not familiar with namespaces because they work in coding languages or environments that don’t have them (such as C).
A namespace provides a means to specifically call unique functions that share the same name. I like to think of a namespace as a context or a classifier for a function.
Let’s say you have two functions, each named “myDisp”, but they have different behavior.
>> myDisp('Hello')
My Display 1 Hello
Versus
>> myDisp('Hello')
My Display 2 ------------- Hello
How do you invoke the appropriate myDisp at the correct time?
Perhaps you could give the functions different names: myDisp and myDisp2.
But if you’re concerned about modularity, and these functions are used independently in other projects and code files, changing the name of the functions will be problematic.
What if instead you could include an identifier that would make the call to the myDisp function more specific?
>> myFirstNamespace.myDisp('Hello') >> myOtherNamespace.myDisp('Hello')
Now both functions can be available, without introducing a name conflict, or needing to change the name of the function.
To accomplish this in MATLAB, you need to use package folders
Namespaces present challenges too
While namespaces provide a means to be more specific about function calls, they can be inconvenient when it comes to actually writing them out, and reading them in the code file. Especially as the namespaces get longer.
>> myMainNamespace.myOtherSubNamespace.myOtherNamespace.myDisp('Hello')
This seems hard to read, and a pain to write.
We can use the IMPORT function to handle this:
>> import myMainNamespace.mySubNamespace.myFirstNamespace.*
>> myDisp('hello')
My Display 1 Hello
Now contents of the myFirstNamespace can be referenced without using the full namespace notation. But if you import two functions with the same name but live in different namespaces, you are back to the same problem that namespaces try to solve! You can partially import namespaces, but this gets tedious.
So what does module do?
The MODULE function makes it possible to refer to functions in namespace by essentially providing an alias for the namespace. This means you can refer to functions deep within a namespace without needing to write out the full namespace, or have the potential conflict issues using the IMPORT function.
>> myLocalSpace = module('myMainNamespace.mySubNamespace.myFirstNamespace'); >> myLocalSpace.myDisp('Hello')
>> myOtherLocalSpace = module('myMainNamespace.myOtherSubNamespace.myOtherNamespace'); >> myOtherLocalSpace.myDisp('Hello')
Here the calls to the functions in the namespace are concise and specific to the desired function.
This also allows you to do fun things like make the namespace dynamic
if (a < b) myLocalSpace = module('myMainNamespace.mySubNamespace.myFirstNamespace'); else myLocalSpace = module('myMainNamespace.myOtherSubNamespace.myOtherNamespace'); end myLocalSpace.myDisp('Hello')
I cannot say at this point whether or not having dynamic namespaces is a good idea, but it is certainly an interesting concept.
What about the namespace self-referencing constraint in MATLAB?
In MATLAB, if a function in a namespace calls another function in the same namespace, it must refer to the full namespace of the function being called.
function myDisp( displayInput ) displayHeader = myMainNamespace.myOtherSubNamespace.myOtherNamespace.otherFunction; disp(displayHeader); disp(displayInput); end
This is fine, until later when you wrap the existing namespace in another parent namespace, and you must go into all of the functions and append the new parent namespace. If you have hundreds of functions, this is going to get old fast.
Daniel provides a really neat mechanism to get around this constraint. Calling MODULE with no inputs assumes the namespace you want is relative to the current function.
function myDisp( displayInput ) localNamespace = module; displayHeader = localNamespace.otherFunction(); disp(displayHeader); disp(displayInput); end
Now, even if the structure of the namespace changes, you can still call the functions local to the namespace, because the local namespace is automatically updated when the myDisp function is called.
It’s all about the function handles
This is the part I think is really elegant.
In order to make this work, Daniel takes advantage of function handles. Function handles are pointers or aliases to functions. This means you can use a variable to store a reference to a function.
Daniel creates a collection of these function handles by creating function handles for each of the functions in a specific package folder. Then he stores these function handles in a MATLAB struct. Subreferencing the struct using the dot notation (struct.field) will now act like referencing a function in a namespace. How cool is that!
Finally, to get around the constraint MATLAB imposes of functions in a namespace referencing other functions in the same namespace, Daniel uses the DBSTACK function.
I’m pretty sure he’s using DBSTACK in a way it was never intended, but I think it’s absolutely brilliant!
Daniel uses the DBSTACK function to determine what function called MODULE, so he can then figure out what namespace the function belongs to.
While there may be some performance implications from using DBSTACK, it is an excellent demonstration of the flexibility of the MATLAB environment. You can ask a function “Who called you?” I’ve been working with MATLAB over 15 years now, and I didn’t realize you could do that!
Comments
If you would like to leave any comments regarding this post, please click here.
- Category:
- Picks
Comments
To leave a comment, please click here to sign in to your MathWorks Account or create a new one.