The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

Visual Basic and New

Yesterday was a day when the high brass played programming just to show that their kung-fu was still up and alive.

He was confronting with a malfunctioning vb6 application (later he'll discover an ADO known half bug).
In the process he noticed a sentence like this

Dim rs as New ADODB.recordset.

He flamed like a dragoon insulting the resigned developer who orginally wrote the code. The he changed it with the following:

Dim rs as Object
Set rs = new ADODB.recordset

The two versions both worked. Why was it so deadly? I'm in BI and I'm not a very expert developer.
Sevenoaks Send private email
Thursday, October 05, 2006
I've not done VB6 for about three years, but I'll have a crack at this.

The first style is called implicit object creation and it declares and instantiates the object in one line. The second style is called explicit object creation. The advantage of it is that it lets you test the variable against Nothing, a test which will always fail for implicitly created objects. This is true even if you set the reference to Nothing in the line immediately preceding the test!

This is one of the reasons why I'm glad I haven't used VB6 for about three years.
John Topley Send private email
Thursday, October 05, 2006
In the first statement rs is a IRecordset type. It stores the value of a COM custom interface and subsequent calls use the interface directly.

rs.Close (VB) -> pRS->Close (C++)

In the second statement rs is a IDispatch type. Subsequent itnerface calls are handled through IDipatch::Invoke.

rs.Close (VB) -> pDisp->Invoke("Close", ...) (C++)

The first one has a better performance. However, the project must have the type library reference because VB needs to know the strucutre of the custom interface. The second one does not require type library reference.
Thursday, October 05, 2006
+1 to the other respondants

I believe that also:
> Dim rs as New ADODB.recordset

the 'New' can be delayed until the first method call on rs.

Set rs = nothing
effectively is the same as:
Set rs = New ADOB.recordset
Thursday, October 05, 2006
The code he found was questionable; his replacement was not a like-for-like replacement, and potentially code-breaking, so I would call it wrong.

He should have replaced it with

Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset

Why was the original questionable - because with this kind of delayed declaration, the variable can never be unset. In fact, whenever it is referenced, VB silently checks it is pointing to an object, and if it isn't, creates one for it to point to. This is careless disregard for object lifetime.

Replacing it with an As Object declaration will break code, so long as Option Explicit is on. If it isn't, there are bigger problems than this...
Larry Lard Send private email
Thursday, October 05, 2006
Larry is correct.  Though I do find it funny that the involved person knows enough about VB6 to understand that declaring an object new in it's declaration is a bad, yet doesn't understand that declaring it object isn't 100x's worse.
Shane Courtrille Send private email
Thursday, October 05, 2006
Larry got it, but just to further clarify...

Dim rs As New ADODB.Recordset

Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset

The trouble with (1) is that if further down in the same method you have

rs = Nothing

and then even further down than that you have

rs.MoveNext (or whatever)

then what you'd expect to happen, especially if you're a .NET programmer, is that the rs.MoveNext will fail.  If you used (2), it will; you get "Object variable or With block not set."  But if you used (1), what actually happens is that rs is reinstantiated as a _new_ ADODB.Recordset.  So you don't get a NullReferenceException...but you also don't get the same recordset you were working with earlier.  Which means your code is going to be harder to debug than if it just crashed with a NullReferenceException.

The other consequence of using (1), related to the above behavior, is that on every reference to rs, VB will check to see whether the reference is valid (so it can create it if not).  I've heard it said that these checks slow down your program.  (However, I haven't done any testing to confirm that.)
Kyralessa Send private email
Thursday, October 05, 2006
The overhead is negligible.

The other scenario that hasn't been discussed is when to use CreateObject() instead of the New operator in Set statements.  If the reference variable is strongly typed (i.e. not Object) you'll still get early binding but there are other subtle differences from using New.  The main differences relate to out of process servers and threading and DCOM.
Slim Simi
Thursday, October 05, 2006
In VB6, if you write something like:
Do While CowsComeHome
    Dim rs as New Recordset
The rs object will be set to a new Recordset instance only on the first iteration. On second iteration and on, you will have a lot of fun.
In .Net this has been fixed...
hobit Send private email
Thursday, October 05, 2006
The New in declaration will reinitialize an object on subsequent calls if it is Nothing, but is only really deadly in large unwieldy functions which are poorly written in the first place and have potential re-use of the object.  If your objects are locally scoped and your code well strucutred, it's not normally going to be the source of a latent bug (but still best to be avoided)...
Cade Roux Send private email
Friday, October 06, 2006

Dim rs As Object
Set rs = New ADODB.Recordset

This is wrong, there is no reason to do this because it voids any of the benefits of early binding.


Dim rs As New ADODB.Recordset

This WORKS, and will let you take advantage of all of the benefits of early binding, however everytime the VB runtime dereferences the "rs" variable, it has to check if the object has been created first. This is a small penalty, but there is really no reason to incur it when you can just use #3:


Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset

Or, if you want it all on one line do this:

Dim rs As ADODB.Recordset: Set rs = New ADODB.Recordset

This is the best way to do it because you are explicitly instantiating the new object and everytime the VB runtime dereferences the pointer, it will not have to validate the pointer.

Also, you never have to explicitly release an object by setting rs = Nothing because the runtime does that automatically when the variable goes out of scope.
Wayne B
Sunday, October 08, 2006

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
Powered by FogBugz