Channels ▼


The Liana Programming Language

Source Code Accompanies This Article. Download It Now.

OCT93: The Liana Programming Language

Ray is senior technical editor of DDJ. He can be reached at [email protected]

Liana is both an object-oriented programming language and a development system for creating Windows applications. As a programming language, it strongly resembles C++, except Liana's syntax is smaller and less restrictive. Like C++, Liana uses classes and member functions to provide encapsulation, inheritance, and polymorphism. Unlike C++, Liana uses no pointers, offers automatic memory cleanup and typeless variables, and lacks multiple inheritance (which some might consider a feature).

As a development tool, Liana leans in the direction of interactive integrated systems such as Asymetrix Toolbook, Microsoft Visual Basic, or Digitalk Smalltalk/V for Windows. Like these systems, Liana provides a great deal of support for creating event-driven programs for the Windows environment. However, the current release of Liana is much less visual than these environments, relying solely on ASCII source files created with a text editor and compiled from the command line. Still, this compile-and-link cycle is relatively fast, painless, and can be easily done from a DOS window in the Windows environment. One benefit of the reliance on text files is that all program components are easily visible, unlike systems such as Visual Basic or Toolbook (the initial versions), in which programs consist partly of visible code fragments and partly of "invisible" data structures created by point-and-click means.

Liana 1.0 was released by Base Technology (Boulder, Colorado) for the Windows 3.0 environment in 1991. Liana 1.0 also runs on Windows 3.1. At this writing, Version 2.0 of Liana (in beta) adds numerous small enhancements to the language as well as providing an integrated-development environment (IDE) similar to those in many programming languages; the Liana IDE allows you to compile and link via a window/menu/buttonbar interface rather than from the command line. Base Technology has also demonstrated a 32-bit version of Liana for Windows NT. However, unless explicitly stated, this article refers only to the current release of Liana.

The principal design goal of Liana is to simplify and accelerate the process of writing Windows applications--especially those that are single-person in size or small in scale. Like Toolbook, Visual Basic, and Smalltalk/V, Liana works at a level of abstraction much higher than programming the raw Windows API with C or C++. The Liana system includes an application framework that packs in a goodly amount of built-in functionality. Consequently, many of the package's example programs are "one-liners" that concisely illustrate a particular subject. For example, the Liana version of the classic "hello world" program C programmers have used since time immemorial is main { (new window ("Hello world")).show; }.

While Liana does allow you to use the traditional printf("Hello world") instead of the intriguing statement above, the one-liner illustrates some of Liana's interesting aspects. The line of code completely defines the main function of a Liana program. It's similar to main() in a C/C++ program, except that, in Liana, functions without arguments don't need to be followed by an empty argument list. The function body that follows the function name consists of braces containing a single statement. This statement is a nested expression; the inner term invokes the new operator to create an instance of class window. The constructor call has one argument, which is the window title. The constructor returns an object reference which happens not to be stored anywhere, although it could have been assigned to a variable. Rather, the show() member function of this anonymous object is invoked. Because show() has no arguments, its empty argument list is omitted. If you understood all the jargon in this paragraph, then you've been reading too many C++ articles!) Happily, programming in Liana can be accomplished without much of the tedious baggage thrown onto the shoulders of C++ programmers. For example, the one-line program does not require a delete to match the call to new. Likewise, variables don't have to be explicitly declared, but are instantiated by using them in a statement. These become global in scope. Variables in Liana can be declared as one of the built-in types (int, real, string, Boolean, array, or Windows memory block), user-defined types (objects), or the generic type, any.

You may wonder what happened to main in this Liana one-liner, paint { w << "Hello world"; }. If you omit main, Liana invokes a default version of main which creates (and shows) an instance of class window and by default sets the global variable w to refer to it. As in C++, the left-shift operator (<<) is overloaded to provide printf-like output capability to the window object. In the case of this program, output occurs when the main application window needs repainting, via an automatic call to paint. The paint function is one of various callback functions Liana automatically invokes whenever an interesting event happens in the Windows environment.

