Home | About | Partners | Contact Us
SourceForge Logo

Quick Links

Home
News
Thoughts and Rants
License
SourceForge Info
Download
Browse CVS
Mailing Lists

XL Links

XL Home
The XL Touch
Basic XL features
Why use XL?
Compiler Status
Frequently Asked Questions
XL Mailing list

Understanding...

Concept programming
Moka
XL
Thin Tools
Active Libraries
Refactoring
Optimizations
Coda
Notes

More Info

Contributors
Related Ideas
Some history
Applications
Other links
The GNU Project

The XL Programming Language

Why are you doing that?
What is XL good for?
Why would I want to use it? Why does it look like Pascal?

See this page for an in-depth discussion of these questions.

XL is too verbose. Why so many keywords?

This comment is very frequent. But in reality, XL has about half the number of keywords of C++ for the same expressive power. XL is also quite often shorter than C or C++, in particular for non-trivial pieces of code. The following listing shows this on a typical piece of code, and this matches experience porting more significant pieces of code.
// C++: 12 lines, 261 characters
Item *FindItem(Item *first, Item *last, const char *name) {
	Item *ptr;
	for (ptr = first; ptr; ptr = ptr->next) {
		if (!strcmp(ptr->name, name))
			return ptr;
		if (ptr == last)
			break;
	}
	if (ptr == last && ptr->next)
		return ptr->next;
	return NULL;
}
// XL: 7 lines, 220 characters
function FindItem(Item first, last; string name) return Item is
	with Item ptr
	for ptr in first..last loop
		if ptr.name = name then
			return ptr
	if ptr = last and ptr.next <> NULL then
		return ptr.next
	return NULL

Besides the problem of dealing with an unfamiliar syntax, the real issue people express with these comments, I believe, are related to the cases where the XL syntax is significantly more verbose, in particular when this syntax happens to be often used in C and C++. This is essentially true for complex object declarations (functions, arrays, pointers), which are in general more verbose in XL than in C or C++.

The justification for introducing keywords is that the C and C++ syntax is ambiguous. This is well known and largely documented. In C and C++, which are closed languages, this is acceptable (although in C++, it quite often causes obscure programming errors). In XL, which is designed for extensions, this is not acceptable. The declaration syntax in XL allows the compiler to know what it is parsing, even if something like array A[1..10] of integer has been completely defined by a library. Also note that the notation is largely under control of the user: array A[10,integer] is also acceptable.

In practice, this verbosity is not a problem, for reasons that depend on the types being discussed:

  • Pointer types are used extremely infrequently in XL compared to C and C++, as the example above illustrates.
  • Specifying arrays with fixed size and type is also relatively infrequent. If a type such as array [1..10] of integer is used often, it is easy enough to give it a name.
  • A type like array being generic is often used in generic algorithms. In that case, the XL notation is shorter:
    procedure Sort(in out array A)
    template<class T, int N> void Sort(T A[N]);
    
  • Function declarations are easily searched for, something done often in practice by programmers. To search for function foo in XL, you search for "function foo". In C++, it is much more difficult.
  • Function declarations for non simplistic code are also not systematically shorter in XL than in C or C++:
    module BANK_ACCOUNT body is
       procedure Add(Client c) is ...
       procedure Remove(Client c) is ...
    
    #include "bank_account.h"
    void BANK_ACCOUNT::Add(const Client &c) { ... }
    void BANK_ACCOUNT::Remove(const Client &c) { ... }
    

Is XL strongly typed or not?

Yes, XL is strongly typed. However, it also has a root type, thing. More precisely, the base hierarchy is:
  • thing, from which all entities derive (including subroutines or types)
  • record, which derives from thing and is the base for all data objects
  • module, a constant record type for building program modules
  • object, a record type which can only be dynamically allocated. Anything deriving from objects behaves like Java reference objects.

Secondly, the any keyword allows the creation of entities with dynamic type. An entity declared as any object will receive any dynamic object. An entity declared as any record will receive any object, dynamic or stack-based. Finally, any thing can be used if you want to also be able to refer to types or subroutines.

// Adding debug code for anything
procedure Debug(any thing O) is
	Write "unknown object"
procedure Debug(any integer X) is
	Write X

Won't expression reduction be confusing?
What happens if you have both A+B, A*B and A+B*C?
How do you change operator priorities?

My experience so far did not allow me to find a case where expression reduction was confusing. It did allow me to find multiple cases where it improved significantly over C++ operator overloading.

Expression reduction selects the largest possible expression. If two candidates are ambiguous, the compiler warns you and picks one. You select the one you want using parentheses.

You cannot change operator priority. A+B*C is always parsed as A+(B*C). Of course, you can redefine a function that computes (A+B)*C for the above expression, but that wouldn't be smart. Named operators all share the lowest priority.

Where is the compiler? How advanced is it?

The compiler is under development. You can access it through the Mozart CVS tree. You can refer to the status page for details.

Why doesn't XL have 'classes'?

