MV Your Way: Extending mvBASIC
Most flavors of mvBASIC have a little used, often misunderstood structure called FUNCTION . It isn't exactly like FUNCTION in other languages. In PHP, JavaScript, nearly every language that has it, you can stack dozens of FUNCTION s into a single script or source record. The one in mvBASIC requires its own document. One function per source record. On a quick glance, this makes it look like a poor cousin of SUBROUTINE . You couldn't be blamed for thinking it has no real purpose.
That's what I thought for most of my career. Now, I'm beginning to develop a deep respect for it instead. In this article, and the next, I hope to sell you on the value of the humble FUNCTION .
The line of code in Figure 1 will not compile in mvBASIC.
019 doz = xconv(quantity,'unitsToDozens')
Figure 1
It sure would be nice to have a built-in library of any-to-any math conversions. If XCONV existed, it could convert radius to circumference. It could change liters to ounces. There are plenty of standard conversions that I don't need to recode over and over again.
If we write a subroutine to solve this, it would look something like Figure 2.
019 call xconv(doz,quantity,'unitsToDozens')Figure 2
We'd support that with a routine like Figure 3.
001 subroutine xconv(result,value,rule) 002 begin case 003 case rule = 'unitsToDozens' 004 result = int(value/12) 005 result<2> = rem(value/12) …Figure 3
It'll work. It just isn't as elegant. However, we can recast the SUBROUTINE as a FUNCTION and keep our original syntax [Figure 4].
001 function xconv(value,rule) 002 begin case 003 case rule = 'unitsToDozens' 004 result = int(value/12) 005 result<2> = rem(value/12) … xxx return result
Figure 4
Now our original line 19, the one that looks like mvBASIC has always had an XCONV, will compile and work. We just need to add a DEFFUN to connect the FUNCTION to the calling program [Figure 5].
005 deffun xconv()
Figure 5
I haven't scanned the documentation on every MultiValue flavor, so you may need to check your version and make minor tweaks. I believe this should work for most or all of them.
So, what really is the difference between a FUNCTION and a SUBROUTINE ? While they can be pressed into equivalent service, the FUNCTION is more organic. It extends the language. See a quick example in Figure 6.
001 function search(needle,haystack) 002 result = '' 003 locate(needle,haystack;pos) then 004 result = 'ATTR' 005 result<2> = pos 006 end else 007 pos = index(haystack,needle) 008 if (pos > 0) then 009 result = 'CHAR' 010 result<2> = 'pos' 011 end 012 end 013 return result
Figure 6
Now we have a combined command that can easily be extended to search for multivalues or subvalues or any case insensitivity… many, many options. Once again, yes, we can do this more awkwardly with SUBROUTINEs but why? The same way that we use multiplication when repeated addition can achieve the same result. Multiplication is clearer and cleaner.
Next issue, we'll show you how to use FUNCTION to do a massive MultiValue makeover.