1. Technology

Shallow Copy versus Deep Copy

What they are and how to you code them.

By

Male office worker at workstation, hand on computer mouse
David Lees/Photographer's Choice/Getty Images
Updated June 30, 2014

You will find this pair of terms quite frequently in articles about programming:

Shallow Copy

and

Deep Copy

This article explains what they mean and shows you how to code both of them. But first: Basic Concepts!

Shallow Copy versus Deep Copy - What's the difference?

None of this really makes a difference unless you're dealing with objects as opposed to fundamental types. A more technical (and also more accurate) way to say this is that shallow copy versus deep copy is only meaningful with "reference types" and not with "value types". Value types are stored on the directly on the "stack" - a section of memory. Reference types are objects stored on the "managed heap". They get their name because the variable actually consists of a pointer in memory - a reference - to the location of the object on the heap. I cover all this in the short article Nullable Types Give Visual Basic the Ability to Say Nothing.

When you copy a value type, such as an Integer, you get what you expect: a copy. But a reference type is actually just a pointer to an area in memory; a "reference". And it can contain pointers to other areas in memory and so on. You might get a shallow copy, a deep copy, or just another pointer to the same memory location depending on the objects and methods you use. Here's a diagram of what a shallow copy looks like.

--------
Click Here to display the illustration
--------

And here's what a deep copy looks like. Depending on the references in the original object, a deep copy could include quite a lot.

--------
Click Here to display the illustration
--------

Since a shallow copy involves less work, you won't be surprised to learn that making a shallow copy is easy. Just use the MemberwiseClone function. It's so basic that it's a built in method in System.Object, so it's available all the time. Here's an example.

First, we need some objects to work with:


Public Class OriginalObject
    Property ReferredObject1 As Object
    Property ReferredObject2 As ComplexObject
End Class
Public Class ComplexObject
    Property ReferredObject3 As Object
End Class

These were coded to match the illustrations above, but to actually make it happen, the objects have to be instantiated and initialized.


Public myOriginalObject As New OriginalObject
Public myComplexObject As New ComplexObject

and


myOriginalObject.ReferredObject1 = "Orig RefObj1 Info"
myComplexObject.ReferredObject3 = "Orig RefObj3 Info"
myOriginalObject.ReferredObject2 = myComplexObject

To make a shallow copy, create a new object and call the MemberwiseClone function. This example shows the content of the objects before the shallow copy. Then a new value is placed in the copied objects. Finally, the content of the original and the copy is displayed to show that when the shallow copy is changed, the original changes too. They're pointing at the same object.


Dim ShallowCopy As New OriginalObject
Console.WriteLine("ReferredObject1: " &
    myOriginalObject.ReferredObject1)
Console.WriteLine("ReferredObject3: " &
    myComplexObject.ReferredObject3)
ShallowCopy = DirectCast(myOriginalObject, OriginalObject)
ShallowCopy.ReferredObject1 = "Shallow RefObj1 Info"
ShallowCopy.ReferredObject2.ReferredObject3 =
    "Shallow RefObj3 Info"
Console.WriteLine(vbCrLf & "myOriginalObject contents ...")
Console.WriteLine("ReferredObject1: " &
    myOriginalObject.ReferredObject1)
Console.WriteLine("ReferredObject3: " &
    myOriginalObject.ReferredObject2.ReferredObject3)
Console.WriteLine(vbCrLf & "... and the shallow copy contents ...")
Console.WriteLine("ReferredObject1: " &
    ShallowCopy.ReferredObject1)
Console.WriteLine("ReferredObject3: " &
    ShallowCopy.ReferredObject2.ReferredObject3)
' ReferredObject1: Orig RefObj1 Info
' ReferredObject3: Orig RefObj3 Info

' myOriginalObject contents ...
' ReferredObject1: Shallow RefObj1 Info
' ReferredObject3: Shallow RefObj3 Info

' ... and the shallow copy contents ...
' ReferredObject1: Shallow RefObj1 Info
' ReferredObject3: Shallow RefObj3 Info

This can be a bug if you're not clear about what you're doing. I documented this in the article Copying Reference Types.

A deep copy is another matter. There are several different techniques that can be used. In fact, although a deep copy is normally assumed to copy the primary object and the entire tree of referenced objects that might be present, the most comprehensive definition of "deep copy" is simply "not shallow". Since you implement the copy in your own code, you might write code that copies some referenced objects but not others. If you're looking at code that is supposed to make a deep copy, don't make any assumptions. When in doubt, check the code to see what it does.

The easiest (not always the best) way to make a deep copy is the "serialization" method. (The two classes, OriginalObject and ComplexObject have to be marked as <Serializable()> as well.


Using stream As New System.IO.MemoryStream()
    Dim formatter As New  _
        System.Runtime.Serialization.Formatters.Binary.BinaryFormatter()
    Dim DeepCopy As New OriginalObject
    Console.WriteLine("ReferredObject1: " &
        myOriginalObject.ReferredObject1)
    Console.WriteLine("ReferredObject3: " &
        myComplexObject.ReferredObject3)
    formatter.Serialize(stream, myOriginalObject)
    stream.Position = 0
    DeepCopy = formatter.Deserialize(stream)
    DeepCopy.ReferredObject1 = "Deep RefObj1 Info"
    DeepCopy.ReferredObject2.ReferredObject3 = "Deep RefObj3 Info"
    Console.WriteLine(vbCrLf & "myOriginalObject contents ...")
    Console.WriteLine("ReferredObject1: " &
        myOriginalObject.ReferredObject1)
    Console.WriteLine("ReferredObject3: " &
        myOriginalObject.ReferredObject2.ReferredObject3)
    Console.WriteLine(vbCrLf & "... and the deep copy contents ...")
    Console.WriteLine("ReferredObject1: " &
        DeepCopy.ReferredObject1)
    Console.WriteLine("ReferredObject3: " &
        DeepCopy.ReferredObject2.ReferredObject3)
    ' ReferredObject1: Orig RefObj1 Info
    ' ReferredObject3: Orig RefObj3 Info

    ' myOriginalObject contents ...
    ' ReferredObject1: Orig RefObj1 Info
    ' ReferredObject3: Orig RefObj3 Info

    ' ... and the deep copy contents ...
    ' ReferredObject1: Deep RefObj1 Info
    ' ReferredObject3: Deep RefObj3 Info
End Using

In this case, the original stays the same, but the copy still changes, indicating that they're separate objects. If you need to know more about serializing, try this article: All About Serializing in Visual Basic.

One reason that the serialize method might not be right for your code is that it's a relatively expensive way to do the job. If you know that the constructor for the object fully defines it (that is, the New method), then you can just call New on the object and populate it with whatever you need. You can use .NET Reflection methods (such as the FieldInfo method) to recurse through the original object and create an independent copy. This method has the advantage that you can examine, and even process the copied object as you create it. An example showing recursion can be found in Permutations, Recursion, and Traversing a Binary Tree

  1. About.com
  2. Technology
  3. Visual Basic
  4. Using VB.NET
  5. Shallow Copy Versus Deep Copy in VB.NET

©2014 About.com. All rights reserved.