Enable Dictionary Object in VBA - vba

When I initiate a dictionary object in Excel VBA, I found out two methods:
Use CreateObject("Scripting.Dictionary") (no "Microsoft Scripting Runtime");
Turn on the reference "Microsoft Scripting Runtime" first, then use Dim dict As New Scripting.Dictionary
Both of them work on my machine. I am wondering is there any difference between these two methods?

The only difference I know is the first one uses Late bind and the second one uses Early bind. The difference between the two is explained here.
Early bind has advantages. One of which is you can use Intellisense to guide you on the available properties of the bound object that you can use in coding. Also, it is said that it is faster in terms of performance. You can also use built-in constant as is. No need to check it's equivalent value. This is discussed here.
Late bind has advantages as well specially if you bound objects that have different versions. This reduces the risk of runtime errors due to version incompatibility (also mentioned in the 1st link).
As for me, I always use Early bind during development so I can utilize Intellisense. If there is a need to convert to Late bind, I'll do it later after I or the customer have done robust testing.
Additional:
When you use Early bind Don't Use Auto-Instancing Object Variables as discussed by CPearson in his post here. Below is the excerpt from his blog.
For object type variables, it is possible to include the New keyword in the Dim statement. Doing so create what is called an auto-instancing variable. Again, while this may seem convenient, it should be avoided. Contrary to what some programmers may believe, the object isn't created when the variable declaration is processed. Instead, the object is created when it is first encountered in the code. This means that, first, you have limited control when an object is created. Second, it means that you cannot test whether an object is Nothing, a common test within code and a common testing and diagnostic technique.
So a better way to set your variable is:
Dim dict As Scripting.Dictionary
Set dict = New Scripting.Dictionary

Related

Where in the VB6/VBA project references do Array(), LBound(), and UBound() come from..?

