Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

clone (deep copy) a handle object

1,443 views
Skip to first unread message

Guillaume Perrault Archambault

unread,
Aug 6, 2009, 12:53:02 PM8/6/09
to
I need to make a deep copy of a hande object. Is there any easy way to do this in R2009a?

Doug Schwarz

unread,
Aug 6, 2009, 1:52:36 PM8/6/09
to
In article <h5f1pe$2ll$1...@fred.mathworks.com>,
"Guillaume Perrault Archambault" <guigui.the...@gmail.com>
wrote:

> I need to make a deep copy of a hande object. Is there any easy way to do
> this in R2009a?

When I had to do this I added this method to my class:

% Make a copy of a handle object.
function new = copy(this)
% Instantiate new object of the same class.
new = feval(class(this));

% Copy all non-hidden properties.
p = properties(this);
for i = 1:length(p)
new.(p{i}) = this.(p{i});
end
end


Then, when I want to make a copy of

a = myclass;

I use something like this:

b = copy(a); % which reads nicely as b = copy of a

or, equivalently,

b = a.copy;


If you need to copy hidden properties which don't show up in the result
of properties(this), you can use

p = fieldnames(struct(this));

instead.

--
Doug Schwarz
dmschwarz&ieee,org
Make obvious changes to get real email address.

Guillaume Perrault Archambault

unread,
Aug 7, 2009, 8:59:02 AM8/7/09
to
It's exactly what I needed. Thanks!
G

Doug Schwarz <s...@sig.for.address.edu> wrote in message <see-CD8C71.1...@news.frontiernet.net>...

Till Bockemuehl

unread,
Sep 30, 2009, 11:29:33 AM9/30/09
to
Many thanks from me as well. Works like a charm!

Best regards,

Till

Peter

unread,
Oct 20, 2009, 4:49:01 AM10/20/09
to
The use of:
p = fieldnames(struct(this));
seems to work fine for public properties, but not for private and protected properties.

The function returns:
??? Getting the 'property_protected' property of the '...' class is not allowed.

Do you have a suggestion to make a deep copy of a hande object which also copies these properties?

Regards,
Peter

Steven Lord

unread,
Oct 20, 2009, 9:37:30 AM10/20/09
to

"Peter " <pleas...@newsgroup.mathworks.com> wrote in message
news:hbjtht$hpq$1...@fred.mathworks.com...

> The use of:
> p = fieldnames(struct(this));
> seems to work fine for public properties, but not for private and
> protected properties.
>
> The function returns:
> ??? Getting the 'property_protected' property of the '...' class is not
> allowed.
>
> Do you have a suggestion to make a deep copy of a hande object which also
> copies these properties?

Rather than trying to convert the class object into a struct array and
getting its field names, use meta-classes.

http://www.mathworks.com/access/helpdesk/help/techdoc/matlab_oop/br8b90p.html

--
Steve Lord
sl...@mathworks.com
comp.soft-sys.matlab (CSSM) FAQ: http://matlabwiki.mathworks.com/MATLAB_FAQ


Barry Ridge

unread,
Jun 3, 2010, 9:34:04 AM6/3/10
to
"Guillaume Perrault Archambault" <guigui.the...@gmail.com> wrote in message <h5f1pe$2ll$1...@fred.mathworks.com>...

> I need to make a deep copy of a hande object. Is there any easy way to do this in R2009a?

I came up with a bit of a hack for doing this. It uses file-handling, and therefore is not so elegant, but it seems to work. Just add this method to whatever class you want to copy:

function new = copy(this)
save('temp.mat', 'this');
Foo = load('temp.mat');
new = Foo.this;
delete('temp.mat');
end

Example usage (assumes copy() is a method in class MyClass):
A = MyClass();
B = A.copy();

Steven Lord

unread,
Jun 3, 2010, 10:03:35 PM6/3/10
to

"Barry Ridge" <nobod...@sogetthis.com> wrote in message
news:hu8b0c$b9e$1...@fred.mathworks.com...

