-
Feb 4th, 2018, 05:24 PM
#1
Thread Starter
Hyperactive Member
Best practice - custom classes and assignments
I have just learned that using the = operator creates a reference to the original instance of the class rather than creating a copy. What I did to get around this is created a ShallowCopy function:
Code:
Imports System.ComponentModel
<TypeConverter(GetType(ExpandableObjectConverter)), Serializable()>
Public Class BoundingBox
Public Sub New()
LowerLeft = New Vertex
UpperRight = New Vertex
End Sub
Public Property LowerLeft As Vertex
Public Property UpperRight As Vertex
Public Function ShallowCopy() As BoundingBox
Dim tempBB As New BoundingBox
With tempBB
.LowerLeft = LowerLeft.ShallowCopy
.UpperRight = UpperRight.ShallowCopy
End With
Return tempBB
End Function
End Class
My question...What is best practice regarding custom classes and creating copies that do not refer to the original instance data?
Thanks,
Eric
--------------------------------------------------------------------------------------------------------------------
VB.net/C# ... Visual Studio 2019
"None of us are as smart as all of us."
-
Feb 4th, 2018, 05:36 PM
#2
Re: Best practice - custom classes and assignments
Pretty much that. Usually it's called .Clone, but I prefer the name you gave as it's plain that it's a shallow copy and not a deep copy.
Because every class is different and all cases are different, there's no one good way to do this sort of thing.
-tg
-
Feb 4th, 2018, 06:18 PM
#3
Re: Best practice - custom classes and assignments
That's not a shallow copy though. That's a deep copy. A shallow copy is a new object with all the same property/field values as the original, i.e. any reference type properties/fields in the new object will refer to the same objects as the original. The fact that you are making copies of the Vertex objects as well means that you're creating a deep copy.
-
Feb 5th, 2018, 09:00 AM
#4
Re: Best practice - custom classes and assignments
Another best practice:
Professionals always put the parameter list on their method calls, even if the list is empty, to help distinguish method calls from properties:
Code:
' Do this:
left.ShallowCopy()
' Not this:
left. ShallowCopy()
I was about to argue with JMC that this is a shallow copy, because at first glance your code confused me and I thought I was looking at 2 property accesses, not 2 method calls.
This answer is wrong. You should be using TableAdapter and Dictionaries instead.
-
Feb 5th, 2018, 10:25 AM
#5
Re: Best practice - custom classes and assignments
I'm still not sure whether it is deep or shallow. If Vertex is a structure, then it is deep, but I'm not familiar with a structure called Vertex, and a quick Google didn't show anything obvious. There are several things called Vertex, so I don't know what that Vertex object is. If it's a class, then it isn't deep, but it isn't really shallow, either. You have a new object that would hold references to the same items found in some other object. So, two objects....entangled, which doesn't seem like what was desired. If Vertex is a structure, then all is well, it's just a deep copy.
My usual boring signature: Nothing
-
Feb 5th, 2018, 10:44 AM
#6
Re: Best practice - custom classes and assignments
Originally Posted by Shaggy Hiker
I'm still not sure whether it is deep or shallow. If Vertex is a structure, then it is deep, but I'm not familiar with a structure called Vertex, and a quick Google didn't show anything obvious. There are several things called Vertex, so I don't know what that Vertex object is. If it's a class, then it isn't deep, but it isn't really shallow, either. You have a new object that would hold references to the same items found in some other object. So, two objects....entangled, which doesn't seem like what was desired. If Vertex is a structure, then all is well, it's just a deep copy.
You have to take a walk to figure out why it's deep.
ShallowCopy() does this:
- Create a new instance of this class.
- Call ShallowCopy() on the left.
- Call ShallowCopy() on the right.
So since ShallowCopy() creates a new instance, calling it on the left and right instances creates two new instances. Hence, it's named wrong.
This answer is wrong. You should be using TableAdapter and Dictionaries instead.
-
Feb 5th, 2018, 10:54 AM
#7
Re: Best practice - custom classes and assignments
Originally Posted by Shaggy Hiker
If it's a class, then it isn't deep, but it isn't really shallow, either.
It's either shallow or it's deep. There are no other options. A shallow copy is one where you create a new instance and then simply assign property/field values from the original to the copy. If you want to create an actual shallow copy then you should call MemberwiseClone. Anything else is a deep copy. It doesn't matter how deep the copy is; if it's not shallow then it's deep. In this case, the code that creates the copy of the BoundingBox class doesn't simply assign LowerLeft and UpperRight property values of the original to the copy. It creates a (seemingly shallow, but maybe not) copy of the Vertex objects from the original and assigns those to the properties of the copy, thus the copy of the BoundingBox class is deep.
Last edited by jmcilhinney; Feb 5th, 2018 at 10:57 AM.
-
Feb 5th, 2018, 11:17 AM
#8
Re: Best practice - custom classes and assignments
Originally Posted by jmcilhinney
It's either shallow or it's deep. There are no other options.
Actually there's a third option where you do some shallow work and some deep work Why? Generally by mistake.
If you want to create an actual shallow copy then you should call MemberwiseClone.
In general you want to write your own cloning code. Reflection-based copying of values is slower than direct assignments, and the performance burden can really add up. This is part of why the rules for creating structs very strongly recommend keeping them small, because all the automatic copy-by-values they can incur can be a problem. That's the reason why reference semantics exist at all!
This answer is wrong. You should be using TableAdapter and Dictionaries instead.
-
Feb 5th, 2018, 12:42 PM
#9
Re: Best practice - custom classes and assignments
Originally Posted by Sitten Spynne
Actually there's a third option where you do some shallow work and some deep work Why? Generally by mistake.
That was what I was getting at. After all, it doesn't really matter what we call it, what matters is whether what is happening is what the OP wants to have happen. I assumed that at the end of the call, the OP expected to have a new object that was of the same type as the original, had the same values, but always had copies of the values, without any shared references between them. Depending on what Vertex is, and what they actually want the result to be, I'm not sure they are getting from that function what they want to get from the function.
My usual boring signature: Nothing
-
Feb 5th, 2018, 08:45 PM
#10
Re: Best practice - custom classes and assignments
Originally Posted by Sitten Spynne
Actually there's a third option where you do some shallow work and some deep work
The way I've read it, a shallow copy is one where all property/field values are assigned directly from the old to the new and a deep copy is anything else. What you're describing as a combination of the two is actually still a deep copy. Any depth anywhere makes it deep. How deep and how widespread that depth is irrelevant to that classification.
-
Feb 5th, 2018, 09:04 PM
#11
Re: Best practice - custom classes and assignments
I have always thought that a shallow copy was just a copy of the reference. Anything beyond that is some form of deep copy, and since it can take on just about any form, that is the reason why no standard deep copy of reference types is possible.
My usual boring signature: Nothing
-
Feb 6th, 2018, 08:02 AM
#12
Re: Best practice - custom classes and assignments
Originally Posted by jmcilhinney
The way I've read it, a shallow copy is one where all property/field values are assigned directly from the old to the new and a deep copy is anything else. What you're describing as a combination of the two is actually still a deep copy. Any depth anywhere makes it deep. How deep and how widespread that depth is irrelevant to that classification.
That makes the definition of "deep copy" worthless, IMO, but you're probably right because what I remember of the commentary about ICloneable is, "We can't get anyone to agree on what the definition of 'clone' means so we wish we hadn't added this interface at all and our internal guideline became "don't use it"."
This answer is wrong. You should be using TableAdapter and Dictionaries instead.
-
Feb 6th, 2018, 05:38 PM
#13
Re: Best practice - custom classes and assignments
Originally Posted by Sitten Spynne
That makes the definition of "deep copy" worthless, IMO
I hear what you're saying, but I'm not sure that I agree. If "deep copy" meant something more specific than "a copy that isn't shallow" then we'd still need other names for the rest of the things that "deep copy" currently covers. If a deep copy was, by definition, a copy where each property/field value was copied then we'd still need another name/description for a copy where some property/field values were copied and others were assigned directly. We'd also need another name where some or all of the property/field values were themselves not shallow copies. Personally, I would say that it's just as easy to know that a shallow copy means that no reference property/field values are duplicated and a deep copy means that at least one is and if you care which are then it's up to you to check to find out.
-
Feb 6th, 2018, 06:47 PM
#14
Re: Best practice - custom classes and assignments
What I mean is I want three definitions:
- Shallow copy: reuses references thus changes in referenced things will impact both copies.
- Deep copy: new instances of everything so no changes to either copy will affect the other.
- Copy: Check the documentation for semantics.
I don't have a use for words with adjectives in front of them if the adjectives don't imply something different from when the word had no adjectives.
This answer is wrong. You should be using TableAdapter and Dictionaries instead.
-
Feb 6th, 2018, 07:48 PM
#15
Re: Best practice - custom classes and assignments
Originally Posted by Sitten Spynne
Deep copy: new instances of everything so no changes to either copy will affect the other.
Would that distinguish between deep copies where the new instances were shallow copies and deep copies where the new instances were deep copies?
-
Feb 6th, 2018, 08:49 PM
#16
Re: Best practice - custom classes and assignments
I was going to vehemently disagree but I came up with an example where you win.
In the contexts I'm used to discussing this, safe concurrency is the concern. If I'm trying to make a copy of an object graph so I can give it to another thread and I don't want it to be able to mess up my original, I have to go out of my way to make sure the graphs of object A and object A' have no overlap. That's what I mean when I ask for a deep copy, and if I get anything less the copy isn't sufficient for my needs.
But when I talked about an example, I realized it's less important that "every object instance is a new copy" and more important that "I can't change the clone in a way that impacts the parent". If we have immutable reference members, what was once a shallow copy becomes deep.
Imagine "clone a button" meaning, for efficiency, something less than a deep clone. Obviously we need to call CreateWindow() and get a new hWnd. Various properties like size and location are going to be copies from being value types. But what about, say, the Font? Deep down, that's another thing with a handle, so if I don't intend on changing anything about it I probably don't want to create a new instance.
But it turns out if I want to change anything, I have to create a new instance anyway, because Font is immutable. I think they did this to save you from the disaster that might happen if you grab, say, the system default Font and try to change something about it. Anyway, the point is even if A and A' share the same reference to a single Font object, there's no way I can change the font of A' in a way that affects A. So that copy becomes "deep enough", and the nitpick that I didn't recreate the Font object is irrelevant.
Still, if we're talking about mutable reference members, the only way to satisfy the requirement of "deep copy" is to deep clone those. There's a lot of reasons why we're desperately trying to get syntax sugars for immutable "record types" in C#. It helps us get things done faster and safer.
This answer is wrong. You should be using TableAdapter and Dictionaries instead.
-
Feb 6th, 2018, 09:08 PM
#17
Re: Best practice - custom classes and assignments
I think that, regardless of the labels used, the takeaway is that cloning/copying is not a straightforward proposition and you should always have your wits about you, whether you're doing the implementing or using someone else's implementation. I think that we probably agree on that, even if the detail of the labelling may be a minor point of contention.
I think that another thing we agree on is that a shallow copy definitely is something specific and the example used in this thread appears not to satisfy the requirements of a shallow copy.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|