Classic VB Corner

Forward Compatibility

While moving code backward is nice, what really matters is that code can move forward.

The phrase "backward compatibility" has always grated on my nerves. Does anyone really expect to be able to take data from the current version of AppX and use it freely in the previous version of AppX? Of course not! If the next version of Word or Excel offered no way to load and use the documents created in the last version, not even through cut and paste of the raw data, how many folks would willingly say, "Hey, that's really cool, sign me up!" Are your eyes rolling too?

To sneeringly speak of "backward compatibility" being an obvious impediment to progress in the same manner that Alberto Gonzalez spoke about the Geneva Conventions is inherently condescending and an attempt to belittle those who are implied to have an interest in reusing their own data. What matters is forward compatibility. Data assets simply must move forward from one version of an application to the next. This must be the developer's imperative. Quaint, my assets.

Those of you who attended the great flamewars that accompanied the introduction of Visual Basic.NET are probably somewhat familiar with this argument. But it was nicely highlighted again through a reader response to one of my recent columns. Larry asked why I bothered with the two Case Else clauses in the following routine:

Public Function ToBoolean(ByVal EntryValue As String) As  Boolean
  ' Interpret entry as either true or false.
  Select Case Trim$(UCase$(EntryValue))
    Case "YES", "Y", "TRUE", "T", "ON", "1", "-1"
      ToBoolean = True
    Case "NO", "N", "FALSE", "F", "OFF", "0"
      ToBoolean = False
    Case Else
      ToBoolean = False
  End Select
End Function

At first, I was left scratching my head, too. Of course they're redundant. Did I do it as a way to self-document my intentions, at the expense of a (negligible) performance hit? I do that sometimes, but I really try not to publish it as a best-practice example. I had a vague recollection that it was in fact a historical artifact of some nature.

Then, it came to me as I read this morning's newspaper. QuickBasic 4.0 triggered an error (39:"CASE ELSE expected") if you didn't properly account for every possible comparison outcome. A quick perusal through my documentation shelf verified this dim memory:

If CASE ELSE is used, the associated statements are executed only if text testexpression does not match any of the other CASE selections. It is a good idea to have a CASE ELSE statement in your SELECT CASE block to handle unforeseen testexpression values. If none of the expressions listed in the CASE clauses matches testexpression, you get a run-time error.

This situation was remedied in the Microsoft BASIC Professional Development System, as the language evolved to handle such situations like this:

If CASE ELSE is used, its associated statements are executed only if text testexpression does not match any of the other CASE selections. It is a good idea to have a CASE ELSE statement in your SELECT CASE block to handle unforeseen testexpression values. When there is no CASE ELSE statement and no expression listed in the CASE clauses matches testexpression, program execution continues normally.

