'''[http://www.tcl.tk/man/tcl/TclCmd/copy.htm%|%oo::copy]''', a [Tcl commands%|%built-in] [Tcl] command, creates a duplicate of a [TclOO] object. ** Documentation ** [http://www.tcl.tk/man/tcl/TclCmd/copy.htm%|%official reference]: ** Synopsis ** : '''oo::copy''' ''sourceObject'' ?''targetObject''? ?''targetNamespace''? ** Description ** '''oo::copy''' creates a new [oo::object%|%object] and copies the configuration of ''sourceObject'' to it, after which it calls the '''``''' method of the new object. The default implementation of that method in the [oo::object] class copies [procedure%|%procedures] and [variable%|%variables] from the source object's [namespace], but does ''not'' copy any traces or [command%|%commands] implemented in [C]. Objects can potentially refuse to be duplicated, generating an [error] instead. Generating an error from the '''``''' method counts as refusal. '''Things copied''': all variables and procedures in the namespace of ''sourceObject'': commands that are not procedures are not copied. [oo::objdefine%|%exported methods]: [oo::objdefine%|%forwarded methods]: [oo::objdefine%|%mixin classes]: [namespace export%|%exported procedures]: '''Things not copied''' commands in ''sourceObject'' that are not [proc%|%procedures]: The [namespace unknown] command for a namespace: [namespace ensemble] of ''sourceObject'': TclOO itself doesn't create a namespace ensemble on the namespace that backs ''sourceObject'', but if one does exist, it doesn't get copied. [trace]s: Neither traces on variables nor traces on commands are copied. ** Determining What is Copied ** The script below runs a test to see what attributes of an object and its underlying namespace are copied. ====== #! /bin/env tclsh proc examine object { variable tests puts [list {what is copied for} $object] set ns [$object eval {namespace current}] namespace eval ns1 [ list namespace import ${ns}::export1] set results {0 yes 1 no} foreach {label script} $tests { set copts {} puts [list $label [dict get $results [ catch $script cres copts]]] #puts $copts } $object forward1 } ::oo::class create c1 { method mixin1 {} {} } proc p1 args {} ::oo::object create one ::oo::objdefine one { export eval method hi args { } method delete1 {} {} method setup {} { namespace eval [self namespace] { namespace export export1 namespace path [list {*}[namespace path] ::tcl::mathfunc] proc export1 {} {} proc unknownproc args {} namespace ensemble create -map {ensemble1 export1} namespace unknown unknownproc } } deletemethod delete1 forward forward1 p1 mixin -append c1 } variable tests { {namespace unknown} { $object eval nosuchproc } {method export} { namespace eval ns1 export1 } {method forward} { $object forward1 } {object mixin} { $object mixin1 } {namespace ensemble} { $ns ensemble1 } {namespace path} { if {{::tcl::mathfunc} ni [namespace eval $ns {namespace path}]} error } } one setup ::oo::copy one two examine two ====== ** Wrapper That Respects [namespace import%|%Imported] [proc%|%Procedures] ** `[oo::object] ` copies aliased procedures in the origin namespace over to the new namespace as native procedures. The following drop-in replacement changes that behaviour so that imported procedures are imported procedures in the new namespace as well. The code below is not necessarily recommended, as overriding `` in a subclass is the recommended way of getting this behaviour. ====== rename copy oocopy proc copy {sourceObject args} { set from [uplevel [list namespace which $sourceObject]] set fromns [info object namespace $from] if {[string range $fromns end-1 end] eq {::}} { set fromns [string range $fromns 0 end-2] } set to [uplevel [list [namespace current]::oocopy $from {*}$args]] set tons [info object namespace $to] foreach proc [info procs ${tons}::*] { set tail [namespace tail $proc] if {[namespace origin ${fromns}::$tail] ne "${fromns}::$tail"} { #For imported procedures ::oo::copy doesn't import the procedure #but creates an entirely new equivalent procedure in the new #namespace. This is probably not what's desired. Delete the proc #that oo::copy made so that copycommands can just make an #equivalent import rename $proc {} } } copycommands $fromns $tons my return $to } ====== <> Command | TclOO