Fog Creek Software
Discussion Board




Dim As New

One of the most significant things I noticed in Joel's new article on VB6 & DAO was the following code :

Dim article As EArticle : Set article = New EArticle

rather than ...

Dim article As New EArticle

Now, this reminds me of a permanent religious war that follows me from job to job. I dislike Dim .. As New with a passion, for the following reasons :

* It makes code more difficult to read, in as much as you can't easily tell whereabouts an object will be initialised. Whereas if you explicitly create an object using Set, you know exactly where Class_Initialize is going to be fired, without any surprises. (And if you declare module level variables As New, that's even worse.)

* Somebody once told me using it can cause memory leaks due to bugs in the VB Virtual Machine.

Yet, most code I come across uses Dim ... As New everywhere. Maybe they all read Bruce McKinney's approval of it in Hardcore Visual Basic (see http://www.mvps.org/vb/hardcore/html/declarationswithnew.htm).

What are your thoughts, oh VB gurus?

Better than being unemployed...
Wednesday, January 08, 2003

I don't use VB anymore but when I did, I considered using Dim As New evil. There's the Class_Initialize reason you gave and there's also the fact that:

Dim article As New EArticle

If article Is Nothing Then
...

- always returns false, even if you *explicitly* set article to Nothing in the previous statement!

John Topley
Wednesday, January 08, 2003

Wait a minute! "Dim As New" is not evil, it is just different.
Generally, you want to use:

Dim X As Y: Set X = New Y

But there are some cases, when the Dim As New actually increases readability of your code. Heres one:

I have a class for reading and writing .ini-files. If you don't explicitly set the filename-property, it defaults to the expression 'App.Path & "\" & App.EXEName & ".ini"'

Thus, when I do "Global goSettings = New CIniFile" I won't get any surprises at all.

What about Singletons? Some Classes return the same object (for instance the top node of an object hierarchy) when instantiated. Those Classes can be Dim-ed as New.

I also allways Dim oFSO As New Scripting.FileSystemObject.

So there. And I bet that isn't bad programming practice!

Daren Thomas
Wednesday, January 08, 2003

In VB6 I always use a separate Dim and Set. Always seemed more sensible not to create it until you wanted it and were definitely going to use it. And I was aware of some problems that you could have. For procedure variables I typically declare all the variables at the top of the procedure and create instances as we go along.

In VB.NET I've started to follow what happens in C++ where procedural variables are quickly defined and created in code where they're needed. In c++ you've got the easy syntax:

MyClass MyObject = new MyClass(parms)

In VB you achieve the same thing with the wordy:

Dim MyObject As MyClass = new MyClass(parms)

Because of the 'Dim' statement it makes me feel like the dim and the assignment are two different things that maybe should for elegance be separated but in c++ it already seems more elegant and appropriate! However I prefer to define and use them in the same place because I was getting fed up with having a list of dozens of variables at the start of a procedure and trying to work out if they're still used anywhere after I'd reshaped the mud a bit. With the definitions in the code you would chop them out as you go along.

Gwyn Carwardine
Wednesday, January 08, 2003

I've found that Dim ... As New lines can generate errors that you can't catch.  My experience is:

On Error Goto MyErrorHandler
Dim fso as New FileSystemObject

MyErrorHandler: code will not run if VB cannot create the object, however:

On Error Goto MyErrorHandler
Dim fso as FileSystemObject
Set fso = New FileSystemObject

will work, even if creating the object doesn't.

ScottB
Wednesday, January 08, 2003

Daren Thomas wrote:

> I have a class for reading and writing .ini-files. If you
> don't explicitly set the filename-property, it defaults
> to the expression 'App.Path & "\" & App.EXEName & ".ini"'

> Thus, when I do "Global goSettings = New CIniFile" I
> won't get any surprises at all.

That would depend where goSettings is defined. If it's in an ActiveX DLL, you might not get any surprises, but a calling client might. They'd create an instance of some object in your DLL and then trip up for no obvious reason because they don't have permission to write files to wherever App.Path is. Note that the VB debugger will _not_ step to the goSettings declaration but just jump straight into CIniFile's Class_Initialize, so they'll sit around racking their brains for a few minutes wondering why the
debugger threw them on that line.

> What about Singletons? Some Classes return the same
> object (for instance the top node of an object
> hierarchy) when instantiated. Those Classes can be
> Dim-ed as New.

