Getting started with OOP for User Language programmers
Background
So, you're a User Language programmer and you're thinking about learning object-oriented programming:
- Rumor has it you can be a more effective programmer if you use object-oriented techniques.
- You're tired of feeling inferior to object-oriented programmers because they speak a language that you don't understand but sure as heck sounds impressive.
- You use Sirius Software products and Sirius has announced that all new User Language functionality will used object-oriented syntax.
- “Object-oriented” looks better on your resume than “User Language”.
- You just want to learn something new.
Unfortunately, most User Language programmers' first experience with object-oriented programming is painful and bewildering. Often it comes in the form of a VB.Net or Java class where the terminology flow freely from day one. Even worse:
- Classes often emphasize how one architects an object-oriented application. While this might be a logical way to build an application, it's a daunting way to learn a language — like trying to learn ballroom dancing before you know how to walk.
- Teachers (and books about object-oriented programming) are often enamored with the more sophisticated aspects of object-oriented programming languages, leaving novices in the dust as they're still struggling to digest the simpler concepts.
- Many object-oriented concepts are inter-related so it often requires plowing ahead without fully understanding the concepts one has already learned.
- There seems no way to put the concepts learned in a Java or VB.Net class to use in User Language. So, one is either forced to try to work on object-oriented programming in one's free time, or the concepts are quickly forgotten.
Fortunately, there is a way you can learn object-oriented programming, and apply the principles on-the-job from day one!
One requirement for this is that one work at a site where Janus SOAP User Language Interface is available or, at least some of the other Sirius “API” products such as Janus Web Server or Janus Sockets.
First, a quick word about terminology. In English-speaking, as opposed to American-speaking countries, objected-oriented is usually called object-orientated. More commonly, everyone just calls object-oriented programming “O-O”. But then, you knew that.
Mixed case code
So, let's get started. First, if you're going to do O-O programming you've got to write your code in mixed case. No, there is no technical reason O-O code in User Language must be in mixed case but:
- It's easy enough to do and, even if you don't use O-O, it makes your code look more modern.
- The industry consensus is that descriptive, often compound words, are better for variable, function, and subroutine names than terse non-descriptive names. For example, %itemNumber is better than %ITMN. While the latter is easier to type, the former is much easier to read. USing %ITEMNUMBER, on the other hand, clearly blunts some of that readability benefit. %itemNumber is written in what's called CamelCase.
- Sirius Software depends on CamelCase to make their function and subroutine names readable.
Fortunately, it's easy to start using mixed case code. Simply start typing your code in mixed case. What can possibly go wrong? If you're system manager has set everything up nicely for you, nothing. But, if not, you might hot a few glitches that are easy enough to fix:
- If you use the 204 editor and type in mixed case code and it gets converted to upper case when you hit enter, you have two options:
- Set *LOWER at command level. This is a bit of a hassle because now Model 204 commands require holding the shift key down, because mixed case Model 204 command don't work.
- Set the SIREDIT user parameter to X'33' (only the X'01' bit is required, but you may as well set some others) before entering the editor. This cause Model 204 to essentially switch to *LOWER mode before entering the editor. Request that your system manager do this for everyone by setting SIREDIT X'33' in CCAIN.
- If you get compilation errors when you type in mixed case UL, it means that the compiler is not running in case-independent mode. To fix this, you have three options:
- Have your system manager set the X'01' bit in the system COMPOPT parameter. This must be done in CCAIN and is probably the best/simplest option.
- Change the BEGIN or B statement at the start of the request you're working on to use mixed case, as in Begin, begin, or b.
- If you can't change the start of the program, add the line Sirius Case ToUpper (the case of the words, doesn't matter) to the start of the procedure you're working on.
The following is an example of a mixed case User Language program that starts with a mixed case Begin:
begin print 'Hello World!' end
The following is an example of an Included procedure that contains a Sirius Case ToUpper directive:
sirius case toUpper subroutine hello print 'Hello World!' end subroutine
Note that mixed case UL support is case independent so you can write UL statements in an case, and you can refer to Model 204 variables in any case. The following illustrates a little island of mixed case code in the middle of some upper case code:
SUBROUTINE FOOBAR(%INPUT IS FLOAT) %MSG IS STRING LEN 32 %TOTAL IS FLOAT ... if %input gt %total then %msg = 'Input value too big' end if ... PRINT %MSG END SUBROUTINE
This illustrates that you don't have to convert an entire procedure (or request) to mixed case to take advantage of mixed case UL, though, obviously, in the long-term, it's a good goal to aim for relatively consisten casing in all your code. In the short term, however, a bit of inconsistency will have to be tolerated to get to the point where most or all UL code is in mixed case. Certainly, any new procedures should be written completely in mixed case.
As this example, illustrates, you don't have to learn anything new to enter UL in mixed case (all statements still work the same way) so there is no excuse not to start.
Object-oriented syntax
The most pernicious difference between O-O languages and procedural languages such as User Language (we'll just call it UL from here on) is the syntax. And the biggest syntactic difference between O-O and UL is how functions are subroutines are invoked. Let's start with functions. All UL programmers know how to invoke a function.
First, functions are called $functions (dollar-functions) or £functions (pound-functions) in the UK. $functions always return a value so must either be on the right side of an assignment, input to a subroutine or other $function call, or inside some UL expression. The following example, has a $substr in all three contexts:
%x = $substr(%y, 3, 10) call clever($substr(%y, %start, %len)) %z = $substr(%y, %len, 1) + 10
As the above example illustrates, and all UL programmers know, a $function can be followed by the $function arguments (inputs) in parentheses with multiple arguments separated by commas.
O-O functions, on the other hand, use a syntax where a function invocation consists of the thing (object, if you will) that the function is operating on specified before the function name, followed by its arguments inside parentheses. Many $functions have O-O equivalents and $substr is no exception: its O-O equivalent is called substring. The following illustrates the use of the O-O substring function by replacing $substr in the previous example with substring:
%x = %y:substring(3, 10) call clever(%y:substring(%start, %len)) %z = %y:substring(%len, 1) + 10
While this might look strange to a User Language programmer, it uses the most common O-O syntax so can honestly be called O-O programming. So, if you find any $substr call in your system and change it to use substring (moving the first argument before a :substring) you have now done some O-O coding. It's that easy!
To further add to your bona fides as an object oriented programmer, don't call substring a function, but call it a method. In addition, don't call %y just a string, call it a string object. Now you're ready for something more advanced. Say “I applied the substring method to the string object”. Repeat until it feels natural to say it. Congratulations, you're well on your way to becoming an O-O programmer and, maybe even a guru. If you're curious about what you just said:
- Method is just a fancy word that means function or subroutine or any other called code that does something.
- Object is just a fancy word for a thingy.
Now, of course, there are many functions available other than just Substring. The functions that operate on strings are called Intrinsic String Methods. You can find a list of the methods at List of Intrinsic String Methods. There are also functions that operate on numbers. The list of these can be found at List of Intrinsic Float Methods.
Now, while congratulating yourself on your new-found skills, you might have the gnawing feeling inside that you really haven't accomplished a lot, as much as you have learned. So what have you accomplished? Is O-O syntax really better than what you're used to? At first blush, it would seem worse, as the traditional $function call is more like English, where verb (function name) precedes the object (first parameter), as opposed to the O-O syntax, where the order is reversed. For example, one would day “get the substring of %y” not “%y get the substring” so
%x = $substr(%y, 2, 3)
seems more natural than
%x = %y:substring(2, 3)
While this might be true, it's easy enough to get used to the second form — in many languages the object comes before the verb.
In any case, the chief advantage of O-O syntax is that because the input of a function is to the left of the function, one can invoke a function and then pass the result of that function to another function by placing the second function call after the first. Similarly, a third function can be placed to the right of second to process its output. To illustrate, consider the following:
%x = %y:substring(%start, %len):toUpper:unspace
This reads rather nicely, left to right: take %y get a substring, convert to upper case, and remove extra blanks. The traditional version doesn't read nearly as nicely:
%x = $unspace($upcase($substr(%y, %start, %len)))
Since the processing happens in inside out order, presumably one should read this code inside out but, of course, this is very difficult. In addition, because only a colon is required as a separator character, and because no dollar-sign is required to distinguish a function from other entities, the O-O version is shorter, in spite of the fact that the function names are somewhat longer, and so, more meaningful. Perhaps more important, the O-O expression contains fewer “noise” characters. All of these lead to much better readability for the O-O expression. And, just as spaces can be placed around parentheses in a $function invocation to improve readability, spaces can be placed around the colon used to separate the object and function name:
%x = %y : substring( %start, %len ): toUpper :unspace
This example used inconsistent spacing just to illustrate what's allowed, not to suggest that inconsistent spacing is recommended -- it's not.
So, to continue the process of becoming an object-oriented User Language programmer, you should familiarize yourself with the list of intrinsic string and float methods and try to use them wherever possible and try to use them in lieu of the $function equivalents. There is no performance penalty for doing so — in some cases O-O functions and $functions share the same underlying code.
Named parameters
The Sirius object-oriented User Language implementation has support for named parameters, parameters that can be specified by name, rather than position. While, strictly speaking, this has nothing to do with O-O programming (in fact, few O-O languages support it -- Java and VB.Net do not) named parameters are used in many Sirius functions, so it is important to understand them. To specify a value for a named parameter, simply specify the name, followed by an equals sign (=), followed by the value. For example, the Right and Left String functions have a Pad named parameter that indicates the pad character to be used if the input string is shorter than the requested length:
%x = %y:right(20, pad='0')
In this case, the name simply makes the code clearer as without the name:
%x = %y:right(20, '0')
it's far less obvious what the second parameter means. In functions with large numbers of parameters, the named parameters can also be very useful for eliminating the need for placeholder commas, and for making the function invocations more readable. String and Float methods tend not to have a lot of parameters so named parameters are not heavily used for them, but they are used here and there, so it's important to understand them.
Stringlists
The object-oriented extensions to User Language are provided by Sirius Software and are only available at sites that can use $lists. Most sites that can use $lists, do use $lists because many Sirius $functions require them as input or outputs, and because they are just generally useful. $lists are essentially objects because an object is a container for information that is accessed via a reference variable, and multiple reference variables can refer to the same object ($list). For example:
%list is float %list2 is float ... %list = $listNew %list2 = %list1 $listAdd(%list, 'Now is the winter') print $listInf(%list2, 1)
In this example, the Print statement would end up printing “Now is the winter” even though the $listAdd added the line to %list. Both %list and %list2 ;point to the same $list (object) and, so, it is not surprising that what is added via %list can be seen via %list2. It is clear, too, that %list and %list2 must be pointers to $list objects and cannot be the objects, themselves, since a Float value couldn't possibly hold the contents of a $list.