Where in the VB6/VBA project references do Array(), LBound(), and UBound() come from..? When I'm typing in code, they don't appear in the Autocomplete list (ctrl+space), they don't get autocompleted, and they must be typed out completely before the text editor recognizes them. And only when a left-parenthesis is typed will ToolTipText pop up with the command syntax. Also, they do not appear anywhere in Object Explorer.
There's probably a basic concept in play here that I'm not aware of. And it makes me wonder, what other commands/statements/keywords are hidden in the same way..? Is there a list somewhere..? I googled for info but didn't find anything, probably because I don't know what I'm looking for and using the wrong search terms.
I ask these questions because I have the habit of prefixing many VB6 built-in functions like this: VBA.Left(), VBA.Len, VBA.Instr(), and so on. But I can't figure out what reference prefeix to use with Array(), LBound(), and UBound(), or perhaps they're so basic to VB6 that they don't have one.
I do this prefixing because years ago I was working on a large project, and there were functions I was trying to use with the same name in different reference libraries. I was a newbie and it took me a while to figure out, and it was causing tremendous problems since the functions were just NOT working the way I thought they were supposed to. It was then that I developed the prefixing habit after I figured it out. It's just easier that way, and always ensures the expected functions are being used.
The reason that they don't appear as IntelliSense options (and also why they don't appear in the Object Browser) is that they aren't declared in the VBE7.dll typelib for some reason that's beyond me. The Array function is implemented in the .dll as rtcArray. The utility of knowing that is dubious, in that its sole argument is a ParamArray, which means that if you called it directly from VBE7.dll you would need to create an array to have it feed you back the same array... This partially explains why it isn't on the typelib - a COM call would need to do the same thing, and the marshaling would basically be doing the same thing as what you'd expect the function to return.
LBound and UBound don't even appear as functions in the export table, so my guess is that they are handled more like "keywords" than first class functions internally. This makes some sense, in that it's fairly trivial to check the bounds of a SAFEARRAY if you have a pointer to the automation struct (you just index into the rgsabound array at the end of it and read the cElements and lLbound from it. Again a guess, but I'd assume that this allows for flexibility in letting LBound and UBound function with both fixed length and variable length arrays. In the fixed case, the array is basically managed as a block of memory with an indexer (more like a VT_CARRAY than a VT_SAFEARRAY). I'd imagine that handling this internally was easier or more convenient than providing first-class functions.
You won't find Debug in the Object Browser either, nor its methods Assert and Print.
You won't find Statements that are used like methods, like Open, Close, Get and Put, which is why you don't get any Intellisense when you use those statements, and the syntax must be memorized.
You will find Load and Unload as members of VBA.Global, but it's not clear what they belong to otherwise, and their arguments are late-bound Objects. The VBA documentation states that Load and Unload are Statements, even though the Object Browser shows them as Methods.
Keep in mind that you can move the order of references and it will make a difference. Try moving VBA to the top or near the top of your list of references. I believe that if something else also defines a BASIC keyword, it steals it, in a sense. I once had Right disappear and because I was not aware of the order of references, had to change all references of Right to VBA.Right. It's possibly the same with the ubound, lbound, or array.

Is there a C# equivalent of VB.NET's "Static"?

The VB.NET Static declaration:
http://msdn.microsoft.com/en-us/library/z2cty7t8.aspx
The only reference I can find to this question is from 2008:
http://forums.asp.net/t/951620.aspx?what+is+the+equivalent+of+static+from+vb+net+in+c+
Is there an equivalent in recent versions of C#, or still not present? Is there anything particularly wrong about using Static in VB.NET?
C# does not support it and probably won't be because it somehow violates object programming idea of state being part of object, not a method.
Of course one can say that it is only syntactic sugar, and he/she will be event quite right. But still, looking through class code, we expected description of its state variables as a fields of class. Otherwise we should find for it in each and every method.
So this can be simply seen about some high-level decision and your millage may vary here.
Personally, I like the VB procedure-level Static, even if it's not "pure" enough for some folk.
You can set it in declaration and forget it:
Static oClient As HttpClient = New HttpClient()
There's no checking whether a module-level variable needs to be instantiated or not:
If moClient Is Nothing Then moClient = New HttpClient()
And, silly me, I always expect that there is equivalency between C#.NET and VB.NET but I've learned that clinging to that concept is folly, unfortunately.

VB.net : How to protect a global variable from being modified inside a sub (ByVal, ByRef : not applicable)

I have a global variable X in an winform application.
The variable X is used in different forms inside the application and I don't want it to be modified. It's not used as a parameter in the functions... so ByRef, or ByVal are not applicable.
It's used like that:
Declaration
dim X as whatever;
dim Y as whatever;
private sub SubExample(A as object)
'Do some staff
'Locally modifiy X
X = something else;
end sub
Main program
call SubExample(Y);
'After this, X should still have its original value
Any idea please ?
You can't protect a global variable (unless it has to be assigned only once, in that case it can be Const). By definition it's global so it's visibile by all classes.
I would avoid them every time it's possible because of that: you can't restrict their access to who really has to use it (as you found by yourself) and they couple all classes use them. Main problems I see with them are:
Testing: because they couple many (all?) classes they make code testing pretty hard. You can't really isolate a class or sub-system for testing.
Concurrency: they're free accessed by everything in any thread then you'll have concurrency issues and you'll need to make them thread-safe. A variable in VB.NET can be thread-safe (at least atomic read/write) only for primitive types.
Access: as you saw you can't restrict access to them. Even if you make them global properties you can just make them read-only but somewhere a write function/setter must exist (unless you're using them for singleton pattern or for other - few - corner cases).
Maintenability: your code will be harder to understand because implications won't be obvious and local.
What you can do to replace them with something more "safe"?
If you put them in a global class with Shared members just remove Shared and make them instance members. If they're in a Module just move them to a Class.
Make your class singleton (I would use a method instead of simple property to make this more obvious). This may or not be your case, you may simply create your object in your startup method.
Add a public property in each form will need them and when you create your form just set this property to class you previously created. According to effective implementation this may be or not a Context Object pattern.
If you have multiple sets of global variables (and each set has different users) you may need to create multiple classes (one class for each set of variables).
This is a pretty general method to quickly replace global variables, better way implies some deeper refactoring to make your code more OOP-ish but I can't say without a more complete view of your code.
As a low-tech solution, I would recommend using an unambiguous name like
Dim READONLY_X
as the name of your global variable. Then you are less likely to forget that you should not be writing a new value to it. When you feel the temptation to write the line:
READONLY_X = 2
it should ring an alarm bell. Wrapping inside getter functions etc (without the formalism of a class) seems like a kluge. But that's just an opinion.
As was said before, global variables are a pain; think carefully about the scope you want them to have, and whether there isn't another solution...

