Issues with the design of MicroSoft's VbClassic language and InteractiveDevelopmentEnvironment? (IDE). This goes into more detail than ThingsWeHateAboutVbClassic.
I'm happy with COM. I'm content that components oughtn't to inherit implementations. But I'm not content that within a component my classes can't inherit. Delegation in VB is clumsy and error prone. This plus the lack of generic types, except for the dreadful Variant, creates lots and lots of redundancy. The nested ifs caused by no lazy evaluation I believe you've conceded above. And by plumbing code I mean recordsets and so on - because it's difficult to leverage your own design abstractions, due to the lack of OO completeness, most of your implementations depend mostly on MS abstractions.
This last is good in some respects. It means an inexperienced programmer doesn't have to understand your design to maintain your code. But it's trouble on larger systems because it results in a lot of redundancy that's hard to maintain.
I concede it's possible to write SpaghettiCode in any language. VB just seems to make it easier :-) -- PeterMerel
I would like to see a specific example of lack of OO creating tangled code as the only option, although I may agree that VB's procedural tools are sometimes not as powerful as they could be and OO (or other changes) may offer a way around VB-specific limitations. -- top
(Double ironic: Python, a Unix scripting language is not known as an industrial strength large application development language. Quite the opposite - it's a scripting language, used primarily for quick and dirty hacks. See PythonProblems with PythonLanguage.)
Again, we would like to see specifics. Functions are not inherently evil. I've yet to see code from my domain where OO clearly improves it. -- top
Is there some reason they couldn't have used the same calling syntax? The only difference is that the one doesn't return a value, right?
A function returns a value. A subroutine does not. Your mind has been corrupted by C/C++: VB works like Fortran, Pascal and other common modern languages.
Calling a function and accidentally ignoring the value is a common cause of error in C/C++ programs.
Q: So you can't call a function like a subroutine in VB and ignore its return value?
A: Yes you can.
PascalLanguage is much more anal about forcing callers to use the return values of functions, and C/C++ now have "functions" that return "void" - making them, in effect, procedures, not functions. In VB, you can "Call" a function - ignoring the returned result. Try that in PascalLanguage. -- JeffGrigg
I've been writing C for years and C++ for about a year, and I don't ever recall having a problem because I called a function and accidentally ignored the value. -- GarethMcCaughan
Historically, it's been a common problem in C, as practically all I/O functions returned some kind of result indicating if they worked or not. On output, these were generally ignored. Like, how often do you check the return value of the printf function? -- JeffGrigg
I generally think of VB as a half-compiled and half-interpreted language. If you expect the compiler to flag everything, you will be disappointed, and missing return values is one of those things that has a foot in the dynamic floor. You mostly only find such problems when run-time behavior is not what you expected. However, some things are even looser than other interpreted languages, like unassigned variables being interpreted as null instead of an error (if Option Explicit isn't used). That one is inexcusable even for a dynamic language. -- top
You have Implementation Inheritance in every object oriented language, including Java. You don't have it in VB, ergo VB isn't OO. Let me tell you what I *really* want. I *really* want: OO. If VB is OO, then so are Fortran and Cobol. -- PM
What about the previous comments that "There are many great arguments against implementation inheritance. Why did people leave it out of Java? ???"
As to VB's exceptions, they seem much weaker than in any other modern language. How can an exception handler differentiate them by type?
(Right: Error handling, up to VB6 sux.)
Um, how is it pilot error if a file can't be opened, a device can't be accessed, or some other typical exception occurs? Is everything in the world a pilot error now?
No, everything is not due to lack of VB development understanding. However, it seems that this topic has lots of references to the VB IDE crashing on exceptions as a rule and I say that this is *not* the case. There are rare cases when the VB IDE will crash while running problematic source in debug. For example, when you pass a ref to a bStr (ByRef) to an API function that expects a lpStr and you do not initialize the size of the bStr, you will get a crash of the IDE. I can only think of 2 other similar cases, anything else causing the IDE to crash is either a bug addressed by an SP, a bug in the CPU or a PilotError IMHO. Running VS6 SP3 on NT SP4 and not seeing any of the crashes that are plaguing some in this group tells me some in the group are doing something wrong. -- Charlie Ferebee
Having a single global error handling object is obscene. To create a large scale application you must have a published, coherent error handling strategy for each layer (or glob) of software. Because of VB's single global object, consistent error handling combined with the natural tendency to reduce duplicate code leads to bloat and hackery. To avoid duplicate code one tends to reuse error handling routines. If you do this in VB, when your call to the central error handling routine returns VB resets the global error object! This makes it impossible to do another common practice, rethrowing the error for a higher-level routine to catch. Since switching to a different group in my company I've been using VB exclusively. I feel dirty. To conform to the coding standards of this group and avoid code duplication, I've had to use a goto statement for the first time in 17 years. This language is a giant step backward.
Jibberdy-gook: it is perfectly possible and quite easy to catch and exception in one method (sub or function) and throw it up to the layer. Here's a simple function that does just that:
Option Explicit Private Const CLASS_NAME As String = "myModule" Public Function myFunction(ByVal Arg1 As Long, ByVal Arg2 As String) As String On Error Goto ErrorHandler Const METHOD_NAME as String = "myFunction" Dim ErrNo? As Long, ErrSource? As String, ErrDesc? As String your declarations... your validation, eg... If Len(Arg2) = 0 Then Err.Raise 60000, GetSource?(CLASS_NAME, METHOD_NAME), "Arg2 is not optional." End If your logic... ExitHandler?: Exit Function ErrorHandler: ' Get error info and clear error ErrNo? = Err.Number ErrSource? = Err.Source ErrDesc? = Err.Description Err.Clear ' Append error source If Not ErrSource? = GetSource?(CLASS_NAME, METHOD_NAME) Then ErrSource? = ErrSource? & GetSource?(CLASS_NAME, METHOD_NAME) End If ' Throw exception to next layer Err.Raise ErrNo?, ErrSource?, ErrDesc? End Functionadd this function somewhere with global view...
Public Function GetSource?(ByVal ClassName As String, ByVal MethodName? As String) As String GetSource? = App.EXEName & "." & ClassName & "." & MethodName? & "()" End FunctionThis will give you errors that can be bubbled between layers, and include a little stack dump, eg:
myApp.myModule.myFunction() <- myApp.frmMain.cmdButton_Click() Arg2 is not optional.
Enjoy! -- Mark Micallef
Let's face it, VB is a RAD tool. It should only be used for RAD projects, and making thin GUI layers on top of code written in other languages. Using VB for enterprise-scale projects is suicide.
What exactly is an EnterpriseApplication anyhow? I never get a good definition. The trick is to break it into smaller applications instead of try to make One Big Exe. One Big Exe is a design smell for almost any language for interactive apps. Communicate between the multiple apps via the database. It tends to be OO'ers who fight the DB that run into such problems (GreencoddsTenthRuleOfProgramming). -- top
I wouldn't view lazy evaluations as a positive design choice. It tends to make code more fragile and too dependent upon intricate knowledge of the conditional evaluation sequence. Explicit code is always better than code relying on implicit knowledge.
Also, you can usually replace nested if statements with sequential else if statements with no associated processing. Often it is much clearer to state what you want to exclude from processing rather than what you want to include. -- WayneMack
PascalLanguage has the same issue: No shortcut evaluation of AND/OR - you have to use nested conditions. This can be a real pain in loops. PascalLanguage does this to give the compiler more freedom to optimize expression evaluation; it may evaluate the two sides of an "AND" in any order it chooses. -- JeffGrigg
They're not type safe: Collections hold Variants - which might be anything, even if your program requires String or Integer, for example.
Or worse... Variant can't hold VB UserDefinedTypes?.
Your question is a very good one. Isn't VBScript VB? It is if you're using it to leverage the skills of VB programmers ... and there's no other reasonable reason to use it, is there? If you want to count it out of bounds, I concede Variant needn't be and shouldn't be used very often in VB. -- PM
VBScript is a SUBSET of VB, which requires late binding, which requires the Variant data type just likeother scripting languages use one or two types. Variants should only be used in VB in rare cases when talking to the Win32 API. The overhead of a Variant is huge. It's usually better to pass a type As Any to the Win32 API. Variants should never be used in regular VB programming.
I think we agree on this, though we draw different conclusions. -- PM
As everything, the Variant has its place. To say Never is very limiting; never is a long time. Don't use Variants because of laziness, but because it is the best thing to use, there and then. A For..Each loop on an array demands a Variant. A refactored function may return a Variant or have Variant parameters. -- Thomas Eyde
Also, NULL values from a database can't be stored in anything but a Variant, unless you forcibly convert it into something else (empty string, zero) first. This also applies to stuff that deals with nulls, such as the IsNull?() function. -- DanNovak
What's VB's stand on:
Concurrency, no. VB is implemented in a COM STA (Sigle Threaded Apartment) making it imposible to support multi-threading. The VB team made a choice that multi-threading was too difficult for their audience.
Isn't it more correct to say that the VB audience shouldn't have to worry about writing code to handle concurrency issues when multi-threading, than claiming it is just too hard for us? -- ThomasEyde
How's VbUnit compare against JavaUnit?
Would there be any compromises to the patterns laid out in MartinFowler's RefactoringBook for VB?
...or the DesignPatternsBook?
Why is it impossible to implement a "Visual Basic" iterator in Visual Basic? (IE: To support "foreach item in X" syntax on a collection class you create, you have to build and return a Collection (or something written in C/C++), because Visual Basic can't "correctly" implement the "Item" method.) [I think that's the method name. Please correct if I'm mistaken.]
The exact reason for the last question: ActiveX implements what they call an "Enumerator" interface (which is really an Iterator) using a Magic DISPID on a member.
If you could declare the DISPID for a member you could do a real Enumerator interface.
You can set the DISPID for any method in VB. Simply write yourself a sub or function and then go to "Tools->Procedure Attributes" on the menu, click the "Advanced >>" button and look for the "Procedure ID" combo box. Select a well-known DISPID or type in your own if you like.
Now... the real reason you can't implement an enumerator in VB is because of the IEnumXXXX family of interfaces in COM. Automation enumerators, like the one used by the "For Each" syntax are based on IEnumVARIANT specifically, however others like IEnumString and IEnumUnknown exist as well. The IEnumXXXX family has four methods that look like any standard iterator, look it up in MsdnLibrary? if you want more details. The quick explanation is, that these interfaces use advanced concepts in COM that VisualBasic, an Automation based language, is not capable of implementing.
However, all that being said... most people who need to expose a custom collection from a VisualBasic component usually write their own collection class, consisting of a typed Item property, the standard Count property, and then a hidden method usually called "_NewEnum" which they mark with the afformentioned procedure property editor as DISPID_NEWENUM or -4. Underneath these customized collection classes, they're really delegating the calls to a standard collection object. For example, suppose I were writing a collection class in VisualBasic which I wanted to hold humans. Well... I hopefully have defined a Human class somewhere and now I just define the following for the collection class:
<codesnippet language="VisualBasic">
Public Property Get Item(Name As String) As Human '-- Simply delegate to standard collection (stored as member variable) Set Item = m_colHumans.Item(Name) End Property Public Property Set Item(Name As String, Instance As Human) '-- Perform any logic desired to make sure this human is acceptable '-- Delegate to store Set m_colHumans(Name) = Human End Property Public Property Get Count() '-- Delegate again Count = m_colHumans.Count End Property Public Property _NewEnum() As IUnknown '-- Deletgate to _NewEnum of standard collection! Set _NewEnum = m_colHumans.[_NewEnum] '-- note need for []s to escape _ End Property</codesnippet>
-- DrewMarsh
(please forgive any errors, I whipped this up from memory...)