Copying objects: Difference between revisions
mNo edit summary |
|||
(4 intermediate revisions by one other user not shown) | |||
Line 6: | Line 6: | ||
and if a contained object itself contains objects, deep copy copies those references and objects, and if any of those objects have contained objects, deep copying continues like this until the chain of objects contained in contained objects is exhausted. | and if a contained object itself contains objects, deep copy copies those references and objects, and if any of those objects have contained objects, deep copying continues like this until the chain of objects contained in contained objects is exhausted. | ||
For example, if a simple object (%S) contains multiple variable members, one of which is an object variable(%c, which references an object that has no contained object variables), | For example, if a simple object (<code>%S</code>) contains multiple variable members, one of which is an object variable(<code>%c</code>, which references an object that has no contained object variables), | ||
a shallow copy produces a matching object with matching variable members, including %c. | a shallow copy produces a matching object with matching variable members, including <code>%c</code>. | ||
Remembering that %c is a reference and not the actual object, the shallow copy of an object that contains an object pointer thus produces a matching object and object pointer. | Remembering that <code>%c</code> is a reference and not the actual object, the shallow copy of an object that contains an object pointer thus produces a matching object and object pointer. | ||
A deep copy of %S produces two objects: one object that matches %S with a pointer to %c, and one object that is a replica of the actual object that %c references. | A deep copy of <code>%S</code> produces two objects: one object that matches <code>%S</code> with a pointer to <code>%c</code>, and one object that is a replica of the actual object that <code>%c</code> references. | ||
For simple objects (objects without contained objects), a shallow copy is the same as a deep copy. | For simple objects (objects without contained objects), a shallow copy is the same as a deep copy. | ||
'''Shallow copies''' may be most useful with collections, say for sorting an <var>Arraylist</var>. To preserve the original order of a given <var>Arraylist</var>, you make a shallow copy of the collection to avoid the expense of making copies of any <var>Arraylist</var> objects | '''Shallow copies''' may be most useful with collections, say for sorting an <var>Arraylist</var>. To preserve the original order of a given <var>Arraylist</var>, you make a shallow copy of the collection to avoid the expense of making copies of any <var>Arraylist</var> objects; then you sort the shallow copy on whatever criterion you want. A shallow copy method may also in turn be used as a building block for constructing copy methods of arbitrary complexity for hierarchical object structures. | ||
'''Deep copies''' provide a facility for copying an entire arbitrarily complex object forest, and they are probably more widely useful than shallow copies. For example, deep copying is essential internally in <var class="product">SOUL</var> system methods that let you pass an object between two threads and reference the object on both threads. | '''Deep copies''' provide a facility for copying an entire arbitrarily complex object forest, and they are probably more widely useful than shallow copies. For example, deep copying is essential internally in <var class="product">SOUL</var> system methods that let you pass an object between two threads and reference the object on both threads. | ||
Line 38: | Line 38: | ||
<li>Not all objects that it is possible to copy should be allowed to be copied. As a general rule of thumb, any object that holds information external to its own public or private variables is a good candidate for not being allowed to be shallow or deep copyable. For example, consider a class that is used to manage a record. Object private variables might be dependent on the contents of the record, but if you have multiple instances of the object and the class updates the record, the private variables in one instance could end up out of synch with the record due to updates by another source. | <li>Not all objects that it is possible to copy should be allowed to be copied. As a general rule of thumb, any object that holds information external to its own public or private variables is a good candidate for not being allowed to be shallow or deep copyable. For example, consider a class that is used to manage a record. Object private variables might be dependent on the contents of the record, but if you have multiple instances of the object and the class updates the record, the private variables in one instance could end up out of synch with the record due to updates by another source. | ||
<li>For an object to be shallow or deep copyable, all | <li>For an object to be shallow or deep copyable, all its contained objects must themselves be shallow or deep copyable, respectively. The compiler ensures that if an object's class contains an object member (or an object member contained in that object member's "descendant objects,") whose class definition does not specify <code>Allow Copy</code> or <code>Allow DeepCopy</code>, the original object is not shallow or deep copyable, respectively.<br />The <var class="product">SOUL</var> system classes that are shallow or deep copyable are specified in the following section. | ||
<li>Allow <var>DeepCopy</var> does not imply <var>Allow Copy</var>. However, [[#Inheritance and polymorphism|inheritance]] permits an <var>Allow Copy</var> designated class to have its own <var>Copy</var> method defined, and it permits an <var>Allow DeepCopy</var> designated class to have its own <var>DeepCopy</var> method. | <li>Allow <var>DeepCopy</var> does not imply <var>Allow Copy</var>. However, [[#Inheritance and polymorphism|inheritance]] permits an <var>Allow Copy</var> designated class to have its own <var>Copy</var> method defined, and it permits an <var>Allow DeepCopy</var> designated class to have its own <var>DeepCopy</var> method. | ||
Line 46: | Line 46: | ||
<li>If a user-defined class already has a method called <code>Copy</code> (or <code>DeepCopy</code>), it does not conflict with the <var>Object</var> class <var>Copy</var> (or <var>DeepCopy</var>) method. However, due to inheritance, the user class <code>Copy</code> definition must specify that it is an override. | <li>If a user-defined class already has a method called <code>Copy</code> (or <code>DeepCopy</code>), it does not conflict with the <var>Object</var> class <var>Copy</var> (or <var>DeepCopy</var>) method. However, due to inheritance, the user class <code>Copy</code> definition must specify that it is an override. | ||
</ul> | </ul> | ||
===Example=== | ===Example=== | ||
The following fragment sketches a deep copyable user class that contains two objects. The contained objects contain no further object references, but they are both subject to update from an external source. The class designer wants instances of the class to be deep copyable only, so class object copies are insulated from external changes to its constituent objects. A shallow copy of a class object, with pointers to its contained objects, would be modified upon changes to its contained objects. | The following fragment sketches a deep copyable user class that contains two objects. The contained objects contain no further object references, but they are both subject to update from an external source. The class designer wants instances of the class to be deep copyable only, so class object copies are insulated from external changes to its constituent objects. A shallow copy of a class object, with pointers to its contained objects, would be modified upon changes to its contained objects. | ||
Line 89: | Line 89: | ||
<ul> | <ul> | ||
<li>All [[Enumerations|enumerations]] | <li>All [[Enumerations|enumerations]] | ||
<li>All [[Collections|collections]] | <li>All [[Collections|collections]] (see qualifying "Note," below this list) | ||
<li><var>[[CharacterMap class|CharacterMap]]</var> | <li><var>[[CharacterMap class|CharacterMap]]</var> | ||
<li><var>[[Json class|Json]]</var> | |||
<li><var>[[RandomNumberGenerator class|RandomNumberGenerator]]</var> | <li><var>[[RandomNumberGenerator class|RandomNumberGenerator]]</var> | ||
<li><var>[[Record class|Record]]</var>, <var>[[Recordset class|Recordset]]</var>, and <var>[[SortedRecordset class|SortedRecordset]]</var> | <li><var>[[Record class|Record]]</var>, <var>[[Recordset class|Recordset]]</var>, and <var>[[SortedRecordset class|SortedRecordset]]</var> | ||
Line 98: | Line 99: | ||
<li><var>[[XmlDoc class|XmlDoc]]</var> | <li><var>[[XmlDoc class|XmlDoc]]</var> | ||
</ul> | </ul> | ||
<p class="note"><b>Note:</b> Although collections themselves are deep copyable, a particular collection might contain references to non-deep-copyable objects, which disallows deep copy of that specific collection. </p> | |||
The following classes are deep copyable only: | The following classes are deep copyable only: | ||
<ul> | <ul> | ||
Line 103: | Line 106: | ||
<li><var>[[XmlNode class|XmlNode]]</var> | <li><var>[[XmlNode class|XmlNode]]</var> | ||
</ul> | </ul> | ||
For the following classes, no copy methods are implemented, typically because of their complexity or their dependence on information that is not held in the objects themselves: | For the following classes, no copy methods are implemented, typically because of their complexity or their dependence on information that is not held in the objects themselves: | ||
Latest revision as of 22:51, 24 January 2017
SOUL includes generic (Object class) methods for making copies of User Language class objects. "Shallow" and "deep" copying methods are available.
The shallow and deep types of copy differ only in how they handle contained objects: A shallow copy of an object includes a copy of the references to its contained objects. A deep copy includes the references to its contained objects and it includes a copy of the referenced object itself — and if a contained object itself contains objects, deep copy copies those references and objects, and if any of those objects have contained objects, deep copying continues like this until the chain of objects contained in contained objects is exhausted.
For example, if a simple object (%S
) contains multiple variable members, one of which is an object variable(%c
, which references an object that has no contained object variables),
a shallow copy produces a matching object with matching variable members, including %c
.
Remembering that %c
is a reference and not the actual object, the shallow copy of an object that contains an object pointer thus produces a matching object and object pointer.
A deep copy of %S
produces two objects: one object that matches %S
with a pointer to %c
, and one object that is a replica of the actual object that %c
references.
For simple objects (objects without contained objects), a shallow copy is the same as a deep copy.
Shallow copies may be most useful with collections, say for sorting an Arraylist. To preserve the original order of a given Arraylist, you make a shallow copy of the collection to avoid the expense of making copies of any Arraylist objects; then you sort the shallow copy on whatever criterion you want. A shallow copy method may also in turn be used as a building block for constructing copy methods of arbitrary complexity for hierarchical object structures.
Deep copies provide a facility for copying an entire arbitrarily complex object forest, and they are probably more widely useful than shallow copies. For example, deep copying is essential internally in SOUL system methods that let you pass an object between two threads and reference the object on both threads.
The Object class copy methods
The Object class has two copy methods: Copy and DeepCopy. Both methods are functions without arguments that return a new instance of the method object to which they are applied.
%cop = %obj:Copy %dcop = %obj:DeepCopy
Where:
- %cop
- A shallow copy (member variable by member variable assignment) of method object %obj.
- %dcop
- A deep copy (member by member assignment plus duplication of any referenced objects) of its method object %obj.
- %obj
- A shallow or deep "copyable" SOUL object. The Public block of such an object's class must include the Allow Copy, AllowDeepCopy, or both keywords to make available the Copy, DeepCopy, or both methods. You specify these keywords as you would a method declaration (see Declaration blocks), but the method is provided by the system rather than the class programmer. Whether an object is shallow or deep copyable is discussed further below.
Usage Notes
- Not all objects may be copied. For example, a SOUL Socket object is an example of a class that is not shallow or deep copyable, because it has a significant amount of information or state that is not held in the object itself. And what does it mean to copy a network connection?
- Not all objects that it is possible to copy should be allowed to be copied. As a general rule of thumb, any object that holds information external to its own public or private variables is a good candidate for not being allowed to be shallow or deep copyable. For example, consider a class that is used to manage a record. Object private variables might be dependent on the contents of the record, but if you have multiple instances of the object and the class updates the record, the private variables in one instance could end up out of synch with the record due to updates by another source.
- For an object to be shallow or deep copyable, all its contained objects must themselves be shallow or deep copyable, respectively. The compiler ensures that if an object's class contains an object member (or an object member contained in that object member's "descendant objects,") whose class definition does not specify
Allow Copy
orAllow DeepCopy
, the original object is not shallow or deep copyable, respectively.
The SOUL system classes that are shallow or deep copyable are specified in the following section. - Allow DeepCopy does not imply Allow Copy. However, inheritance permits an Allow Copy designated class to have its own Copy method defined, and it permits an Allow DeepCopy designated class to have its own DeepCopy method.
- For all Copy and DeepCopy methods (system or generic SOUL), the method object may be null (internally, it is defined with the AllowNull keyword). The output of a copy of a null object is a null object.
- If a user-defined class already has a method called
Copy
(orDeepCopy
), it does not conflict with the Object class Copy (or DeepCopy) method. However, due to inheritance, the user classCopy
definition must specify that it is an override.
Example
The following fragment sketches a deep copyable user class that contains two objects. The contained objects contain no further object references, but they are both subject to update from an external source. The class designer wants instances of the class to be deep copyable only, so class object copies are insulated from external changes to its constituent objects. A shallow copy of a class object, with pointers to its contained objects, would be modified upon changes to its contained objects.
class latitude public allow deepcopy ... end public ... end class latitude class longitude public allow deepcopy ... end public ... end class longitude class point public allow deepcopy property latitude is object latitude readonly property longitude is object longitude readonly ... end public private variable xlat is object latitude variable xlong is object longitude end private ... end class point %a is object point %b is object point %a = new ... do things with %a %b = %a:deepcopy ... do things with %b
Copy methods in SOUL system classes
The following system classes are shallow and deep copyable, that is, they include both Copy and DeepCopy methods. In the classes that contain no object members, the Copy and DeepCopy methods are the same:
- All enumerations
- All collections (see qualifying "Note," below this list)
- CharacterMap
- Json
- RandomNumberGenerator
- Record, Recordset, and SortedRecordset
- Screen
- Stringlist
- UserStatistics
- XmlDoc
Note: Although collections themselves are deep copyable, a particular collection might contain references to non-deep-copyable objects, which disallows deep copy of that specific collection.
The following classes are deep copyable only:
For the following classes, no copy methods are implemented, typically because of their complexity or their dependence on information that is not held in the objects themselves:
- All intrinsics
- All exceptions
- Daemon
- Dataset
- FastUnloadTask
- HttpRequest and HttpResponse (HTTP Helper)
- Journal
- LDAP
- PersistentObjectInfo
- RecordsetCursor
- Socket
- SortOrder
- SelectionCriterion
- StringTokenizer
- System and Subsystem
- XmlParser
- XmlNodelist
As described in The Object class copy methods, the presence or absence of the Copy and DeepCopy methods in the system classes affects the degree of copyability of any user-defined classes that contain objects of these system classes. A user class that contains a Daemon object, for example, is not deep copyable. A user class that contains a Stringlist, though, may be shallow or deep copied, subject to the copyability of the other members of the class.
The deep copyability of the individual SOUL system classes also determines the objects that are eligible to be used with system Daemon objects. Only objects that are deep copyable may be passed to and retrieved from Daemon objects, which may be called by a SOUL program to execute commands on a separate thread.