Enhancing BASIC+ Part 2: Iteration Irritations

In this series of articles, we’ve been exploring how the a precompiler can be used to enhance the BASIC+ language. In the previous article, we introduced the precompiler directive and some tips on creating language enhancements without sacrificing usability in other areas. This article in the series reveals how the SRP Precompiler is improving dynamic array iteration.

List Loops

BASIC+ programmers use dynamic arrays everyday. We use them to model complex data or to hold simple linear lists. Either way, we often find ourselves doing this:

NumItems = DCount(List, @FM)
For iItem = 1 to NumItems
    Item = List<iItem>
    // Do stuff with Item
Next iItem

This is how BASIC+ does a simple iteration through the list from beginning to end using the simplest syntax. As programmers, we learn little techniques to make these loops reliable, such as using “iItem” as the counter instead of “i”, just to avoid the possibility of nested GoSubs using the same counter. Simple. Reliable. Performant… most of the time.

Fast and Ugly

As most BASIC+ programmers are aware, a dynamic array is just a string. When using angle brackets to access an element within a dynamic array, the language (behind the scenes) always scans from the beginning of the string to find the first character of the desired element, scans to find the end of the element, and extracts the result. If your list is large, performance starts to degrade.

If you are iterating from the beginning of a large list to the end, you can do the following in order to gain a performance increase.

ListPos = 1
LenList(List)
Loop
    Item = List[ListPos, "F":@FM]
    ListPos = Col2() + 1
    // Do stuff with Item
Until ListPos GE ListLen
Repeat

The technique ensures the entire string is only traversed once, turning an O(n2) operation into an O(n) operation: an exponential speed increase! But, boy, is it ugly. Techniques like these are often used as a last resort because, well, programmers (ironically) don’t like typing. It sure would be nice if we could get all the speed without all the blemishes.

Introducing For…Each

The SRP Precompiler introduces the For…Each loop. If you have an @FM delimited list, you can do this:

For Each Item in List
    // Do stuff with Item
Next Item

The SRP Precompiler will convert the For…Each loop into the same efficient, ugly loop from the previous section. So, you can have your cake and eat it too. It also supports any delimiter:

For Each Param in ParamList using ","
    // Do stuff with Param
Next Param

It even supports nesting without worrying about stepping on shared variables:

For Each Field in Array using @FM
    For Each Value in Field using @VM
        // Do stuff with Value
    Next Value
Next Field

It only takes one use to fall in love with this simple syntax that has graced most modern languages. Now we have it too. The only catch: you have to include the following line of code in your stored procedure:

#pragma precomp SRP_Precompiler

Better with SRP Editor

One thing important to us at SRP is that code have the ability to be compiled anywhere. That is why the SRP Editor never offered proprietary precompiling. The #pragma keyword ensures that we can enhance the language for environments with or without the SRP Editor. However, the SRP Editor will make the experience of using a precompiler much better.

In the first place, we quickly realized that adding the #pragma statement to every stored procedure was tedious. So, the SRP Editor will add it automatically when you attempt to compile any code that contains Enhanced BASIC+. This means, if you use the aforementioned For…Each loop and press F9, the #pragma statement will be inserted near the top of your stored procedure if it isn’t there already. Using Enhanced BASIC+ will be effortless. If for any reason, you want to manually insert the #pragma, you can right click on your code and select “Insert SRP_Precompiler”.

The SRP Editor will also perform syntax highlighting on new keywords, so the Enhanced BASIC+ will operated like a first class citizen.

ForEach

Stay Tuned

We hope you are getting excited for the next release of the SRP Editor. In the next article, we will blow your mind when we reveal how the SRP Precompiler is bringing joy to Event Commuter Modules.

2 Responses to Enhancing BASIC+ Part 2: Iteration Irritations

  • Matt Crozier says:

    This looks super cool! Can’t wait – as long as it supports UTF8 apps 😉

    Remember that the ‘Fast and Ugly’ technique is not effective in UTF8 mode. This is because even though the starting character position (ListPos) has been specified, Basic+ in UTF8 mode still needs to scan from the beginning of the string to find out which (multi-byte) character it is referring to. (See http://sprezzblog.blogspot.co.nz/2010/03/utf8-and-extended-string-operators.html)

    A good alternative, for both ANSI and UTF8 modes, would be:

    ListPos = 1
    LenList = getByteSize( List) ;* length of the string in Bytes
    Loop
    Item = List[ListPos, “F”:@FM, 1] ;* use Byte positions instead of Character positions
    ListPos = bCol2() + 1 ;* set the next Byte position
    // Do stuff with Item
    Until ListPos GE ListLen
    Repeat

    Cheers, M@

    • Kevin Fournier says:

      I had indeed overlooked this. It’s good to have friends across the ocean. Thanks to this comment, the For…Each will be both ANSI and UTF8 compatible upon release.

Leave a Reply