Examples of interesting events include mouse click, mouse up, keystroke, window close, window paint, timer, and so on. These correspond to standard messages in Windows such as WM_LBUTTONDOWN, WM_MOUSEMOVE, WM_KEY, WM_CLOSE, WM_PAINT, WM_TIMER, and the like. The Liana language and its built-in application framework shield you from most of this "Windows grunge" (to use a Seattle-area term). In fact, the documentation doesn't mention any of the WM_* messages (although perhaps it should).

The one-line program position(x,y) { w.home; w << x << "," << y << " ";} consists of a callback function that's automatically invoked whenever the mouse moves. The function "homes" the cursor to the upper left of the main window, then displays the current x and y coordinates of the mouse.

Although Liana keeps you from getting mired in grunge--both the Windows and C++ flavors of it--you still have to deal with the essential concepts of event-driven programming and object-oriented structures. What's cool is that you can forget about the non-essential concepts: registering a window class, creating a window, exporting a WndProc in a .DEF file, writing #defines for an .RC file, making sure you dealt with the issue of whether SS equals DS, and so on. Likewise, you don't need to deal with similar C++ grunge, such as matching every new with a delete. However, at some point in using Liana, you'll likely have to declare a class and define its member functions--but not at the very start. If you were using a C++ framework such as OWL or MFC, there'd be many pages of documentation to absorb before you could begin to write code. Tools such as App-Wizard in Microsoft's Visual C++ package do help, but AppWizard can only be used once, at the very start. AppWizard is like getting a healthy push on a bike journey down a steep mountain road--you still have to navigate the sharp curves of C++ and MFC.

The freedom from mundane details that Liana provides can be exhilarating; but as you might expect, there's a price to pay for this freedom, mostly having to do with performance and scalability. In many cases, this will be worth it.

Example 1 (from the Liana package) shows a complete program that waits for a mouse down, then tracks the mouse and rubberbands a line. This program relies on overriding two standard callbacks, startdrag and drag--functions that are invoked upon a mouse-click and mouse-move event, respectively.

Example 2, an enhanced version of the program, brings up a window, rubberbands a line, stores it in an array structure, and redraws all stored lines as necessary (when the paint callback is invoked). I can't think of any other language that offers such economy of expression. Example 3 shows a two-line program that tracks the mouse and displays its position on a status line (a horizontal pane at the bottom of the main window to display prompts or other information to the user). As you can see, it takes longer to describe the program in English than Liana.

Liana provides programmatic access to the standard user-interface elements in the Windows environment, such as menus, listboxes, buttons, dialogs, comboboxes, and icons. Your program instantiates these UI elements dynamically via code, as opposed to defining them statically in an RC file. This means that if you want to change the text of a menu item, window title, or dialog prompt, you have to edit your program's source code--in contrast to Windows RC files, which can be changed without recompiling source code. However, I've always considered the distinction between running CC.EXE over source code versus running RC.EXE over data files to be pretty much meaningless. The two tasks are similar enough that, in practice, all such activity falls within the domain of program maintenance. In any case, Liana does provide a command-line utility called LXMOD that allows you to modify the values of global string variables (such as dialog prompts or window titles) without recompiling, for purposes such as internationalizing (localizing) an application.

One benefit of specifying your application's UI via code rather than data is that it gains more run-time flexibility. Also, Liana's scheme for specifying items in a dialog uses a higher level approach than that used by raw RC files. The constructs in Liana allow you to place items by specifying relationships (such as "under" or "east") instead of numerical units that have to be changed if, say, a label string gets longer or a fontsize is bumped up. Listing One (page 114) is a program that creates a dialog containing a group box, radio buttons, checkboxes, and edit controls. The disadvantage of Liana's high-level approach, of course, is that if you want non- default behavior (such as pixel-by-pixel positioning), it may be difficult or impossible to work around the built-in constructs. (This, of course, applies to any high-level class library or application framework that provides rich default behavior. Having the source code can help, but that approach is also problematic. In the case of Liana, the source to the application framework is not available in the basic package, but is available as an extra-cost option.)