I'm not sure what you mean. Creating an instance of a class doesn't return anything. For singletons, I create a single Private instance of it in a module, initialize it in Sub Main, and create a global public function that returns a reference to this instance. This has the advantage that the object's instance is read-only ie: everybody can get a reference to it, but nobody can change that reference, intentionally or otherwise. Fortunately I've never had a situation where I've needed more than one singleton, so this never gets out of hand.

> I also allways Dim oFSO As New
> Scripting.FileSystemObject.

> So there. And I bet that isn't bad programming practice!

I wouldn't be so sure of that. Supposing the end user has a "bad" scrun.dll. Would you know exactly where in the code you'd trip up? What if six months later somebody else had to do a mod on your code. Would they be as wise?
I very much doubt it.

Better than being unemployed...
Wednesday, January 08, 2003

>Thus, when I do "Global goSettings = New CIniFile" I >won't get any surprises at all.

How does this increase readability? I'd rather you be consistent than save the odd line of code.

>What about Singletons? Some Classes return the same >object (for instance the top node of an object hierarchy) >when instantiated. Those Classes can be Dim-ed as New.

How does that help? If I inadvertently set your singleton to Nothing and then reference it, then I get a completely new instance to work with and not the original. I'd use a global function that creates a new instance or returns the existing instance if the singleton has already been instantiated.

>I also allways Dim oFSO As New >Scripting.FileSystemObject.

What's special about the FileSystemObject that merits it being an exception to your general rule?

>So there. And I bet that isn't bad programming practice!

I respectfully disagree!

John Topley
Wednesday, January 08, 2003

While we're discussing Dim As New / Set var = New, what's your preference for calling Set var = Nothing?  Doesn't VB do that for you when the variable goes out of scope?  Yet, I see tons of code that has:

Sub Foo
  Dim fso as FileSystemObject
  ...
  Set fso = New FileSystemObject
  ...
  Set fso = Nothing
End Sub

What's the use of setting the var to Nothing just as you exit the subroutine?

Bounty Hunter
Wednesday, January 08, 2003

VB 6.0 is suppoed to do it for you but its object reference counting is...not all it could be, so it's generally best to give the garbage collector a hand and do it explicitly.

John Topley
Wednesday, January 08, 2003