(Wild digression: If anyone knows of electronic documentation for QB or PDS, I'd love an e-mail! I hate typing stuff like that, if cut/paste is an option.)

Note the last four or five words in each passage. Graceful deprecation if ever there were, huh? It was entirely possible to write code that worked exactly as intended, not to mention exactly as written, and compile it in both environments. In fact, this tradition lasted the entirety of the MSBASIC years, a full quarter century from 1976 to 2001. With very few exceptions, and nearly all of those due strictly to the underlying change of platform, code from one version of MSBASIC easily moved forward to the next.

Of course code written to expect PDS ignoring the lack of a CASE ELSE statement could blow chunks if used in QB. But code written in QB to offer a default response for CASE ELSE worked just fine in PDS. That's a critical distinction. Forward compatibility.

Getting back to the case at hand, the code Larry objected to was offered for use in VB6. I quit consciously trying to write code that would load without fail in VB1 through VB3 back when I moved to 100 percent VB4/32 work. (I loved 32-bitness, and never looked back.) But the routine I presented was actually written originally in VB1, and at that time I made every effort to ensure that all the code that could would be fully reusable in QB, PDS, VBDOS and VB. It didn't take a lot of effort, just a functional understanding of the enhancements offered at each step along the way.

This effort to write code that works in previous versions as well as the current version is what would rightly be called backward compatibility. Of course, you can't do this for versions that haven't yet been developed. The best you can do in that case is to lay your bets with the vendor who has consistently provided forward compatibility for customer assets.

Getting back to the object of Larry's comment: Yes, at some point I changed the As Integer in that function return to As Boolean, and of course True and False had to be defined as Global constants, but I guess since the rest of the routine was fully tested and never posed any problem whatsoever, there was never the attention given to fully optimize it for 32-bit Classic VB. So, in Larry's honor, I present the fully optimized version:

Public Function ToBoolean(ByVal EntryValue As String) As  Boolean
  ' Interpret entry as either true or false.
  Select Case Trim$(UCase$(EntryValue))
    Case "YES", "Y", "TRUE", "T", "ON", "1", "-1"
      ToBoolean = True
    'Case "NO", "N", "FALSE", "F", "OFF", "0"
    '  ToBoolean = False
    'Case Else
    '  ToBoolean = False
  End Select
End Function

Microsoft didn't have to include a boatload of gratuitous incompatibilities in Visual Fred, just because it couldn't meet its original goal of 100 percent forward compatibility for older code. For one (poster-child) example, there was no need to recycle the Return keyword, when adding an optional parameter to the Exit Function statement would've preserved the option of returning GoSub to the language at some point in the future.

Save your rants about the utility of that particular construct, if you can, and focus on the negligence involved in totally recycling a 25-year-old keyword, giving it entirely new meaning. And speaking of negligence, let's not forget about the abomination of redefining fundamental data types, such as Integer and Long, following the wakeup calls offered with VB4's introduction of UniMess.

Stick to the message here. Yes, I know Select Case works just the same in Visual Fred as it does in Classic VB, which is why I'm not using it as the poster child exhibit. Larry's comment served only to remind me of how strictly Microsoft stuck to a policy of forward compatibility from the time the company was founded (presumably everyone reading this knows what Microsoft's first product was?) until the introduction of Visual Fred. Was it perfect in this regard? No, stumbles were made along the way, acknowledged and were followed by promises that "it wouldn't happen again."

Don't assume for a moment I think this rant or position I advocate on Language Stability matters one bit to the folks in Redmond. I do feel a responsibility to urge anyone investing their current intellectual efforts into any vendor's products to stop and consider whether that vendor has demonstrated a commitment to the security of their investment. It's a state of mind. Should data move forward into the future, or be cast off into the dustbin of history whenever a new marketing opportunity arises for the vendor?

Which vendor mindset is the one you want to invest your data with? You know where I stand.

Classic VB died in 2001.

Long live Classic VB.

About the Author

Karl E. Peterson wrote Q&A, Programming Techniques, and various other columns for VBPJ and VSM from 1995 onward, until Classic VB columns were dropped entirely in favor of other languages. Similarly, Karl was a Microsoft BASIC MVP from 1994 through 2005, until such community contributions were no longer deemed valuable. He is the author of VisualStudioMagazine.com's new Classic VB Corner column. You can contact him through his Web site if you'd like to suggest future topics for this column.

comments powered by Disqus

Featured

  • Compare New GitHub Copilot Free Plan for Visual Studio/VS Code to Paid Plans

    The free plan restricts the number of completions, chat requests and access to AI models, being suitable for occasional users and small projects.

  • Diving Deep into .NET MAUI

    Ever since someone figured out that fiddling bits results in source code, developers have sought one codebase for all types of apps on all platforms, with Microsoft's latest attempt to further that effort being .NET MAUI.

  • Copilot AI Boosts Abound in New VS Code v1.96

    Microsoft improved on its new "Copilot Edit" functionality in the latest release of Visual Studio Code, v1.96, its open-source based code editor that has become the most popular in the world according to many surveys.

  • AdaBoost Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the AdaBoost.R2 algorithm for regression problems (where the goal is to predict a single numeric value). The implementation follows the original source research paper closely, so you can use it as a guide for customization for specific scenarios.

  • Versioning and Documenting ASP.NET Core Services

    Building an API with ASP.NET Core is only half the job. If your API is going to live more than one release cycle, you're going to need to version it. If you have other people building clients for it, you're going to need to document it.

Subscribe on YouTube