One of Liana's biggest advantages, at least for C++ programmers, is its similarity to C++ syntax. In the linked-list sample program (see "Comparing Object Oriented Languages" by Michael Floyd, page 104), I basically started from the C++ version of the code, replacing cout with w and removing keywords like virtual and friend. Pointers became object references; for example, MyListElement *next was changed to MyListElement next. The program compiled and ran, but didn't produce the output I expected. I was a bit stymied by this, and wished for a debugger with which to step through the code. Fortunately, Jack Krupansky (Liana's author) found the problem. In the C++ version, class MyList is a friend of class MyListElement; in Liana, this reference to member data fails silently. Making the structure member next publicly visible solves the problem (see Listing Two, page 114). In the meantime, I implemented a different approach that makes all the list classes a subclass of Linkable (see Listing Three, page 114). I found I could basically think in C++ and not worry much about the differences between Liana and C++. Finally, Jack provided a more concise version that satisfies the linked-list protocol by using Liana's dynamic typing and built-in classes; see Example 4. The moral here is that converting an existing body of C++ code may be problematic, but writing Liana code from scratch is easy and natural, especially if you take advantage of its unique features. (I'm still wishing for a source-level debugger though.)

As with any system, Liana is not without problems. Some of its deficiencies will be addressed by the upcoming Liana 2.0. Others are inherent in its design--namely the performance hit that occurs with an interpreted language. Also, the syntax of Liana trades off scalability and maintainability in favor of conciseness, ease of use, and rapid development. For many Windows applications, this tradeoff will be well worthwhile.

Example 1:

startdrag (x1, y1, x2, y2)
    w.line (old_x1 = x1, old_y1 = y1, old_x2 = x2, old_y2 = y2);
drag (x, y)
    w.xor = true;
    w.line (old_x1, old_y1, old_x2,     old_y2    );   // Erase prev line
    w.line (old_x1, old_y1, old_x2 = x, old_y2 = y);   // Draw  new  line
    w.xor = false;

Example 2:

startdrag (x1, y1, x2, y2)
    w.line (old_x1 = x1, old_y1 = y1, old_x2 = x2, old_y2 = y2);
drag (x, y)
    w.xor = true;
    w.line (old_x1, old_y1, old_x2, old_y2);          // Erase prev line
    w.line (old_x1, old_y1, old_x2 = x, old_y2 = y);  // Draw  new  line
    w.xor = false;
enddrag (x, y)
    if (! lines) lines = new array;
    lines << new line (old_x1, old_y1, old_x2, old_y2);
    for (int i = 0; lines && i < lines.size; i++)
              lines [i].draw (w);

Example 3:

main { window();  w.status_line_enabled = true; }
position (x,y)  { w.status = x+","+y+"       "; }

Example 4:

class  MyList : array
          for (int i = 0, int n = size; i < n; i++)
                if ((any e = this [i]).isa ("MyList"))
                  cout << e.class_name+": "+e.text+"\n";
void main (void)
        MyList  list1 =   new   MyList;
        MyList  list2 =   new   MyList;
        int     n1 =      10;
        int     n2 =      20;
        point   p1 =      new   point (2,3);
        point   p2 =      new   point (4,5);
        /* build the lists */
        list1 << n1 << n2 << p1;
        /* an obj can be in more than one lst at same time */
        list2 << n2 << p1 << p2;
        list2 << list1; /* we can even put a list into another list  */
        /* print the lists */
        cout << "\nLIST1:\n";    list1.Print;
        cout << "\nLIST2:\n";    list2.Print;

by Ray Valdes


//----- Liana program that uses Windows controls in a dialog. ------
{       window (); = new menu
            << new menuitem ("&Language Info...");
        cr = "\n";
        d = new language_info_dialog;
        d.lang_name = "Liana";
        d.language_type = "object-oriented";
        d.provides_app_framework = true;
        d.has_ide = false;
language_info { if ( w.refresh; }
{       w.home;
        if (d)
            w <<   "  Language name: " + d.lang_name + cr
              + "  Language type: " + d.language_type + cr
              + "  Provides app framework: " + d.provides_app_framework + cr
              + "  Has IDE: " + d.has_ide;
class language_info_dialog: dialog
          string lang_name,
          bool   provides_app_framework,
          dialog ();
          this << new labeltext ("Language name:")
               << new edittext  (20, "lang_name");
          this [0].under;
          south ();
          this << new groupbox    ("Language Type")
               << new radiobutton ("&Procedural")
               << new radiobutton ("&Functional")
               << new radiobutton ("&Object-oriented")
               << new endgroupbox;

          this [2].after;
          this << new checkbox ("Provides app framework")
               << new checkbox ("Has IDE");
          this [6].under;
          this << new ok_button
               << new cancel_button;

<a name="02c2_000b">

//**** Linked list program that uses put_to ("<<") operator to append elements.
// by Jack Krupansky, 1993.
class  MyListData
            Print { cout << "Object of class "+this.class_name; }
struct  MyListElement
{           MyListData    data;
            MyListElement next;

            MyListElement (MyListData initialData)
                    data = initialData;
class  MyList : MyListData
{          MyListElement head;
           MyListElement tail;
            put_to (MyListData data)
                MyListElement newElement = new MyListElement (data);
                if (head) = newElement; // Append to non-empty list
                else       head = newElement;      // Start from an empty list
                tail = newElement;            // Point to the new end of list
                return this;
                for (int i = 0, MyListElement e = head; e; e =
class  MyNumber : MyListData
{           int value;
            MyNumber (int initialValue) { value = initialValue; }
            Print { cout << "    Number: " + value + "\n";}
{           int x, y;
            MyPoint (int initialX,int initialY)
                    { x = initialX; y = initialY; }
            Print { cout << "    Point: " + x + "," + y + "\n"; }
void main (void)
{       MyList   list1 =   new  MyList;
        MyList   list2 =   new  MyList;
        MyNumber n1    =   new  MyNumber (10);
        MyNumber n2    =   new  MyNumber (20);
        MyPoint  p1    =   new  MyPoint  (2,3);
        MyPoint  p2    =   new  MyPoint  (4,5);
        /* build the lists */
        list1 << n1 << n2 << p1;
        /* an object can be in more than one list at same time */
        list2 << n2 << p1 << p2;
        list2 << list1; // we can even put a list into another list
        /* print the lists */
        cout << "\nLIST1:\n";    list1.Print;
        cout << "\nLIST2:\n";    list2.Print;

<a name="02c2_000c"><a name="02c2_000d">
<a name="02c2_000d">

//*** Linked list program that subclasses "Linkable", by Ray Valdes, 1993. ***
class Linkable {
        Linkable next;
        Linkable GetNext    { return next; }
        SetNext(Linkable n) { next = n; }
        Print { w << "Should override this method.\n"; }
class MyPoint : Linkable {
        int x,y;
        MyPoint(int xx,int yy) { x = xx; y = yy; }
        Print { w << "Point ("+ x + "," + y  + ")\n"; }
class MyNumber : Linkable {
        int value;
        MyNumber(int v) { value = v; }
        Print { w << "Integer " + value  + "\n"; }
class MyList : Linkable {
        Linkable head,tail;
        int count;
        AddToList(Linkable item) {
           if(! head)  { head = tail = item; }
           else        { tail.SetNext(item); tail = item; }
        Print {
           for(int i = 0, Linkable x = head; i < count; i++, x = x.GetNext)
main {  (w = new window).show;  w << "Sample List Program in LIANA\n";
        MyList  list1 =   new   MyList;
        MyList  list2 =   new   MyList;
        MyNumber n1   =   new   MyNumber  (10);
        MyNumber n2   =   new   MyNumber  (20);
        MyPoint  p1   =   new   MyPoint   (2,3);

        // build the lists
        list1.AddToList (n1);
        list1.AddToList (n2);

        // an object can be in more than one list at same time
        list2.AddToList (n2);
        list2.AddToList (p1);

        // a list can contain another list as an element

        // print the lists (should also print the content of any sublists)
        w << "LIST1:\n";    list1.Print;
        w << "LIST2:\n";    list2.Print;
        w << "Done.\n";

Copyright © 1993, Dr. Dobb's Journal

Related Reading

More Insights

Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.