I'm trying to figure out how to ask the user whether they want to replace the previous object of the same class with the default object, or simply use the previous object, when calling the constructor.
I'm looking for actions in both these cases:
>>obj = Obj()
'obj' already exists. Replace it with default? (y/n): y
%clear obj and call default constructor to create new obj
>>obj = Obj()
'obj' already exists. Replace it with default? (y/n): n
%cancel call of Obj()
How would I do this? I've messed around with the default constructor, to no avail.
EDIT: If it makes any difference, Obj is a subclass of Handle.
The following solution stems from several workarounds/hacks and is not part of the standard MATLAB's OO constructs. Use with caution.
You need to:
evalin()
into the 'caller'
workspace the names and classes of the 'base'
workpsace variables
- retrieve the last executed command
- extract the name of the assigned variable with e.g.
regexp()
- compare names and classes. If a total match occurs, i.e. the variable in the
'base'
workspace is being overwritten with a new instance of the same class, ask the user for input()
. If the user chooses to preserve the existing object, overwrite the new instance with the existing one through evalin('caller',...)
.
The class foo
:
classdef foo < handle
properties
check = true;
end
methods
function obj = foo()
% variable names and sizes from base workspace
ws = evalin('base','whos');
% Last executed command from window
fid = fopen([prefdir,'\history.m'],'rt');
while ~feof(fid)
lastline = fgetl(fid);
end
fclose(fid);
% Compare names and classes
outname = regexp(lastline,'\<[a-zA-Z]\w*(?=.*?=)','match','once');
if isempty(outname); outname = 'ans'; end
% Check if variables in the workspace have same name
idx = strcmp({ws.name}, outname);
% Ask questions
if any(idx) && strcmp(ws(idx).class, 'foo')
s = input(sprintf(['''%s'' already exists. '...
'Replace it with default? (y/n): '],outname),'s');
% Overwrite new instance with existing one to preserve it
if strcmpi(s,'n')
obj = evalin('caller',outname);
end
end
end
end
end
Class in action:
% create class and change a property from default (true) to false
clear b
b = foo
b =
foo with properties:
check: 1
b.check = false
b =
foo with properties:
check: 0
% Avoid overwriting
b = foo
'b' already exists. Replace it with default? (y/n): n
b
b =
foo with properties:
check: 0
The weaknesses (see points above):
- applies only to cmw line and script executed commands, not functions (see link to extend to function calls). Also, might break in case of problems reading history.m.
- the current regex fails on
a==b
.
- Dangerous because the
evalin()
on user input leaves potential security threats open. Even if the input is filtered with the regexp and the string comparison, the construct might pose a problem if the code is revisited later on.
Singleton
try this, not sure if you are familiar with it, but this mean, you only have one global instance of this specific object.
You could use the function isobject()
(see doc here) to check if the variable is an object. If true, you could then check the class of the object with class()
(see doc here) and compare it to the class of the object you want to build. Something like (just to give you an idea):
if isobject(obj)
if class(obj) == myclass
% ask to replace it or not
else
% create new one over the object of a different class
end
else
% create new one
end
If I understand your question correctly, you probably want to put this as a constructor function for your class. I think you will have to pass the variable name when calling the constructor: obj = Obj(obj)
.