Also, you're explicitly mentioning in the code that you're finished with this object and want to destroy it, rather than assuming the garbage collector will do it for us (which isn't so easy to read).

(By the way, some of my other pet VB hates are using "dumb" collections (ie: Dim xyz As Collection rather than creating a collection class) and using the Hungarian wart "cls" for all object references.)

Better than being unemployed...
Wednesday, January 08, 2003

hm. I guess I will rethink my programming practices.

With Singletons I didn't meen my own classes. I use a Document Management framework (Panagon IDM from FileNET) which exposes a class Neighborhood. Objects of this type allways refer to the same instance, which can be used to get hold of other objects. So it doesn't really matter when it get's created.

The only reason I like Dim As New is because it's one line.

Dim oFSO as FileSystemObject: Set oFSO = New FileSystemObject

does the trick as well... so I will probably train myself to use that.

Daren Thomas
Wednesday, January 08, 2003

I understand the arguments for using Set, but I don't like how it creates bloat.  For instance see the following subs:

' without Set var = New and Set var = Nothing
Sub Foo
  On Error Goto ErrorHandler
  Dim fso as New FileSystemObject
  ' more code
  Exit Sub
ErrorHandler:
  ' error handling code
End Sub

' with Set var = New and Set var = Nothing
' * requires three extra lines, including redundancy in the error handler
Sub Foo
  On Error Goto ErrorHandler
  Dim fso as FileSystemObject
  ' more code
  Set fso as New FileSystemObject
  ' more code
  Set fso = Nothing
  Exit Sub
ErrorHandler:
  ' error handling code
  Set fso = Nothing
End Sub

If I'm sure I'm going to use an object I just use Dim var As New.  However, if what you say is true about On Error ignoring Dim var As New errors, then I may have to rethink that.

Bounty Hunter
Wednesday, January 08, 2003

Darn, I was hoping some one would have come up with a real smack on my brain, and come up with a  good argument for either case!

I tend to use the dim…New keyword, but on this issue, I am open to any, all ideas.

I would most enjoy being corrected on this one.

For me…it just a habit.

However, using the set ….new means your code does not have to initialize the instance of the object until you actually use it.

Since using the Set….New means YOU control when the object initializing occurs, I am thinking that my approach is has been the WRONG one all along!!

There is also a class initialize event that fires when you use the set….new.  So, again it would seem that the set…new is a MUCH better approach. (other wise the event fires when the sub loads…that is not good. You have no contorl when the class objects initizlie code runs).

Using the dim…new means that your class object code has to fire at that point. Darn, the more I think about this…the more I seem to be doing it the wrong way!!!

My problem is that I don’t use the initialize event in my class objects very often.

Bounty Hunter also did hint at some error handling issues., and that concept just might hold some real additional ideas.

So, I kind of have to vote for Joel’s example. 

In fact, in thinking about hits…My own use of dim…new should be held with a dim view (pun intended!!).

Albert D. Kallal
Edmonton, Alberta Canada
Kallal@msn.com

Albert D. Kallal
Wednesday, January 08, 2003

Well, "Dim x As New abc" is easier, in theory, to read in code, in the same way as C++'s "abc * p = new abc;"

The problem stems from the fact it doesn't do what you would expect it to do from experience in other languages.

(Another link : http://www.vb-faq.com/vb_commandments.asp - see number 5)

Better than being unemployed...
Wednesday, January 08, 2003

It is better to require that the object be explicitly instantiated because that prevents bugs arising from inadvertent instantiations after points where the objects are thought to have finished their lifetime.

obj.DoSomething will generate compile-time errors if it inadvertently occurs outside the known scope of the object, where the object was declared Dim obj as Classname.

However it won't generate compile-time errors if the object was declared Dim obj as New Classname. It will instead generate mysterious run-time errors.

Must be a manager
Wednesday, January 08, 2003

In VB6, Dim as New is evil because it's weird, and sometimes causes objects to rise from the dead.

In VB.NET, Dim as New is fine.

Dave Rothgery
Wednesday, January 08, 2003

Correction: the errors generated by Dim obj as Classname will be caught at run-time rather than compile-time, but the point is that errors will definitely be generated and will be obvious, rather than being subtle logic errors.

Must be a manager
Wednesday, January 08, 2003

Commandment V =Thou shalt not Dim as New

http://www.vb-faq.com/vb_commandments.asp

Matthew Wills
Wednesday, January 08, 2003

Bounty Hunter,

You claim that not using Dim As New adds bloat. But your argument is misleading. You make it seem that not using Dim As New requires more Set Variable = Nothing statements. This is not the case. The need for Set Variable = Nothing statements (in the example you show) has nothing to do with how you declare the variable. It has everything to do with whether or not you think VB will decrement the reference counter when the object variable goes out of scope.

I am not saying you should or shouldn't have the Set Variable = Nothing statement. What I am saying that to imply that the need for the statement is dependent on how you declare the variable (with or without Dim As New) is incorrect. This renders the foundation of your argument somewhat shaky.

Thanks

Matthew Wills
Wednesday, January 08, 2003

I see your point Matthew. 

VB upsets me.  If it has garbage clean up when objects go out of scope, then it should work correctly.  We should be able to rely upon it.  If it has a Dim As New, we should be able to use it in good faith, not follow the "5th commandment."

Bounty Hunter
Thursday, January 09, 2003

Not knowing Commandment V caused me some terrible headaches early on.  Check out this piece of code that demonstrates:

    Dim c1 As Collection
    Set c1 = New Collection
    Dim c2 As New Collection
   
    ' here both should print false
    ' because they both point to an instance
    Debug.Print "= Before ===="
    Debug.Print c1 Is Nothing
    Debug.Print c2 Is Nothing
   
    Set c1 = Nothing
    Set c2 = Nothing
   
    ' here c1 is nothing, but c2 is pointing
    ' to a new instance created by VB
    Debug.Print "= After ====="
    Debug.Print c1 Is Nothing
    Debug.Print c2 Is Nothing

When you "Dim as New" you're giving away your control of the object reference.  You're letting the runtime create an instance for you on the fly.  Sure you could use it...but not everybody can see the implications.

Richard Caetano
Thursday, January 09, 2003

Bounty Hunter,

<quote>
If it has a Dim As New, we should be able to use it in good faith
</quote>

The thing is that Dim As New works EXACTLY as documented. The problem is not that it doesn't work. It is that:

a) Alot of beginner programmers do not know how it works.
b) The way it works tends to produce more problems than it solves.

