Ok so I was in college and I was talking to my teacher and he said my code isn't good practice. I'm a bit confused as to why so here's the situation. We basically created a for loop however he declared his for loop counter outside of the loop because it's considered good practice (to him) even though we never used the variable later on in the code so to me it looks like a waste of memory. We did more to the code then just use a message box but the idea was to get each character from a string and do something with it. He also used the Mid() function to retrieve the character in the string while I called the variable with the index. Here's an example of how he would write his code:
Dim i As Integer = 0
Dim justastring As String = "test"
For i = 1 To justastring.Length Then
MsgBox( Mid( justastring, i, 1 ) )
End For
And here's an example of how I would write my code:
Dim justastring As String = "test"
For i = 0 To justastring.Length - 1 Then
MsgBox( justastring(i) )
End For
Would anyone be able to provide the advantages and disadvantages of each method and why and whether or not I should continue how I am?
Another approach would be, to just use a For Each on the string.
Like this no index variable is needed.
Dim justastring As String = "test"
For Each c As Char In justastring
MsgBox(c)
Next
I would suggest doing it your way, because you could have variables hanging around consuming(albeit a small amount) of memory, but more importantly, It is better practice to define objects with as little scope as possible. In your teacher's code, the variable i is still accessible when the loop is finished. There are occasions when this is desirable, but normally, if you're only using a variable in a limited amount of code, then you should only declare it within the smallest block that it is needed.
As for your question about the Mid function, individual characters as you know can be access simply by treating the string as an array of characters. After some basic benchmarking, using the Mid function takes a lot longer to process than just accessing the character by the index value. In relatively simple bits of code, this doesn't make much difference, but if you're doing it millions of times in a loop, it makes a huge difference.
There are other factors to consider. Such as code readability and modification of the code, but there are plenty of websites dealing with that sort of thing.
Finally I would suggest changing some compiler options in your visual studio
Option Strict to On
Option Infer to Off
Option Explicit to On
It means writing more code, but the code is safer and you'll make less mistakes. Have a look here for an explanation
In your code, it would mean that you have to write
Dim justastring As String = "test"
For i As Integer = 0 To justastring.Length - 1 Then
MsgBox( justastring(i) )
End For
This way, you know that i is definitely an integer. Consider the following ..
Dim i
Have you any idea what type it is? Me neither.
The compiler doesn't know what so it defines it as an object type which could hold anything. a string, an integer, a list..
Consider this code.
Dim i
Dim x
x = "ab"
For i = x To endcount - 1
t = Mid(s, 999)
Next
The compiler will compile it, but when it is executed you'll get an SystemArgumenException. In this case it's easy to see what is wrong, but often it isn't. And numbers in strings can be a whole new can of worms.
Hope this helps.
Related
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
Here is what i have tried so far , but no new shot variable is being declared
Module Module1
Dim shotlist As New List(Of Boolean)
Dim shono As Integer = 0
Dim shonos As String
Dim shotname As String
Dim fshot As Boolean
Dim shots As String
Sub Main()
For i As Integer = 0 To 1000
Dim ("shots" & i) as String = "shots" & i
fshot = Convert.ToBoolean(shots)
Next
End Sub
End Module
You can't do things this way. The variable names you see when you write a program are lost, turned into memory addresses by the compiler when it compiles your program. You cannot store any information using a variable's name - the name is just a reference for you, the programmer, during the time you write a program (design time)
Think of variables like buckets, with labels on the outside. Buckets only hold certain kinds of data inside
Dim shotname as String
This declares a bucket labelled shotname on the outside and it can hold a string inside. You can put a string inside it:
shotname = "Shot 1"
You can put any string you like inside this bucket, and thus anything you can reasonably represent as a string can also be put inside this bucket:
shotname = DateTime.Now.ToString()
This takes the current time and turns it into a string that looks like a date/time, and puts it in the bucket. The thing in the bucket is always a string, and lots of things (nearly anything actually) can be represented as a string, but we don't type all our buckets as strings because it isn't very useful - if you have two buckets that hold numbers for example, you can multiply them:
Dim a as Integer
a=2
Dim b as Integer
b=3
Dim c as Integer
c=a*b
But you can't multiply strings, even if they're strings trust look like numbers; strings would have to be converted to numbers first. Storing everything as a string and converting it to some other type before working on it then converting it back to a string to store it would be very wearisome
So that's all well and good and solves the problem of storing varying information in the computer memory and giving it a name that you can reference it by, but it means the developer has to know all the info that will ever be entered into the program. shotname is just one bucket storing one bit of info. Sure you could have
Dim shotname1 as String
Dim shotname2 as String
Dim shotname3 as String
But it would be quite tedious copy paste exercise to do this for a thousand shotname, and after you've done it you have to refer to all of them individually using their full name. There isn't a way to dynamically refer to bucket labels when you write a program, so this won't work:
For i = 0 To 1000
shotname&i = "This is shotname number " & i
Next i
Remember, shotname is lost when compiling, and i is too, so shotname&i just flat out cannot work. Both these things become, in essence, memory addresses that mean something to the compiler and you can't join two memory addresses together to get a third memory address that stores some data. They were only ever nice names for you to help you understand how to write the program, pick good names and and not get confused about what is what
Instead you need the mechanism that was invented to allow varying amounts of data not known at the design-time of the program - arrays
At their heart, arrays are what you're trying to do. You're trying to have load of buckets with a name you can vary and form the name programmatically.
Array naming is simple; an array has a name like any other variable (what I've been calling a bucket up to now - going to switch to calling them variables because everyone else does) and the name refers to the array as a whole, but the array is divided up into multiple slots all of which store the same type of data and have a unique index. Though the name of the array itself is fixed, the index can be varied; together they form a reference to a slot within the array and provide a mechanism for having names that can be generated dynamically
Dim shotnames(999) as String
This here is an array of 1000 strings, and it's called shotnames. It's good to use a plural name because it helps remind you that it's an array, holding multiple something. The 999 defines the last valid slot in the array - arrays start at 0, so with this one running 0 to 999 means there are 1000 entries in it
And critically, though the shotnames part of the variable name remains fixed and must be what you use to refer to the array itself(if you want to do something with the entire thing, like pass it to a function), referring to an individual element/slot in the array is done by tacking a number onto the end within brackets:
shotnames(587) = "The 588th shotname"
Keep in mind that "starts at 0 thing"
This 587 can come from anything that supplies a number; it doesn't have to be hard coded by you when you write the program:
For i = 0 to 999
shotnames(i) = "The " & (i+1) & "th shotname"
Next i
Or things that generate numbers:
shotnames(DateTime.Now.Minute) = "X"
If it's 12:59 when this code runs, then shotnames(59), the sixtieth slot in the array, will become filled with X
There are other kinds of varying storage; a list or a dictionary are commonly used examples, but they follow these same notions - you'll get a variable where part of the name is fixed and part of the name is an index you can vary.
At their heart they are just arrays too- if you looked inside a List you'd find an array with some extra code surrounding it that, when the array gets full, it makes a new array of twice the size and copies everything over. This way it provides "an array that expands" type functionality - something that arrays don't do natively.
Dictionaries are worth mentioning because they provide a way to index by other things than a number and can achieve storage of a great number of things not known at design time as a result:
Dim x as New Dictionary(Of String, Object)
This creates a dictionary indexed by a string that stores objects (I.e. anything - dates, strings, numbers, people..)
You could do like:
x("name") = "John"
x("age") = 32
You could even realize what you were trying to do earlier:
For i = 0 to 999
x("shotname"&i) = "The " & (i+1) & "th shotname"
Next i
(Though you'd probably do this in a Dictionary(Of string, string), ie a dictionary that is both indexed by string and stores strings.. and you probably wouldn't go to this level of effort to have a dictionary that stores x("shotname587") when it's simpler to declare an array shotname(587))
But the original premise remains true: your variable has a fixed part of the name (ie x) and a changeable part of the name (ie the string in the brackets) that is used as an index.
And there is no magic to the indexing by string either. If you opened up a dictionary and looked inside it, you'd find an array, together with some bits of code that take the string you passed in as an index, and turn it into a number like 587, and store the info you want in index 587. And there is a routine to deal with the case where two different strings both become 587 when converted, but other than that it's all just "if you want a variable where part of the name is changeable/formable programmatically rather than by the developer, it's an array"
I am trying to program a way to read a text file and match all the values and their quantites. For example if the text file is like this:
Bread-10 Flour-2 Orange-2 Bread-3
I want to create a list with the total quantity of all the common words. I began my code, but I am having trouble understanding to to sum the values. I'm not asking for anyone to write the code for me but I am having trouble finding resources. I have the following code:
Dim query = From data In IO.File.ReadAllLines("C:\User\Desktop\doc.txt")
Let name As String = data.Split("-")(0)
Let quantity As Integer = CInt(data.Split("-")(1))
Let sum As Integer = 0
For i As Integer = 0 To query.Count - 1
For j As Integer = i To
Next
Thanks
Ok, lets break this down. And I not seen the LET command used for a long time (back in the GWBASIC days!).
But, that's ok.
So, first up, we going to assume your text file is like this:
Bread-10
Flour-2
Orange-2
Bread-3
As opposed to this:
Bread-10 Flour-2 Orange-2 Bread-3
Now, we could read one line, and then process the information. Or we can read all lines of text, and THEN process the data. If the file is not huge (say a few 100 lines), then performance is not much of a issue, so lets just read in the whole file in one shot (and your code also had this idea).
Your start code is good. So, lets keep it (well ok, very close).
A few things:
We don't need the LET for assignment. While older BASIC languages had this, and vb.net still supports this? We don't need it. (but you will see examples of that still floating around in vb.net - especially for what we call "class" module code, or "custom classes". But again lets just leave that for another day.
Now the next part? We could start building up a array, look for the existing value, and then add it. However, this would require a few extra arrays, and a few extra loops.
However, in .net land, we have a cool thing called a dictionary.
And that's just a fancy term of for a collection VERY much like an array, but it has some extra "fancy" features. The fancy feature is that it allows one to put into the handly list things by a "key" name, and then pull that "value" out by the key.
This saves us a good number of extra looping type of code.
And it also means we don't need a array for the results.
This key system is ALSO very fast (behind the scene it uses some cool concepts - hash coding).
So, our code to do this would look like this:
Note I could have saved a few lines here or there - but that would make this code hard to read.
Given that you look to have Fortran, or older BASIC language experience, then lets try to keep the code style somewhat similar. it is stunning that vb.net seems to consume even 40 year old GWBASIC type of syntax here.
Do note that arrays() in vb.net do have some fancy "find" options, but the dictionary structure is even nicer. It also means we can often traverse the results with out say needing a for i = 1 to end of array, and having to pull out values that way.
We can use for each.
So this would work:
Dim MyData() As String ' an array() of strings - one line per array
MyData = File.ReadAllLines("c:\test5\doc.txt") ' read each line to array()
Dim colSums As New Dictionary(Of String, Integer) ' to hold our values and sum them
Dim sKey As String
Dim sValue As Integer
For Each strLine As String In MyData
sKey = Split(strLine, "-")(0)
sValue = Split(strLine, "-")(1)
If colSums.ContainsKey(sKey) Then
colSums(sKey) = colSums(sKey) + sValue
Else
colSums.Add(sKey, sValue)
End If
Next
' display results
Dim KeyPair As KeyValuePair(Of String, Integer)
For Each KeyPair In colSums
Debug.Print(KeyPair.Key & " = " & KeyPair.Value)
Next
The above results in this output in the debug window:
Bread = 13
Flour = 2
Orange = 2
I was tempted here to write this code using just pure array() in vb.net, as that would give you a good idea of the "older" types of coding and syntax we could use here, and a approach that harks all the way back to those older PC basic systems.
While the dictionary feature is more advanced, it is worth the learning curve here, and it makes this problem a lot easier. I mean, if this was for a longer list? Then I would start to consider introduction of some kind of data base system.
However, without some data system, then the dictionary feature is a welcome approach due to that "key" value lookup ability, and not having to loop. It also a very high speed system, so the result is not much looping code, and better yet we write less code.
I have seen over the time people mentioning that the Call Statement is deprecated, but I can't seem to find anything official to support this claim.
On the documentation page, there was a pretty recent update to the page (12/03/2018), so can't really say is outdated information.
I've been using Call in my code, most of the time simply because I find this:
Call function(arg1, arg2, arg3)
to be more readable than
function arg1, arg2, arg3
Now for the question, can anyone provide some insight into why I shouldn't use the Call statement anymore? If you do say is deprecated, please do provide a link to a resource.
If this question is against the site rules, please do let me know, I`ll happily delete it myself, though would be nice to get answer.
Consistency is King
Whether you're calling a Sub or a Function makes no difference whatsoever. What matters is consistency, and that's what Call-lovers claim using the keyword brings. Consistency with whether or not parentheses are required around the argument list.
So instead of this simple-as-it-gets implicit call statement:
MsgBox "I'm a function but you're discarding my return value, so no parentheses."
We get things like this:
MsgBox ("I'm a function but you're discarding my return value, and this call looks weird.")
And I've yet to see the Call actually being used with any kind of actual consistency:
Call MsgBox("I'm a function but you're discarding my return value, so I have a Call keyword.")
Call MyProcedure(42)
Call ActiveSheet.Range("A1:A10").Clear
Call Beep
Call CallByName(obj, "SomeMethod", VbCalType.VbMethod)
Used consistently, Call quickly becomes obnoxious, clearly redundant, and slows down reading, because the eyes can't help but stop on the keyword, and then the brain goes "oh hey watch out, we're calling something here". I suppose at one point you just stop seeing it, and just feel like something's off if it's missing.
The overwhelming majority of every single executable statement is going to be a call to something, somewhere, at some abstraction level - using Call consistently makes the language even more heavily bulky than it already is.
Unless Call isn't really about consistency, more about being able to easily see my own user procedure calls... which at this point is just grasping at straws to legitimize an archaic construct that serves no purpose whatsoever: there is no legitimate use for the Call keyword.
This is the only "legit" use case:
Public Sub Test()
DoSomething: DoSomethingElse
'vs.
'Call DoSomething: Call DoSomethingElse
End Sub
Private Sub DoSomething() '<~ dead code. can you see why?
End Sub
Private Sub DoSomethingElse()
End Sub
The Call keyword disambiguates a LineLabel: from a ParameterlessProcedureCall followed by an : instruction separator. Only problem is, : instruction separators are great for golfing and cramming as much executable code as possible on a single line of code ...they are terrible for readability. Besides everybody agrees that a NEWLINE should follow a ; in any semicolon-terminated language, even though it makes perfect sense for the compiler to ignore the line jump.
We write code for people to read and maintain, not just for compilers to build and run.
Deprecated? Says who?
Says me and my ducky.
I'm 100% certain I've read in the Official docs at one point in my life, that the keyword was obsolete. Heck, it's even specified as being redundant. Languages evolve, VBA is no exception - even with mind-blowingly incredible levels backward-compatibility and after two decades without any kind of significant changes, the language - or rather, its practices are still fluid, even if its maintainers have retired vowed to just let it be.
Call isn't the only deprecated token in VBA, but for questionable subjective reasons not unsimilar to what people use to justify clinging to the formidable mistake that Systems Hungarian notation was in this century, its roots run deep.
Where are the defenders of the Rem comment marker? Why is While...Wend still a thing when Do While...Loop supersedes it? Is anyone raising errors with the Error statement rather than through Err.Raise? Outputting error messages with Error$ rather than through Err.Description? Declaring variable types with the ever-so-legible $&%^!# type hints? Who writes On Local Error? Why use Global for things that are really Public?
And if explicit Call isn't obsolete and "makes the code more readable", then why aren't the same people using explicit Let statements for value assignments for the exact same explicitness/clarity reasons?
I think it's well past time to rewrite what the best practices are, and leave Call in the past, along with Let, Hungarian Notation, and walls-of-declarations at the top of procedures. Every single programming community did this already - only the VBA community is still holding on to the "best practices" from 30 years ago, for brand new code, not just legacy stuff written in another era. I suspect it's very much possible that VBA's "dread score" has a lot to do with that, even without taking the bare-bones IDE into account.
I'd love to be able to pull a reference from fellow Microsoft MVP old-timers Rob Bovey and Stephen Bullen, and say "here, see, page 172 it says the call keyword is obsolete" (this answer seems to mention a "two inch thick book on VBA basically says don't use it unless you want to use the Find feature of the VBE to easily find calls in large projects"), so this might be it, but in any case at the time these gurus essentially defined what the best practices were, "refactoring" was a foreign word, "unit testing" was an extreme programming crazy idea - the entire programming landscape has enormously evolved in the past 20 years, but VBA stood still. Time to end this, and move on forward.
Speaking of moving forward...
"It makes it easier to migrate to VB.NET"
Allegedly, using Call statements make it "easier" to port the code to .NET, because VB.NET will want the parentheses everywhere. Respectfully, that's bullocks. First because what you'll want to port your VBA code to isn't VB.NET but much more likely TypeScript, if any kind of porting is ever actually going to happen. If you're manually copying VBA code and "translating it" to get it to compile in the target language, you'll quickly find that not having to deal with parentheses is a very marginal perk, since literally everything else needs to be rewritten, ...including dropping the Call tokens.
Writing small, specialized procedures that do very few things if ever more than a single one, leveraging abstraction levels and classes/objects, reducing coupling between modules, improving cohesion within modules, having your code's behavior covered and documented with thorough unit tests, that will help you port your VBA code faster, and ensure the ported code works identically. Call and parentheses are just an excuse to keep a bad habit going.
I try to avoid the Call (and thus, it is depreciated for me) for the following reason - in #VBA I consider passing a variable in parenthesis as a way to overrun the standard ByVal/ByRef specification of the parameters. What do I mean? Consider this example:
Public Sub TestMe()
Dim var1 As Long: var1 = 1
Dim var2 As Long: var2 = 1
IncrementByVal (var1)
IncrementByRef (var2)
Debug.Print var1, var2
End Sub
Public Function IncrementByVal(ByVal a As Variant) As Variant
a = a + 100
IncrementByVal = a
End Function
Public Function IncrementByRef(ByRef a As Variant) As Variant
a = a + 100
IncrementByRef= a
End Function
As you probably see, both var1 and var2 return 1, while the var2 should be 101, as far as it is ByRef. The Call-word kind-of improves this "feature" in VBA, but it becomes too complicated to remember when the parenthesis are overriding the ByRef and when not, when reading code. Thus, having 3 cases is quite a lot:
Public Sub TestMe()
Dim var1 As Long: var1 = 1
Dim var2 As Long: var2 = 1
Dim var3 As Long: var3 = 1
Dim var4 As Long: var4 = 1
Dim var5 As Long: var5 = 1
Dim var6 As Long: var6 = 1
IncrementByVal (var1) '1
IncrementByRef (var2) '1
IncrementByVal var3 '1
IncrementByRef var4 '101
Call IncrementByVal(var5) '1
Call IncrementByRef(var6) '101
Debug.Print var1, var2
Debug.Print var3, var4
Debug.Print var5, var6
End Sub
Public Function IncrementByVal(ByVal a As Variant) As Variant
a = a + 100
IncrementByVal = a
End Function
Public Function IncrementByRef(ByRef a As Variant) As Variant
a = a + 100
IncrementByRef = a
End Function
I frequently use Call when I'm refactoring code or cutting new code I'm not yet sure of. To explain, using Call requires brackets around the arguments and so does returning a value from a function. I might want to return a value from a function, or I might want to pass an argument by reference (ByRef)
Sub Test()
Dim v
'* Call requires brackets
Call NotSureIfThisWillEndUpAsASubOrAFunction(1, 2)
'* return a value from a Function then need brackets
v = NotSureIfThisWillEndUpAsASubOrAFunction(1, 2)
'* if always a sub then no brackets required
WillAlwaysBeASub 4, 5
'* but is this really so ugly, why deprecate this?
Call WillAlwaysBeASub(4, 5)
End Sub
Function NotSureIfThisWillEndUpAsASubOrAFunction(a, b)
End Function
Sub WillAlwaysBeASub(c, d)
End Sub
EDIT: I think using brackets all the time (which means using Call as a keyword for Subs) means less time hopping around the code taking brackets out and then putting them back in upon change of mind.
So there is a question on what DIM is, but I can't find why I want to use it.
As far as I can tell, I see no difference between these three sets of code:
'Example 1
myVal = 2
'Example 2
DIM myVal as Integer
myVal = 2
'Example 3
DIM myVal = 2
If I omit DIM the code still runs, and after 2 or 3 nested loops I see no difference in the output when they are omitted. Having come from Python, I like to keep my code clean*.
So why should I need to declare variables with DIM? Apart from stylistic concerns, is there a technical reason to use DIM?
* also I'm lazy and out of the habit of declaring variables.
Any variable used without declaration is of type Variant. While variants can be useful in some circumstances, they should be avoided when not required, because they:
Are slower
Use more memory
Are more error prone, either through miss spelling or through assigning a value of the wrong data type
Using Dim makes the intentions of your code explicit and prevents common mistakes like a typo actually declaring a new variable. If you use Option Explicit On with your code (which I thoroughly recommend) Dim becomes mandatory.
Here's an example of failing to use Dim causing a (potentially bad) problem:
myVar = 100
' later on...
myVal = 10 'accidentally declare new variable instead of assign to myVar
Debug.Print myVar 'prints 100 when you were expecting 10
Whereas this code will save you from that mistake:
Option Explicit
Dim myVar as Integer
myVar = 100
' later on...
myVal = 10 ' error: Option Explicit means you *must* use Dim
More about Dim and Option Explicit here: http://msdn.microsoft.com/en-us/library/y9341s4f.aspx
Moderators, I'm making an effort, assuming you'll treat me with due respect in thefuture.
All local variables are stored on the stack as with all languages (and most parameters to functions). When a sub exits the stack is returned to how it was before the sub executed. So all memory is freed. Strings and objects are stored elsewhere in a object manager or string manager and the stack contains a pointer but vb looks after freeing it. Seting a vbstring (a bstr) to zero length frees all but two bytes. That's why we try to avoid global variables.
In scripting type programs, typeless programming has many advantages. Programs are short and use few variables so memory and speed don't matter - it will be fast enough. As programs get more complex it does matter. VB was designed for typeless programming as well as typed programming. For most excel macros, typeless programming is fine and is more readable. Vbscript only supports typeless programming (and you can paste it into vba/vb6).