If modifying the class is an option, then have your clone method in your
class instantiate a new empty handle object and set the appropriate
properties. Remember, inside a class method, you have access to all the
properties of the object. If you don't want to hard-code the list of
properties, you could always make use of the meta.class object for your
object along with dynamic "field" names (or your class's GET and SET
methods, or whatever other property access system you've devised.)

http://www.mathworks.com/access/helpdesk/help/techdoc/matlab_oop/br4iuh2.html

--
Steve Lord
sl...@mathworks.com
comp.soft-sys.matlab (CSSM) FAQ: http://matlabwiki.mathworks.com/MATLAB_FAQ

To contact Technical Support use the Contact Us link on
http://www.mathworks.com


boaz

unread,
Jul 29, 2010, 4:51:06 AM7/29/10
to
"Steven Lord" <sl...@mathworks.com> wrote in message <hu9mt4$pkh$1...@fred.mathworks.com>...

Thanks Steve,
Summing up, I think adding this function to the base class does the trick. Any remakrs?

function newObj = clone(this)
% create an empty instance of the class
newObj = eval(class(this));

% copy non-dependent properties, by creating a meta object for the class of 'this'.
mo = eval(['?',class(this)]);
ndp = findobj([mo.Properties{:}],'Dependent',false);
for idx = 1:length(ndp)
newObj.(ndp(idx).Name) = this.(ndp(idx).Name);
end

Thanks,
Boaz

boaz

unread,
Jul 29, 2010, 4:51:06 AM7/29/10
to
"Steven Lord" <sl...@mathworks.com> wrote in message <hu9mt4$pkh$1...@fred.mathworks.com>...
>

Thanks Steve,

Peter O'Connor

unread,
Dec 15, 2011, 6:35:11 PM12/15/11
to
The above won't work if your properties are also handle objects (that is, your properties will still refer to the original objects). It also gets a little more complicated when you have circular object references (eg A.B.A==A) or objects that can be referenced from two different paths (eg A.B==A.C).

The below code takes care of these things. To use it, subclass your class of DataBaseObject instead of handle, then you can use the copy method (eg "B=A.copy"). I trimmed it down a bit for this post but I think it should work as-is.

Happy copying

===================================================

classdef DataBaseItem<handle
% Contains a few properties and method useful when dealing with arrays
% of linked objects like one would in a relational database.
%
%

properties

copyCode; % This code ensures that when doing a deep copy, objects
% With cyclic references aren't copied in infinite
% loops.

copies=struct; % Links to next copies.

end

methods

function B=copy(A,Ob,copyCode)
% Make a deep copy of the object. The copyCode stuff is there
% to make sure circular references don't get copied in infinite
% loops
%
% Peter O'Connor

if ~exist('Ob','var'), Ob=A; end

% If object's already been copied
if ~exist('copyCode','var'),
copyCode=['c' num2str(typecast(now,'uint64'))];

elseif ismember('DataBaseItem',superclasses(Ob))
if isfield(Ob.copies,copyCode), % If it's been copied already, return the copy
B=Ob.copies.(copyCode);
return;
end
end

meta=metaclass(Ob);
pnames=cellfun(@(x)x.Name,meta.Properties,'uniformoutput',false);

B=eval(class(Ob));
warning off MATLAB:structOnObject
S=struct(Ob);
warning on MATLAB:structOnObject
pB=fields(S);

Ob.copies.(copyCode)=B;
B.copyCode=copyCode;

for i=1:length(pB)

if any(ismember(pB{i},{'copies','copyCode'})), continue; end

whichone=strcmp(pB{i},pnames);

% Do not copy Transient or Dependent Properties
if any(whichone) && (meta.Properties{whichone}.Transient || meta.Properties{whichone}.Dependent)
continue;
end

val=S.(pB{i});

if ~isempty(val) && isa(val,'handle')
B.(pB{i})=eval(class(val));
B.(pB{i})(length(val))=eval(class(val)); % God damn ugly matlab
for j=1:length(val)
B.(pB{i})(j)=A.copy(val(j),copyCode);
end
else
B.(pB{i})=val;
end
end

end
end

===================================================

Peter O'Connor

unread,
Dec 15, 2011, 7:14:08 PM12/15/11
to
Actually minor edit: replace

copyCode=['c' num2str(typecast(now,'uint64'))];
with
copyCode=['c' num2str(typecast(rand,'uint64'))];

Because if you're copying things in quick succession, "now" won't give a unique answer

Mark Mikofski

unread,
Dec 17, 2012, 1:04:06 PM12/17/12
to
"Peter O'Connor" <peter....@mail.mcgill.ca> wrote in message <jce2gg$3sv$1...@newscl01ah.mathworks.com>...
For those consulting this thread in the present (2012), it looks like this has been implemented in MATLAB at least as early as R2012a (and possibly earlier).

Subclass your object to matlab.mixin.Copyable instead of handle and that will expose the copy method which will perform shallow copies (no dependent or nested objects or recursive properties).

The methods can be overloaded and an example is given for a method to make deep copies.

http://www.mathworks.com/help/releases/R2012a/techdoc/ref/matlab.mixin.copyableclass.html

http://www.mathworks.com/help/releases/R2012a/techdoc/ref/matlab.mixin.copyable.copy.html

nikolaus...@googlemail.com

unread,
Oct 30, 2019, 12:30:26 PM10/30/19
to
On Thursday, 6 August 2009 18:53:02 UTC+2, Guillaume Perrault Archambault wrote:
> I need to make a deep copy of a hande object. Is there any easy way to do this in R2009a?

as an inspiration:






% NK
classdef DeepCopyable < matlab.mixin.Copyable

methods
% this does work for immutable/private/protected props..
% but not for transients
function cpObj = makeBruteCopy(obj) %#ok<MANU>
save('bruteCopyTempObj.mat','obj')
tmp = load('bruteCopyTempObj.mat');
cpObj = tmp.obj;
delete('bruteCopyTempObj.mat')
end

% this works only for publicly settable props..
function cpObj = deepCopy(obj)
% Make a shallow copy
cpObj = obj.copy;
% copy all sub Copyables too
obj.copyAllSubCopyables(obj,cpObj,'deep');
end
end

methods (Access = private)
function copyAllSubCopyables(obj,cpObj,shallowOrDeep)
assert(ismember(shallowOrDeep,{'shallow','deep'}))
mc = metaclass(obj);
props = properties(obj);

% order might be critical (when one prop depends on another being set already)
while ~isempty(props)
prop = props{1};
meta = mc.PropertyList(strcmp(prop,{mc.PropertyList.Name}));
if ~strcmp(meta.SetAccess,'public')
props(1) = [];
continue
end
if meta.Dependent && (isempty(meta.SetMethod) || isempty(meta.GetMethod))
props(1) = [];
continue
end
try
if isa(obj.(prop),'DeepCopyable')
% Make a copy of the prop object
switch shallowOrDeep
case 'shallow'
cpObj.(prop) = obj.(prop).copy;
case 'deep'
cpObj.(prop) = obj.(prop).deepCopy;
end
end
props(1) = [];
catch
if numel(props)>1
props = [props(2:end); props(1)]; % send to bottom
else
props(1) = [];
continue
end
end
end
end
end
end

nikolaus...@googlemail.com

unread,
Oct 30, 2019, 12:33:21 PM10/30/19
to
i ended up using the BruteCopy mostly ...

nikolaus...@googlemail.com

unread,
Nov 1, 2019, 4:38:26 AM11/1/19
to
On Wednesday, 30 October 2019 17:33:21 UTC+1, nikolaus...@googlemail.com wrote:
> i ended up using the BruteCopy mostly ...

correction:

obj.copyAllSubCopyables(obj,cpObj,'deep');

is of course

obj.copyAllSubCopyables(cpObj,'deep');
0 new messages