Instantiating a variable with Nothing, then assigning a New object instance - vb.net

Looking through some old VB.Net code, I noticed a strange pattern that is making me scratch my head.
Dim objMyObject As Namespace.Child.ChildType = Nothing
objMyObject = New Namespace.Child.ChildType
(There is no additional code between the dimension and the assignment.)
It seems like the preferred style would be to do both on one line, or else skip the = Nothing. As follows:
Dim objMyObject As Namespace.Child.ChildType = New Namespace.Child.ChildType
OR
Dim objMyObject As Namespace.Child.ChildType
objMyObject = New Namespace.Child.ChildType
OR, as suggested by #helrich
Dim objMyObject As New Namespace.Child.ChildType
Is there any particular value to doing it this way, or is this an instance of the original programmer being used to the VB6 way of doing things?
In VB6, dimensioning and instantiating a variable on one line was considered problematic because it would rerun the instantiation (if necessary) when the variable was accessed - effectively, a variable dimensioned in this way could never be tested for Nothing, because a new instance would be created on demand. However, VB.Net does not preserve this convention.

No, this is pointless. The CLR already provides a hard guarantee that variables are initialized to Nothing.
It is otherwise completely harmless, the jitter optimizer will completely remove the code for the assignment. So if the original author preferred that style then that's okay. Maybe he was a former C# programmer that didn't understand the definite assignment rules in that language. VB.NET does some checking too but it isn't nearly as strict. Do check if this is a team standard that you are supposed to follow as well, hopefully not.

In the first example, there's no need to separate the declaration and assignment.
But I was wondering here (a hypothesis): Since you should split this way when you want to persist the variable in the stack when it is assigned in a code block (e.g: If statement), maybe once upon a time this block existed and it was removed keeping a constant association to it.
Its association, though, was not merged with its declaration.
About associating Nothing to an empty variable: I personally like this pattern. :)
It tells myself (in future maintainances) that the variable was declared with an empty (null) value on purpose. It eliminates the doubt that I, maybe, forgot to write the New keyword behind the type.
Ahh, and it will also eliminate a vb.net warning during build.

Related

What are the risks of declaring a variable in the middle of the code?