So, you can use it in good faith - assuming you understand how it works. But to be honest, once you understand how it works, its pretty rare you would want to use it anyway... ;-)

Seeya

Matthew Wills
Thursday, January 09, 2003

Ahh, here it is, the statement I was looking for:
  "The problem stems from the fact it doesn't do what you
  would expect it to do from experience in other languages."

Well, VB6 isn't other languages. I agree, the auto-instantiation effect of Dim As New is a bit odd and unexpected, but by now every VB programmer should know it and hence, no more surprices.

The key is expectation. What do you expect of your code? I expect my code to be readable and working as intended. If I have a CLibrary class with books, I would expect a new instance to return 0 books, like Debug.Assert aLibrary.books.count = 0.

The easiest way to achieve this is to have a class member inside CLibrary, like: Private itsBooks as New Collection.

When do you expect an object to die? When you are done, of course. I consider myself done when I don't use the object anymore. If the object dies at that point, fine. If I attempt to use it afterwards, then I am not done and the object shouldn't die.

I scope my objects' lifetimes to the scope they live in. So class member objects should die when the containing object dies. Method objects should die when leaving the method.

I use Dim As New most of the time. When I can't satisfy a unit test this way (mostly because it expects Nothing) then Dim As New won't work. So I think it's more a question on when not to use it than not using it at all.

Thomas Eyde
Tuesday, January 14, 2003

Thomas Eyde wrote :

"What do you expect of your code? I expect my code to be readable and working as intended."

and then

"When do you expect an object to die? When you are done, of course."

Those two statements contradict each other. How would you be able to tell "when you are done" from a glance in code if the OS is doing the destruction for you? You can't, so that can't make the code easy to read. If you have to make a mod six months later then the point at "when you are done" might shift, creating problems you didn't need to create in the first place.

Anyway, the more significant question is "When do you expect an object to be created?" That's a bit more difficult in this case. I'm just fed up of finding stupid Dim As New related bugs in legacy code, time and time again. That clearly indicates to me that it's an easy way to write bad code.

I maintain those who advocate Dim As New haven't done much bugfixing or maintenance programming, nor do they really appreciate memory allocation.

Better than being unemployed...
Tuesday, January 14, 2003

I should express my intentions clearer, I suppose. I am done when my method ends, or when my class goes out of scope. How do I know when that happens? It's easy on methods: End X or Exit X, where X is Sub, Property or Function. I expect my objects to be valid everywhere inside a method, except:

* The first line where it's used, I might have to create it
* The last line before End X, I might have to destroy it

So when do I expect it to be created? Before whenever I need it, that be as a Dim As New or = New in Class_Initialize.

I have only one need for not using Dim As New, and that is when I need to test on Nothing.

How do I know my code satisfies my intentions? By writing unit tests which expresses what my intentions are. How do I know where an object is created? By keeping every method very small so it's virtually impossible to miss what's happening.

I am using Dim As New as my preferred declaration/instantiation. I have no problems finding bugs. I maintain my own code all the time and take pride in doing so.

Thomas Eyde
Thursday, January 16, 2003

"I have no problems finding bugs. I maintain my own code all the time and take pride in doing so.”

Don’t forget that you have no problems finding bugs partly because you know what to expect.

But having explicit object creation and destuction in your code not only helps your colleagues, it also helps you, whether you are aware of it or not.
It helps your subconscious scan for information that you are looking for on a conscious level. They are the landmarks that help you find your way, and that you don’t even notice that are there, until they’re not. And you find yourself lost in a place that you may visit every day.

You won’t experience that effect, because you don’t count on those landmarks in the first place. You won’t feel the pain when they’re missing, but you also don’t experience the gains they provide. You decide whether your net effect is positive or not.

Practical Geezer
Friday, January 17, 2003

"They are the landmarks that help you find your way, and that you don’t even notice that are there, until they’re not"

What if no methods are not longer than 20 lines, or at least no longer than your monitor can show at once? In really short, cohesive methods you need no landmarks. It should be pretty obvious what's going on. Looking at 10 lines of code a "Dim As New" should be easy to spot.

The fact that it saves me one line and look cleaner makes it my preferred choice. As I probably wrote earlier, I let the circumstances decide when "Dim As New" is useless. Those circumstances are rare.

Thomas Eyde
Friday, January 24, 2003

*  Recent Topics

*  Fog Creek Home