Vb Classic Language Issues

Issues with the design of MicroSoft's VbClassic language and InteractiveDevelopmentEnvironment? (IDE). This goes into more detail than ThingsWeHateAboutVbClassic.

Incorrect. The only part of OO that VB currently does not have is Implementation Inheritance. Most OO Gurus warn that Implementation Inheritance is vastly overrated and that most designs don't need it or need it on the scale that people think. Look at PeterCoad 's book on Java Modeling in Color, where he suggests different approaches. If you want, you can do it with Aggregation or Composition anyway like COM does. It's not in COM either for a very good reason. The FragileBaseClassProblem is one big reason. As to the argument of being fully OO, you can ask 50 people for that definition and get 50 answers. Anyone can write SpaghettiCode in ANY language. You must apply discipline. Use what what VB gives you - class modules, structure your code well. My engineers are able to create fully OO VB components that are readable, maintainable, and not SpaghettiCode by applying these skills. I don't understand the remark of plumbing code because in my opinion, VB totally hides or eliminates the Windows plumbing code. If you are using a lot of nested ifs and so on, I would contend it's a bad design myself.

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

From comp.lang.python:
"Yes, they do. I should know - I'm working on a whopping great big laboratory erp system built in Visual Basic. First there was the prototype and it looked like a Windows program. Then there wasn't enough time to start again and discard the prototype, so the prototype became the specification, and in time, the system. Then the project was delayed by about a year. Then there were performance problems caused by conceptual errors that had to be rectified by hacking around. Then suddenly, the whole blasted !@#$%^&* was more than ten million lines, more than hundred DLL's, numerous OCX'es, and countless forms, all built by twenty to thirty novices in the art of programming, of whom fifteen had left the company. It's more than painful or embarrassing... And it's not the first time I've seen that happen. Sorry for the rant - I just had to get it of my chest. I don't think Python really insures you against these mistakes.

"VB is notorious for insuring THAT a project makes those mistakes. :)"

How in the hell this person can actually blame a language/environment on his/her team's misuse and bad practices is beyond me. This has nothing to do with the VisualBasic language, it could happen just as easily with any other language. -- DrewMarsh

(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.)

PythonProblems doesn't give any reasons why Python isn't suitable for developing large applications. Neither does PythonLanguage, where the only relevant comment I can find is one saying "Its other great strength is its scalability". In my limited experience, Python isn't used primarily for quick and dirty hacks. (I use it for quick hacks, among other things, but they're quick and clean hacks.)

Actually the language is responsible for its "misuse." In general, a lot of VB code reminds me of C code. Unfortunately, the addition of OO capabilities to VB did not have as strong an influence on coding practices as the introduction of C++. Perhaps the changes chould have been advertised as VB++. VB does not strongly guide developers to use class structures and the result is many develop long, rambling functional novels. It is a valid expectation for a language to try and minimize poor usage. -- WayneMack

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

Having Subs and Functions is a feature.

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

In C++ the compiler will catch you if you screw the syntax up - in VB you get no error, no warning, no nothing - all you get is a bug when your ByRef is magically and silently turned into a ByVal. At the very least Option Explicit should fix this behaviour. It doesn't.

No: Your class offers it as foo.bar; a variable of type "foo" can hold a reference to your object, and call the method "bar." An internal implementation detail of your class is that the method name is called foo_bar, but caller's won't be calling your implementation class directly.

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...


Exit Function


' 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 Function
add 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 Function
This 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

(Maybe someday they'll learn... Sigh.)

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

The String semantics compare poorly with those in other languages. Contrast them with the Perl primitives especially. Contrast the collection classes with the Perl compositable hashes, list/sets, and closures, and the ability to map these directly onto databases, and VB seems far from amazingly and tremendously easier. -- PM

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?.

If you do not have write access to a form (IE: you haven't checked it out of SourceSafe), you will be unable to... If you don't want to check out (and lock) the file right now, you must exit VB, set the file writable, and then restart the VB IDE. (...because the VB IDE "knows" what files are writable, and which are read-only, but it's unaware of access changes that occur outside the IDE environment.)

Are you talking VBScript or VisualBasic? You don't have to use Variants hardly ever in VisualBasic. VBScript is a whole another issue and is based on that it is late-binding and a scripting language. Compare to the lack of data types in Perl.

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:

-- DanGreen

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

-- DrewMarsh

(please forgive any errors, I whipped this up from memory...)


EditText of this page (last edited November 12, 2011) or FindPage with title or text search