I usually see in almost all of VBA codes all variables are declared after e.g. Sub/Function name line
I know and I used variable declaration in the middle of some of my codes (Not inside a loop) and saw no problems.
I usually avoided that because I see most of VBA example codes have them declared right after the first line. I just want to know what are the risks from an expert/experienced VB programmer point of view.
There are no risks of declaring it in the middle.
The effect of declaring a variable in the middle is that it can only be used after that point and not before (which is scope).
The lifetime of the variable is different: the variable is created (allocated and initialized to its respective flavour of zero) when you enter the procedure, but you may not actually use it until you reach its scope (the point in the procedure where it's declared).
Declaring inside or outside a loop does not make a difference in VB6/A as they do not have block scope, unlike VB.NET.
So there is no performance difference between the two approaches (because all variables are created when you enter the procedure), but there is a difference in usage (you may not use a created variable before its declaration line). If you think that distinction is helpful in making sure you are not using a variable wrongly, declare your variables only where needed. Otherwise you are free to pick any of the two approaches, just apply it consistently (it's probably not a good idea to declare most of the variables in the beginning and then some in the middle).
Declare your variables, when you actually need them. When you have all declarations lumped at the top of the procedure, refactoring becomes much harder. And when you want to double check your declaration as you read your code (or, perhaps, someone else), searching it at the top may be again quite inconvenient, unless you procedure is short.
I would try to declare variables in a location that conveys useful information to the next programmer, over and above being functionally correct. This normally means: follow the scoping rules of the language.
By declaring all variables at the top you are making them available (in scope) for the entire procedure. That increases the work for a reader in the future, trying to understand how they will be used. Better to have them as local as possible.
I would not declare them in a loop since that actually would not have significance in VB6/VBA - but someone else might find confusing or misleading, or worst case it may cause subtle bugs.
Of course remember that this is not the only coding practice that we should be mindful of - if the procedure is so long that the location of the variable declarations is a big problem, that's a really good sign that the procedure should be broken up into smaller discrete logical blocks. The variable declarations would just be a symptom, not the main cause.
IMO there were many bad programming practices back in the 90s and earlier when VBA/VB6 were invented, but the industry has significantly learned & improved since then. So code from that era (or inspired by it) is often not a good example.
Declaring your variables up front, at the top of your sub/function makes it easy for others (and perhaps for you if you come by the code after, say a month) to read and understand what your code needs to calculate, and what placeholders/variables are required for the code to function.
You can of course declare variables anywhere (as long as you remember not to use a variable unless you have actually declared it first). That can work, and it has no effect whatsoever on the performance of your code (unless your logic includes an early Exit Sub or Exit Function. In this case, there will be a difference in performance depending on if your code does actually allocate memory for the variables or not).
It just isn't good practice to declare some variables at the top then do some work, then declare another set of variables mid-code. There are exceptions of course. When the variable you declared mid-code is for a temporary use, or something like that.
Sub CalculateAge()
Dim BirthYear As Integer
Dim CurrentYear As Integer
'Code to fetch current year
'Code to get BirthYear from user/or document
'Code to report result
End Sub
Compare that with the following:
Sub CalculateAge2()
Dim BirthYear As Integer
'Code to ask the user or fetch the birth year from the document
Dim CurrentYear As Integer
'Code to populate currentYear
'Code to do the calculation and report result
End Sub
In the first example, there is a clear separation from variables and logic. In the second, everything is mixed.
The first example is a lot easier to read and understand, especially if you use a good naming convention.
If you look at how classes are written or defined, you will see properties usually are first declared, then methods/logic below. This is the common practice used to write code.
PS: In other languages, you can declare and assign variables in the same line. in C# or VB.Net you could say something like:
int Age = CurrentYear - BirthYear; //C#
Dim Age As Integer = CurrentYear - BirthYear 'VB.Net
This is great if you use a lot of temporary variables, that you don't intend to declare ahead of time or maybe it would be more clear if declared mid-logic. But that's not possible in VBA. You need a separate line to declare a variable, and another to assign a value. You end up with a lot of Dim ___ As ___ statements. You might as well move the declaration part somewhere else to reduce distraction while reading the logic. Again, this works best if you use a good and consistent naming convention. If not, you end up in a worse situation like:
Dim w As Integer
Dim a As Integer
a = 42 'we don't know what this variable is for
'but we know its type from the previous line
Some_Lines_Of_code_And_Logic
' more code
' more code
w = 2 'we don't know what (w) is for, and we have to
'look up its declaration to get a hint
'which might be tedious

When should an Excel VBA variable be killed or set to Nothing?

I've been teaching myself Excel VBA over the last two years, and I have the idea that it is sometimes appropriate to dispose of variables at the end of a code segment. For example, I've seen it done in this bit adapted from Ron de Bruin's code for transferring Excel to HTML:
Function SaveContentToHTML (Rng as Range)
Dim FileForHTMLStorage As Object
Dim TextStreamOfHTML As Object
Dim TemporaryFileLocation As String
Dim TemporaryWorkbook As Workbook
...
TemporaryWorkbook.Close savechanges:=False
Kill TemporaryFileLocation
Set TextStreamOfHTML = Nothing
Set FileForHTMLStorage = Nothing
Set TemporaryWorkbook = Nothing
End Function
I've done some searching on this and found very little beyond how to do it, and in one forum post a statement that no local variables need to be cleared, since they cease to exist at End Sub. I'm guessing, based on the code above, that may not be true at End Function, or in other circumstances I haven't encountered.
So my question boils down to this:
Is there somewhere on the web that explains the when and why for variable cleanup, and I just have not found it?
And if not can someone here please explain...
When is variable cleanup for Excel VBA necessary and when it is not?
And more specifically... Are there specific variable uses (public variables?
Function-defined variables?) that remain loaded in memory for longer
than subs do, and therefor could cause trouble if I don't clean
up after myself?
VB6/VBA uses deterministic approach to destoying objects. Each object stores number of references to itself. When the number reaches zero, the object is destroyed.
Object variables are guaranteed to be cleaned (set to Nothing) when they go out of scope, this decrements the reference counters in their respective objects. No manual action required.
There are only two cases when you want an explicit cleanup:
When you want an object to be destroyed before its variable goes out of scope (e.g., your procedure is going to take long time to execute, and the object holds a resource, so you want to destroy the object as soon as possible to release the resource).
When you have a circular reference between two or more objects.
If objectA stores a references to objectB, and objectB stores a reference to objectA, the two objects will never get destroyed unless you brake the chain by explicitly setting objectA.ReferenceToB = Nothing or objectB.ReferenceToA = Nothing.
The code snippet you show is wrong. No manual cleanup is required. It is even harmful to do a manual cleanup, as it gives you a false sense of more correct code.
If you have a variable at a class level, it will be cleaned/destroyed when the class instance is destructed. You can destroy it earlier if you want (see item 1.).
If you have a variable at a module level, it will be cleaned/destroyed when your program exits (or, in case of VBA, when the VBA project is reset). You can destroy it earlier if you want (see item 1.).
Access level of a variable (public vs. private) does not affect its life time.
VBA uses a garbage collector which is implemented by reference counting.
There can be multiple references to a given object (for example, Dim aw = ActiveWorkbook creates a new reference to Active Workbook), so the garbage collector only cleans up an object when it is clear that there are no other references. Setting to Nothing is an explicit way of decrementing the reference count. The count is implicitly decremented when you exit scope.
Strictly speaking, in modern Excel versions (2010+) setting to Nothing isn't necessary, but there were issues with older versions of Excel (for which the workaround was to explicitly set)
I have at least one situation where the data is not automatically cleaned up, which would eventually lead to "Out of Memory" errors.
In a UserForm I had:
Public mainPicture As StdPicture
...
mainPicture = LoadPicture(PAGE_FILE)
When UserForm was destroyed (after Unload Me) the memory allocated for the data loaded in the mainPicture was not being de-allocated. I had to add an explicit
mainPicture = Nothing
in the terminate event.

Why do we declare variables at the start of a module?

As my first language and as completely taught from other's example I never questioned the standard practice in VBA of grouping all variable declarations at the start of the module, routine or function they are scoped to as in this example.
Sub Traditional()
Dim bVariable as Boolean
Dim OtherVariable
' Some code using OtherVariable goes here
'
' Now we use bVariable
bVariable = True
Do While bVariable
bVariable = SomeFunction()
Loop
End Sub
Now I'm learning that standard practice in other languages is to declare variables as close to where they are used as possible, like this:
Sub Defensive()
Dim OtherVariable as String
' Some code using OtherVariable goes here
'
' Now we use bVariable
Dim bVariable as Boolean
bVariable = True
Do While bVariable
bVariable = SomeFunction()
Loop
End Sub
This seems completely sensible to me as a defensive programming practice - in that it limits both span and live time (as explained in Code Complete), so I'm wondering if there is any reason for not doing the same in VBA? Possible reasons I can think of are memory, running time (e.g. repeatedly declaring inside a loop), tradition - arguably a good reason as there must be hundreds of thousands of VBA programmers who expect to see all used variables at the start of the routine. Are there any I've missed that might explain the benefit of this practice or at least where it came from?
I declare all my variables at the top. I think declaring them closer to first use masks (at least) two other problems that should be fixed first.
Procedures too long: If you're procedure is more than fits on a screen, perhaps it's doing too much and should be broken into smaller chunks. You'll also find that unit tests are way easier to write when your procedures are small and only do one thing.
Too many variables: If you have a bunch of related variables, consider using a custom class module or user-defined type. It will make the code more readable and easier to maintain.
If your procedures are short and you're using classes and UDTs, the benefits of declaring the variables at the point of use are lessened or eliminated.
I think both way are just different coding style in VBA
In old C Standard, all Declaration must be on the top, I think many people just adopt this habit and bring it into other PL such as VBA.
Declaring variable on the top is clear for short list of variable names. It will be unreadable for a long list of variable name
Declaring variable close to where it's being used is introduced later. I think this practice has a clear advantage over "declare on the top" for PLs that has optimizer or more scope than VBA. (Like you can declare variables where the scope is visible in a FOR loop only) Then the optimizer will change the scope for you. (In VBA words, it may change a GLOBAL variable to a PROCEDURE variable)
For VBA, no perference

Is it possible to use Variables without DIM in VB.NET?

Is it in VB.NET possible to use variables without the need of use DIM?
now I have to use the variables like this:
dim a = 100
dim b = 50
dim c = a + b
I want to be able to use vars in this way:
a=100
b=50
c=a+b 'c contains 150
I think in VB6 and older VB this was possible, but I am not sure.
As far as what #Konrad said, he is correct. The answer, buried in all his caveat emptors, is the answer of "yes", you can absolutely do this in VB.NET by declaring Option Explicit Off. That said, when you do a=1, the variable a is NOT an Integer - it is an Object type. So, you can't then do c = a + b without compiler errors. You'll need to also declare Option Strict Off. And at that point, you throw away all the benefits of a compiler. Don't do it.
As an alternative, with Option Infer On, Dim behaves the same as C#'s var keyword and gives you a lot of advantages if you're trying to save on typing.
You have a fundamental misunderstanding of how VB is supposed to work. The Dim statements are there to help you. Your wish to elide them is misplaced.
The compiler enforces variable declaration so that it can warn you when you have accidentally misspelt a variable name, thus inadvertently creating a new variable, and is required to enforce type safety. Without variable declaration, VB code becomes an unreadable, unmaintainable mess.
Incidentally, the same was true in VB6, and you should have used Option Explicit in VB6 to make the compiler force you to use them properly. This option still exists in VB.NET but switching it off has no advantage, and a whole lot of disadvantages so don’t do it – instead, learn to appreciate explicit variable declarations, and all the help that the compiler is giving you through them.

VB.Net Running Threading with Reflected Objects

Running into problems creating objects through reflection and then running them on multiple threads.
I just cannot seem to figure out what I need to here:
For Each WorkerNode As XmlNode In oRunSettings.GetWorkerValues
Dim sWorkerName = WorkerNode.Attributes(SETTING_NAME_ID).Value
Dim oWorkerType As Type = Type.GetType(String.Format("Worker.{0}", sWorkerName))
Dim oWorker As Object = Activator.CreateInstance(oWorkerType)
Dim tWorker As Thread = New Thread(AddressOf oWorker.Process)
tWorker.Start()
Next
It is causing errors at the "AddressOf" because Object does not have a method called that. Do I need to do something with an interface?
First of all I want to say that I've never wrote code in VB so I can be completely wrong here but I'll try anyway.
It seems that you hold the created instance as Object instead of it's correct type.
Object does not contain method named Process, hence the error.
try casting the object to the correct type.
I hate when people answer their own question, but while waiting for an answer, I realized that I could just cast the object as its base object, and set the reflection from there. That is working now.