Dylan programming language
Dylan is a dynamic programming language created by a group led by Apple Computer. It was originally intended for use with Apple's Newton computer, but their implementation did not reach sufficient maturity in time, and they instead developed NewtonScript for that project. A "technology demonstration" version for writing Macintosh applications was released in 1995, based on an advanced IDE, but by this time Apple had already publicly abandoned Dylan, and developers avoided it even at the $29 price. The language design was intriguing enough that two other groups developed optimizing compilers for Dylan: Harlequin Inc. (now Functional Objects) released a commercial IDE for Microsoft Windows, and Carnegie Mellon University released an open source compiler for Unix systems. Both implementations are now being maintained and extended by a group of volunteers as Gwydion Dylan.
Dylan is essentially a cleaned-up version of CLOS, an object-oriented programming system built on Lisp. In Dylan, almost all entities (including primitive data types, methods, and classes) are first-class objects. One tremendous advantage of Lisp-like languages is that nearly every component of the system, including the actual language itself, can be modified from within the language. This makes Lisp systems incredibly flexible. However many programmers have been turned off by Lisp's seeming odd and unfamiliar syntax. Another issue is that most Lisp systems, because of their dynamism and flexibility, did not always perform as well as more static programming languages. For various reasons, Lisp did not enjoy widespread use for developing commercial software.
Dylan's main design goal was to be a dynamic language well-suited for developing commercial software. Dylan attempted to address the performance problem by introducing "natural" limits to the full flexibility of Lisp systems, allowing the compiler to clearly understand compilable units. Early versions of Dylan were otherwise similar to existing CLOS systems, but developer feedback in the 1993 era forced them to send the product back into engineering and produce a clearer syntax as well.
Modules vs. namespace
In most OO languages the concept of class is the primary encapsulation system; the language is generally thought of as "a way to make classes". Modern OO languages often also include a higher level construct known as the namespace in order to collect related classes together. In addition the namespace/class system in most languages defines a single unit that must be used as a whole, if you want to use the String.concat function, you must import and compile against all of String, or the namespace that includes it.
In Dylan the concepts of compile-unit and import-unit are separated, and classes have nothing specifically to do with either. A module defines items that should be compiled and handled together, while an interface defines the namespace. Classes can be placed together in modules, or cut across them, as the programmer wishes. Often the complete definition for a class does not exist in a single module, but is spread across several that are optionally collected together. Different programs can have different definitions of the same class, including only what they need.
In addition, many interfaces can be defined for the same code, for instance the String.concat could be placed in both the String interface, and the "concat" interface which collects together all of the different concatenation functions from various classes. A more practical use of the interface construct is to build public and private versions of a module, something that other languages include as a "bolt on" feature that invariably causes problems and adds syntax.
Classes in Dylan describe "slots" (data members) of objects in a fashion similar to most OO languages. All access to slots are via methods, a feature of most dynamic languages. Default getter and setter methods are automatically generated based on the slot names. In constrast with most other OO languages, other methods applicable to the class are defined outside of the class, and thus class definitions in Dylan typically include the definition of the storage only. For instance:
define class <window> (<view>) slot title :: <string> = "untitled", init-keyword: title:; slot position :: <point>, required-init-keyword: position:; end class;
In this example the class "window" is created. The <class name> syntax is convention only, to make the class names stand out. In most languages the convention is to capitalize the first letter of the class name, but this is similar in concept and not a part of the language itself. Window inherits from a single class,
In languages such as C++ or Java, the class would also define its interface. In this case the definition above has no explicit instructions, so in both languages access to the slots and methods is considered
Dylan also uses multiple inheritance, but the developers spent enough time on the classloader to avoid the problems that continue to make many uninformed programmers believe that multiple inheritance is a "bad idea".
Methods and Generic Functions
In Dylan, methods are not intrinsically associated with any particular class. (Methods can be thought of as existing outside of classes.) Like CLOS, Dylan is based on multi-methods, where the specific method to be called is chosen based upon the types of all its arguments.
The Dylan analog of a method is the method, but that simplifies the matter too much. In most OO languages the methods are defined as an integral part of the class itself, meaning that if you wish to use a method from another class it must be imported and called in a wrapper in your class.
In Dylan code is isolated from storage in functions. Many classes have methods that call their own functions, thereby looking and feeling like most other languages. However functions may also be generic functions, meaning they are not attached to a particular class, and can be called natively by anyone. Linking a particular generic function to a method in a class is accomplished this way:
define method turn-blue (w :: <window>) w.color := $blue; end method;
This definition is similar to those in other languages, and would likely be encapsulated within the <window> class. Note the := setter call, which is syntactic sugar for
Generic methods come into their own when you consider more "generic" examples. For instance, one common function in most languages is the
This might strike some readers as very odd. The code to handle to-string for a window isn't defined in <window>? This might not make any sense until you consider how Dylan handles the call to to-string. In most languages when the program is compiled the to-string for <window> is looked up and replaced with a pointer (more or less) to the method. In Dylan this occurs when the program is first run instead, the runtime builds a table of method-name/parameters details and looks up methods dynamically via this table. That means that a function for a particular method can be located anywhere, not just in the compile-time unit. In the end the programmer is given considerable flexibility in terms of where to place their code, collecting it along class lines where appropriate, and functional lines where it's not.
The implication here is that a programmer can add functionality to existing classes by defining functions in a separate file. For instance, you might wish to add spell checking to all <string>s, which in most languages would require access to the source code of the string class -- and such basic classes are rarely given out in source form. In Dylan (and other "extensible languages") the spell checking method could be added in the
This still might not sound all that obvious, but in fact it is a common problem faced by almost all OO languages -- not everything fits into a class construct, many problems apply to all objects in the system and there's no natural way to handle this. For instance Java is currently attempting to add this sort of system in AspectJ, but this is proving very difficult and many Java programmers question the need for it in the first place. Suffice it to say, once you have used a language that allows extensions, you'll never want to go back.
A concrete example of this flexibility is what most other languages refer to as aspect oriented programming, where a particular function "cuts across" most of the objects in the system. This functionality cannot be provided in the basic language, leading to a series of add-ons and non-standard versions of the language as they invariably attempt to add it at some later date.