18

I had to delve into some VB6 code recently and I saw this pattern all over the place:

dim o as obj
set o = new obj

Why not this?

dim o as new obj

I remember from 15 years ago that there was a good reason for this, but I can't remember what it was now. Anyone remember? Is the reason still valid?

AngryHacker
  • 59,598
  • 102
  • 325
  • 594
  • Hmm, interesting, I was coding in VB6 for 3 years and what I remember is that the two are perfectly correct. – Wiktor Zychla Nov 13 '11 at 21:08
  • 1
    `dim o as new obj` is instantiated on first access, not before. Thus each property/method call on it has an overhead of checking the variable for `Nothing`. – wqw Nov 13 '11 at 22:11
  • @wqw Each property has the overhead of checking for Nothing even after the object has been instantiated or just the first time? – AngryHacker Nov 13 '11 at 22:18
  • 2
    @AngryHacker Yes, because you can't access the object's properties _at all_ unless the object is "Not Nothing." So _every_ access has an implied "If obj Is Nothing Then Set obj = New MyObj" in front of it. – JeffK Nov 14 '11 at 15:04
  • @wqw lets not forget that once used in a loop, the "New obj" method will not destroy and recreate the obj, however if you do "Dim o As obj" & "Set o = New obj" then every time this sequence runs, it will destroy and recreate the "o" variable. Especially if the obj is a Collection type, and it's not destroyed and recreated (as would be when only doing a "Dim o As New Collection"), every time you add items to the Collection ("o" in this case, when in a loop) it will just keep re-adding the items to the Collection & you'll have stale data from the previous loop, big difference. See my answer. – Erx_VB.NExT.Coder Sep 04 '12 at 05:18
  • @wqw Also forgot to mention, if you are not running in a loop, you can encounter the same problem if this is declared / defined in a static function, or if the Collection is defined as static anywhere in your program, you will have stale data in your obj or Collection, especially if you are just adding items and expecting the "As New Collection" to recreate your Collection/obj (because it won't). – Erx_VB.NExT.Coder Sep 04 '12 at 05:24

4 Answers4

25

There may be other reasons but in VB6 using the New keyword when you Dim an object can cause unexpected results because VB will instantiate the object whenever it is referenced.

Dim objMyObject as New SomeObject

Set objMyObject = Nothing   ' the object is nothing

If objMyObject Is Nothing Then  ' referencing the object instantiates again
   MsgBox "My object is destroyed"  ' what you would probably expect
Else
   MsgBox "My object still exists"
End If
Cemafor
  • 1,633
  • 12
  • 27
jac
  • 9,666
  • 2
  • 34
  • 63
  • 1
    This is the exactly the reason why. – RS Conley Nov 14 '11 at 13:39
  • 6
    This answer is going in the right direction, but possibly not the best wording? I would not use *unpredictable*. The results are entirely *predictable* but often *unexpected* to most developers. The results can also mean that programming errors cause subtly wrong behaviour at runtime, rather than a nice simple exception "Object variable not set" – MarkJ Nov 14 '11 at 15:20
  • @MarkJ You made an excellent point, and I edited the answer accordingly – jac Oct 11 '12 at 14:02
7

This question touches on one of the many reasons that experienced programmers really dislike VB6. The New keyword changes the way the declared variable works. For instance:

Dim MyObject As MyClass
Set MyObject = New MyClass
Set MyObject = Nothing
Call MyObject.MyMethod()

... throws a runtime exception, while this:

Dim MyObject As New MyClass
Set MyObject = Nothing
Call MyObject.MyMethod()

... does not. Personally, if I go to the effort of setting a variable to Nothing, then referencing it again is almost certainly an error and I'd really like the program to crash, thank you very much. It's particularly important in the case where the class allocates resources in the initializer (constructor) and needs to get rid of those in the destructor. It's reasonably easy to write code that incorrectly references variable set to Nothing, perhaps when you want to check a result value or something. Doing this could cause the class to be instantiated again, grabbing all the unnecessary resources.

The reason for this weird behavior is so that VB6's forms (which are classes) work the way a novice would expect them to work. There's an implicitly declared global variable with the same name and type as each defined form, so:

Call frmMain.Show

... doesn't crash. This is the same behavior. It's really doing:

If frmMain Is Nothing Then
    Set frmMain = New frmMain
End If
Call frmMain.Show

This very much goes against what we're used to in other object oriented languages, so, in my opinion it's a bad idea. It's trying to hide the fact that MyObject is a reference type, and yet, when you write something like this (without using Set):

MyObject = New MyClass

... then you get a runtime exception instead of a compiler error because you didn't use the Set command. The compiler knows it's a reference type... why do I have to use Set, and even if I do, why not tell me about it sooner?

At any rate, to answer your question, you rarely want the behavior implied by using the Dim ... New syntax because you want to control the construction and destruction of objects. In fact, the only time it would ever make sense is in the construction of global singleton objects (such as frmMain above) where you just want the syntactic sugar. I would argue that global singletons are a bad idea anyway, so if I could turn off the ability to use the Dim ... New syntax, I would.

Scott Whitlock
  • 13,739
  • 7
  • 65
  • 114
  • 1
    Of all the many great reasons there are to not like vb6, I'd say this one is hardly even worth mentioning, haha – Brandon Moore Nov 15 '11 at 08:09
  • @Mat'sMug fair enough about the IDE but attributes like that are essentially invisible to VB6 programmers. Actually, are they even documented anywhere? – StayOnTarget Dec 18 '17 at 12:56
6

Here's another caveat:

For x = 1 to 100
   dim obj as new MyObject

   'Do something with obj
Next

You might expect that a new object is instantiated 100 times, but you'll find that it only gets instantiated the very first time. This one caught me off guard long ago.

I still use this notation all the time though. Just make sure you know the behavior.

Brandon Moore
  • 8,590
  • 15
  • 65
  • 120
2

I wanted to add to Brandon Moore's answer...

So continuing from the loop...

For x = 1 to 100
  Dim obj as New Collection
  obj.Add "New String Number " & x
Next x

Even though you've added say 20 items to obj when x = 1, when x = 2 all those 20 items will still be there! whereas, if you did set obj= new myObject then it would not! This is the most significant reason, as i once got caught out in this in a big looping area in my code, stuff was being added throughout the program and I had no idea why, nothing was being deleted or reset.

So, If instead of:

  Dim obj as New Collection

You wrote the foilowing:

  Dim obj as Collection
  Set obj = New Collection

Then you would have the obj Collection being reset every single time, which is probably what you want, but if you only want it to set Once, then use the As New Collection method. But, if you jsut wanted to set it once, you'd probably put it outside the loop.

Also, if you are not running in a loop, but the variable (Collection) is defined in a static function, or is defined with the static keyword, the exact same thing applies, not running the Set obj = New Collection will ensure you have stale data from your last use of the obj/Collection, which can be very bad.

So, in conclusion, the two methods are actually very different (and can have different behaviour)!

Erx_VB.NExT.Coder
  • 4,838
  • 10
  • 56
  • 92