the_trouble_with_MATLAB_packages - depcharge-org/depcharge GitHub Wiki

The Trouble with MATLAB Packages

MATLAB packages are essential for managing namespaces, but they come with several unique challenges that set them apart from package implementations in languages like Python, Java, C++, and C#.

Uniqueness of MATLAB's Approach

MATLAB's approach to packages and imports is distinct from most other programming languages:

  • For other languages, when imports are required, their scope is broad, covering an entire file or module.

  • In other languages, no import or namespace enumeration is required for sibling functions within the same namespace.

  • Other languages minimize the impact of the external directory structure on the code. When there is an impact, IDEs typically automate changes required.

Key MATLAB Deficiencies

  1. Local Import Requirements:
    • In other languages import packages to an entire file or module,
      In MATLAB the scope of the package import statements is only one function or script, so a new import is needed within each function.
    • This approach leads to repetitive import statements, especially in files with many small functions.
  2. Limited Sibling Function Access:
    • In other languages, functions within the same namespace, package, or class can call sibling functions without explicitly specifying the namespace. However in MATLAB, sibling functions within the same namespace must fully express the namespace, including all parent namespaces. The only exception is if an import statement is used in each function, which would also have to fully enumerate ALL parent namespaces.
    • This applies even to methods within the same class when referencing static methods.
  3. Reduced Code Readability:
    • The need to specify full package paths without imports can make code less readable if not managed properly.
  4. Rigid Directory Structure:
    • The package path is also a folder hierarchy, and the package path must be fully enumerated repeatedly within the code. Consequently, any change in the package folder structure will break function calls internal to the package.
    • Nesting existing code within a new parent package will break all internal function calls of the package. There is no precedent for this brittleness in other programing languages.
    • For a large project with many internal function calls, this can require significant refactoring.
    • MATLAB provides no tool for automating this refactoring. MATLAB Projects provides some automatic refactoring for moving and renaming files, but those tools do not work when files are moved into packages.

Even in the case of methods of the same class, referencing another static method would require the full package path in every call

+myPackage
  +utilities
    @MyClass
      MyClass.m
classdef MyClass
    methods
        function method1(obj)
            disp('Method 1 called');
			% Calling another method in the same class
			obj.method2();
			% Calling a static method in the same class
			myPackage.utilities.MyClass.method3()
        end

        function method2(obj)
            disp('Method 2 called');
        end        
    end
    
    methods (Static)
    	function method3()
    		disp('Static Method 3 called');
    	end
    
    end
end

Workarounds

1. Import Statements

import myPackage.utilities.*
  • Pros: Allows use of short function names.
  • Cons: Needed in every function context; may interfere with "Find Function" features.

2. Function Aliases

myFunc = @myPackage.utilities.myFunction;
  • Pros: Similar to import statement but allows tracing of the definition.
  • Cons: Still requires definition in each function context.

3. Class-based Static Functions

classdef MyUtilities
    methods (Static)
        function result = myFunction(arg)
            % Function implementation
        end
    end
end

% Usage
utils = myPackage.utilities.MyUtilities;
result = utils.myFunction(arg);
  • Pros: Allows access to functions without using the entire package path.
  • Cons: Requires instantiation of the class.

4. Class Member Variables as Function Aliases

classdef MyClass
    properties
        utilFunc
    end
    
    methods
        function obj = MyClass()
            obj.utilFunc = @myPackage.utilities.myFunction;
        end
        
        function useFunction(obj)
            result = obj.utilFunc(arg);
        end
    end
end
  • Pros: Sets the namespace path once in a file, usable in multiple methods.
  • Cons: Somewhat of a hack; must avoid accidental recursion.

Conclusion

While MATLAB packages provide namespace management, their implementation presents unique challenges not typically found in other programming languages. The workarounds presented here can help mitigate some of these issues, but they each come with their own trade-offs.