Information on OOP, creating Objects

I have a problem in understanding OOP...
This is it :
Sometime's you create an object with this syntax:
Object ObjectName = new Object();
But sometimes, we don't need to do that like in Android:
Textview TextviewName;
Or in J2ME:
form formName;
I already searched it and I got some information (but not sure) that this is because of static method... is it true? I think it has a relation with Polymorphism.. is it true?
Thanks all.
PS : Sory if I made some mistakes, English is not my native languange :D
Forget static methods - they're not relevant here. I'd advocate only looking at static methods / elements when you've truly grasped what objects are.
In Java, you can do this:
Object object;
Just as well as you can do this:
Object object = new Object();
In the first example, you're creating a reference but you're not populating that reference with anything, in the second example you're creating a reference and populating it with a new object, on which you can call methods, modify values and so on.
If you try and call methods on the first declaration you won't be able to - there's nothing there. Depending on the language and how you've declared it this might produce an error at runtime or a compile time error (Java does both depending on whether it's a field or a local variable.) The principle though is the same for all OO languages, you can't dereference (call methods, fields, etc.) on a reference that hasn't been populated, because in effect you're trying to call a method on something that isn't there.
you are mixing different languages and it's not the case of static methods nor polymorphism..
i suggest to read a good book of OOP beginning with the basis.. you can find "Thinking in c++" for free on the net..
Your Textview would not be initialized. Any try at using it would result in a NullReference error. In order for an object to actually be created, you have to use the new syntax or a function that returns a valid object.
However, this is a syntax-dependent issue, so first decide what language you want to study. If your Textview had been declared in C++, it would actually create an object, on the stack.

Best use of System.Windows.Forms.Application.Run()

Hello i Have a programa that has starts in a main sub, it executes some code and after that code it opens a form using
System.Windows.Forms.Application.Run(General)
General is a form but also a class, so I wonder what it the pros or cons of using :
System.Windows.Forms.Application.Run(General)
vs
Dim gen as general
System.Windows.Forms.Application.Run(gen)
In the first I am opening a form using the name of the class, and I read that it is best to declare the instance as an object variable.
So far I used the first approach without any problem.
Thanks for your comments !
Yes, your first code snippet gives OOP purists the shivers. Application.Run() requires a form object, you are passing the form type. That this is possible is an anachronism carried over from VB6. It is admittedly very bad style, it prevents programmers from understanding the difference between a type and an object. Something that's crucial to understand to get ahead with object oriented programming. It is also quite lethal when you start using threads.
Your second snippet is closer to what's needed, except that it cannot work. You pass an uninitialized object to Run(). Fix:
Dim gen as General = New General()
System.Windows.Forms.Application.Run(gen)
Or taking advantage of VB.NET syntax:
Dim gen as New General
System.Windows.Forms.Application.Run(gen)
Or since you never actually need the object in the Main method:
System.Windows.Forms.Application.Run(New General())
In the last snippet, you're passing a null reference to the Run() method. Don't forget to create an instance of the form first.