The type system in XL doesn't require a class keyword: class can be constructed. I have not made a final decision yet with respect to its implementation.

  • I could have a class type that behaves like record, but then people would try and write something like class X with... and get a class object rather than a class type.
  • Alternatively, I could have class be a synonym for type, which would be neat for Java or C++ users because they could write class Glop is... and get what they expect. But I don't really want to reserve a useful name such as 'class' for a keyword.
  • Last, my current preferred alternative, is to make class a built-in type with reflective behavior. In that case, you would be able to write class X is... and get the behavior you expect (a type definition, not an object definition), yet class would not be a keyword. In addition, the reflective behavior could automatically create C++/Java style shortcut notations for "member function" calls (i.e. you would be able to write a.f() rather than f(a))

So the reason class doesn't appear is because I did not make my mind yet, but it's likely to be a "library implementation detail" ultimately, although an important one. What matter is that the current syntax supports using class without requiring a modification of the compiler or language.

Why no private keyword? Information hiding is important!

Information hiding is important. But hiding the information is the best way to practice it :-) In XL, private implementation details are really hidden, they are not in the source code. In C++ or Ada, by contrast, they are not hidden but forbidden (using a private keyword). The XL approach allows you to use all the scoping rules to perform information hiding.

For instance, the following is a C++ class. Many developers would walk away from a class that looks like this, assuming incorrectly that it can store only a few books, and saying "that's stupid". This shows that our knowledge (or what we think we know) of the internal details of the implementation influences if and how we use the class.

class Library
{
public:
  void AddBook(Book *bk);
private:
  Book *books[32];
  int numbooks;
};

In contrast, the same interface in XL would look like the following. No private information leaks out. The implementation is free to intelligently hash book entries alphabetically without having users making incorrect assumptions on the behavior of the class.

type Library
procedure AddBook(in out Library L; in Book b)

Does XL support functional programming?

The short answer is: yes. Functional programming is defined by three essential characteristics.

  1. The value of a function depends only on its arguments
  2. Objects are immutable. Rather than modifying objects, one creates new objects.
  3. Functions are first class objects: they can be used in expressions, passed as arguments, part of a data structure, and function literal can be created ("lambda functions")

XL does not always respect the first rule, and is therefore not a pure functional language. Most functional languages are not different in that respect: as long as you allow a user to enter data, the output of the function that reads user input doesn't depend solely on its inputs. However, in XL, the {functional} pragma can be used to indicate that a given function has no side effects and that its result only depends on the input arguments. In this case, the compiler is allowed for instance to optimize f(1)+f(1) into 2 * f(1).

The second aspect is not enforced by XL: XL does have pointers. This is necessary to create data structures which are difficult to create with languages that respect the rule, such as circular lists or cyclic graphs. On the other hand, it is possible to write XL code that completely respects the rule (this would be very difficult in C or C++)

XL does qualify for the last aspect. Functions as objects are a necessity for convenient use of reflection. See for instance how the tasking example uses functional bodies for the task objects. XL also has support for other properties often associated with functional programming, such as lists, garbage collection and weak typing.

However, it is important to understand that the functional approach is often not the most efficient one in XL. For instance, closures and lambda functions are often conveniently replaced with generic code and functors in XL.

But functions are not first class objects

Yes, functions are indeed first class entities. They can be assigned to an any thing type, they can be created dynamically, they can be processed at compile-time using compiler plug-ins.

On the other hand, the compiler internal representation of a function as an object (for reflection) is distinct from the representation of a compiled function (a code pointer). The downside is that the structure of A+B is not A-then-plus-then-B (matching the source code as it would in Lisp), but rather a tree with + at the root and name leafs. This surprises Lisp hackers, since the mapping between the source code and the internal compiler structure is much less obvious than in Lisp.

The upside is that the representation can contain additional information (such as the structure of the generated code or optimization annotations.) Also, it improves readability of the source code when you don't care about its reflective properties (which is most of the time). For most programmers, A*B+C is easier to read than (+ (* A B) C).

It's the fragile base class problem, not the weak base class!

The two problem are subtly different, if related. It appears that Daveed Vandevoorde and I may have created the terminology and I was not aware of it. This is why I used it as if it was standard terminology.

  • The fragile base class problem is the issue that modifications in the base class may break derived classes that use it. The base class is fragile because changes in it break its role as a base class. The fragile base class is essentially a maintenance problem.
  • The weak base class problem is the issue that a class cannot be reused because it lacks necessary functionality, and said functionality cannot be added without "opening" the class, which may not be acceptable if the class is not owned (e.g. a library class). The base class is weak because you can't build on top of it. The weak base class is essentially a software reuse problem.

Object-oriented languages with weak typing such as Objective-C or Smalltalk don't generally have the weak base class problem. XL solves the problem while preserving (not mandating) strong typing. XL also helps solving the fragile base class problem by allowing better encapsulation, but it doesn't totally eliminate it.


Copyright Christophe de Dinechin
First published Feb 17, 2000
Version 1.5 (updated 2002/11/20 16:39:34)