Managing custom classes, mat-files, and namespaces
13 views (last 30 days)
Show older comments
Say I have a (simple) custom class, defined with a classdef. Let's say it's defined in my_class.m
I then generate a bunch of objects of the class, and save the results to a matfile: my_data.mat.
I then want to reorganize my code, either by:
- renaming my class (but otherwise keeping the definition the same). Now I have my_class_ver1.m as the classdef.
- introducing namespaces. Here, I've moved the file, my_class.m, into a namespace directory, i.e.,: +ver1/my_class.m
Is there any way to provide a class (re)mapping when loading the existing my_data.mat file? As it stands, Matlab just loads the file as an int a uint32 array. For #2, just importing the namespace (import ver1.* or import ver1.my_class) does not work.
0 Comments
Accepted Answer
Steven Lord
on 1 Aug 2024
For at least the first of those scenarios, class aliasing may be of use. That documentation page has a section "Renaming a Namespace" that may also address the second of your scenarios.
3 Comments
Steven Lord
on 1 Aug 2024
Edited: Steven Lord
on 1 Aug 2024
That page states "MATLAB recognizes both FirstName and SecondName as the same class as long as SecondName.m and the associated alias resources folder are in the same folder on the MATLAB path." so I believe you can move the resources directory elsewhere as long as you move SecondName.m alongside it.
[Removed something I'd written about FirstName.m after rereading the page, as it says "In fact, you must remove the original definition from the path so that MATLAB finds the newer alias instead of the older definition."]
More Answers (1)
Shubham
on 1 Aug 2024
Hi John,
When you rename a class or move it into a namespace, MATLAB does not automatically recognize the new class definition when loading old .mat files containing objects of the original class. However, you can use MATLAB's matfile and loadobj functionalities to handle this situation.
Scenario 1: Renaming the Class
- Define the new class with a loadobj method: Create a loadobj method in your new class definition to handle the conversion from the old class to the new class.
% my_class_ver1.m
classdef my_class_ver1
properties
% Define your properties here
end
methods
function obj = my_class_ver1()
% Constructor code
end
end
methods (Static)
function obj = loadobj(a)
if isa(a, 'my_class')
% Convert from my_class to my_class_ver1
obj = my_class_ver1();
% Copy properties from a to obj as needed
else
obj = a;
end
end
end
end
2. Load the .mat file: When you load the .mat file, MATLAB will call the loadobj method to convert the objects.
data = load('my_data.mat');
% Access your objects from the data struct
Scenario 2: Introducing Namespaces
- Define the new class within the namespace with a loadobj method: Create a loadobj method in your new class definition within the namespace to handle the conversion.
% +ver1/my_class.m
classdef my_class
properties
% Define your properties here
end
methods
function obj = my_class()
% Constructor code
end
end
methods (Static)
function obj = loadobj(a)
if isa(a, 'my_class')
% Convert from my_class to ver1.my_class
obj = ver1.my_class();
% Copy properties from a to obj as needed
else
obj = a;
end
end
end
end
2. Load the .mat file: Similar to the first scenario, MATLAB will call the loadobj method to convert the objects when you load the file.
data = load('my_data.mat');
% Access your objects from the data struct
Important Points to consider:
- Ensure that the properties and methods of the new class match those of the old class to facilitate smooth conversion.
- You might need to manually copy the properties from the old object to the new object within the loadobj method.
- This approach requires you to have access to the old class definition during the transition period. If the old class definition is not available, you will need to manually handle the conversion.
3 Comments
Shubham
on 1 Aug 2024
John,
You're right, the loadobj method of the new class won't be called directly if the .mat file contains objects of the old class, and MATLAB will look for the old class definition.
I think your approach is right that you can temporarily add the legacy class definitions to the path when loading and converting your data.
An Idea for writing a code would look like this:
function new_data = load_and_convert(filename, legacy_path, new_class_map)
% Temporarily add the legacy class definitions to the path
old_path = addpath(legacy_path);
% Load the data
legacy_data = load(filename);
% Convert the data
new_data = structfun(@(obj) convert_legacy_object(obj, new_class_map), legacy_data, 'UniformOutput', false);
% Restore the original path
path(old_path);
end
function new_obj = convert_legacy_object(obj, new_class_map)
% Check if the object is an instance of a legacy class
old_class_name = class(obj);
if isfield(new_class_map, old_class_name)
new_class_name = new_class_map.(old_class_name);
new_obj = feval(new_class_name); % Create an instance of the new class
% Copy properties from the old object to the new object
% Note: This assumes the properties have the same names and types
props = properties(obj);
for i = 1:numel(props)
new_obj.(props{i}) = obj.(props{i});
end
else
% If the object is not a legacy class, return it unchanged
new_obj = obj;
end
end
You can use it like this:
First, define the mapping of legacy class to new class:
new_class_map = struct();
new_class_map.my_class = 'my_class_ver1';
% Add more mappings as needed
Then, call the load_and_convert function:
legacy_path = '/path/to/legacy/classdefs';
filename = 'my_data.mat';
new_data = load_and_convert(filename, legacy_path, new_class_map);
This should let you load and convert legacy data without needing to keep the old class definitions permanently on the path. It handles multiple legacy classes with minimal changes. It might work in your case.
See Also
Categories
Find more on Startup and Shutdown in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!