[Prev][Next][Index][Thread]

A Dylan FAQ (was Re: Good book on Dylan)



I've answered a good many of these questions. Anyone want to take on
the rest and correct my errors?

On Thu, 5 Apr 2001 07:19:18 -0400 (EDT), Rob Myers <robmyers@mac.com> wrote:
>The FAQs I can think of are:
>
>Dylan FAQs.
>
>1. Background.
>
> o Who created Dylan?

I'll let someone who was there answer this.

> o What implementations are currently available?

There are two major implementations available.

Functional Developer is a commercial Dylan implementation sold by
Functional Objects, Inc. (http://www.functional-objects.com) It is
currently available for Windows, and features a very sophisticated IDE
and a high-performance native-code compiler.

Gwydion Dylan (http://www.gwydiondylan.org) is an open-source
implementation that is mostly aimed at Unix-like systems (including
Mac OS X and Cygwin). It is, like most Unix compilers, a command line
app, and it compiles using C as an intermediate form.

> o Is it available on my platform?

Probably. See above.

> o Is there a standard?

There is no ISO or ANSI Dylan standard, but _The Dylan Reference
Manual_ written by Andrew Shalit (ISBN 0-201-44211-6) exists, and
incompatibilities with it are usually treated as bugs. Also, both
major implementations work to make sure that their libraries are
intercompatible.

> o Is there a reference implementation?

Not in the sense of Perl or Python, no. 

> o What does the name mean?

It's a portmanteau word, from the phrase "DYnamic LANguage."

> o So was is taken from Bob Dylan or Dylan Thomas?

Dylan Thomas. 

> o Wasn't Dylan used for programming Newtons?

Someone y

> o Is Dylan a Functional Language or an OO Language?

Yes. :)

Dylan has first-class functions, proper lexical scoping, and is
usually tail-recursive: that's from the functional universe.  It also
has multimethods, inheritance, and "objects all the way down": that's
from the OO universe.

The combination is very powerful and a lot of fun to program in.

>2. Ancestry.
>
> o Is Dylan a form of Lisp?

Yes, to the same extent that Scheme is a Lisp. You can think of Dylan
as the offspring of Scheme and CLOS, and you won't be too far wrong.

>o What happened to the Lisp syntax?

[This is a guess.]

It went away when macros were added -- when you write a macro in one
synatx, there's no way to autogenerate macros for the other syntax.
As a result, this meant that keeping two syntaxes would be painful,
and one went away. It happened to be the Lisp syntax.

> o Where can I find a copy of the Lisp syntax?

[Don't know]

> o Why don't you re-implement the List syntax?

See above.

>3. Gotchas and Good Practice.
>
> o Why do I have to leave spaces between every single token?

Because Dylan has a very rich syntax for identifiers. The graphical
ASCII characters, like '?', '!' and '-', are all legal as parts of
Dylan identifiers, and this means that you need to put spaces to
distinguish 'twelfth-elephant' from 'twelfth - elephant'.

> Why should I use a naming scheme?

[What does this question mean?]

> Why should I avoid calling functions "element" or ...?

Dylan is lexically scoped, and methods are simply functions bound to
names. If you name a variable "element", then you will shadow all
references to the module-level "element" within the lexical scope of
the block. Since the "foo[bar]" notation for element access is just
syntactic sugare for "element(foo, bar)"

In other words

  begin
    let v = #[1, 2, 3, 4, 5];
    let elt = 'x';	
    v[4];
  end;

will yield '5', the last element of v.

But doing

  begin
    let v = #[1, 2, 3, 4, 5];
    let element = 'x';
    v[4];
  end;

will yield an error. This is because "let element = 'x';" rebinds the
element() method to the character 'x', and this means that you will
try to call the character 'x' as a function in the last line. Not
happy. Likewise, this is also true for object slots, names in the
Dylan module and top-level functions.

> o What does object.slot() mean?

Let's do this step by step. The "." syntax is just sugar for a
function call -- "foo.bar" is the same thing as "bar(foo)". So
"object.slot()" is just the same as "slot(object)()".

In other words, we are calling the 'slot' method of 'object', and then
calling it as a nullary function. (Remember that functions are first-
class in Dylan, and can be stored in objects and variables just like
any other data.)

> o What do =, =, := and == mean and what are the wrong ways to use them?

[Why are there two "="s?]

\= and \== are the two equality methods in Dylan. \== is the object
identity method; it return #t if the two objects it compares are the
same object. You can think of this informally as asking if the two
variables being compared point to the same hunk of memory. This is
akin to the 'eq?' function in Scheme, or the Python 'is' operator.

\= is the semantic equality predicate. It should return #t if the two
objects *mean* the same thing. It's like "equal?" in Scheme. \= is
predefined for the built-in classes, but it's extensible to cover the
classes you define.

As a rule of thumb, you probably want to use \== unless you
deliberately want to test for object identity. 

':=' is the syntax used to spell assignement in Dylan. There's a bit
of syntatic sugar in the ":=" macro. If you are assigning to a
binding, then the usual imperative update of the variable happens.
When assigning to collections or to slots, the := syntax expands
into a setter method. That is,

  v[x] := 4;
  object.slot := 7;

is equivalent to

  element(v, x) := 4;
  slot(object) := 7;

is equivalent to

  element-setter(4, v, x);
  slot-setter(7, object);

When you write a -setter method of your own, you should take care that
it *always* return the value that the object was set to. People sometimes
write code like this:

   foo.bar := baz.quux := thingy;
  
and use assignment as an expression. If you don't return the set
value, you lay the groundwork for some dramatically perverse bugs.

> o How do I initialize a slot?

Usually, you use a slot-specification in the define-class statement.
Here are some examples:

  define class <foo> (<object>)
    slot bar,
      required-init-keyword: bar:;
  end class;

This means that there will be a keyword argument "bar:" in the
make(<foo>) call, and that an error will be signalled if it's not
present.

  define class <foo> (<object>)
    slot bar,
      init-keyword: bar:,
      init-value: 42;
  end class;

This means that you may call with a keyword argument like
"make(<foo>, bar: 14)", but that if the keyword bar: is absent
the slot will default to 42.

  define class <foo> (<object>)
    slot bar,
      init-function: method() seconds-since("15 Jan 2001") end,
  end class;

An init-function slot specification means to call the zero-argument
function to get the value to initialize the slot with. You can mix and
match init-keyword, and init-value/init-function arguments and they
will generally have the obvious effects.

You should try to supply initializers whenever possible; this makes it
possible for the compiler to prove that the slot is never unbound, and
lets it generate slightly faster code (since it doesn't have to
generate tests to see if the slot is unbound at each access).

> o What is initialize()?

[Someone else can do this. I've never used initialize() in anger. :]

> o What are unsupplied() and false-or().

[I'll just take false-or(), someone else can do unsupplied().]

false-or() is a function that creates a new type from an old one.
(Everything is an object in Dylan, including classes and types.)

Specifically, false-or(<foo>) returns a new type that returns #t for
exactly all the values that instance?(x, <foo>) returned #t for, plus
the value #f is also an instance of false-or(<foo>).

This is useful when you want to add an out-of-band value to a type.

>4 Language Design.
>
> o What are keyword parameters?

Most functions distinguish there arguments by position. Keyword
arguments let you identify arguments by their name. Eg, the
call

  range(from: 0, to: 10)

returns a sequence of integers from 0 to 10, inclusive. This
would be declared in Dylan with something like:

  define method range(#key from :: <integer>, to :: <integer>)
   => (s :: <range>)
    // implementation
  end method;

> o What are they good for?

"If you have a procedure with ten parameters, you probably missed
some." -- Alan Perlis

Whenever you have functions with a lot of parameters, it's *very*
convenient to be able to simply name them. This comes up a lot in GUI
programming in particular. 

> o What is a generic function?

A generic function is a special kind of function that contains a
collection of methods. When it is called, it does no work other than
selecting a method based on the types of the arguments, and then it
passes the arguments on to the method it selects. Think of it as a
kind of C++ like virtual function that a) doesn't have to live inside
a class, b) is a first-class function, and c) can dispatch dynamically
on more than one argument.

> o Where can I read up more of generic function implementation?

The Cecil project at the University of Washington has a ton of papers
describing how to optimize multimethods and other OO features.

 http://www.cs.washington.edu/research/projects/cecil/www/Papers/papers.html

Of particular note for multimethods is

 "Efficient Multiple and Predicate Dispatching"

 http://www.cs.washington.edu/research/projects/cecil/www/
  Papers/dispatching.html

Johnathan Bachrach implemented the algorithms described in this paper,
and reports a good performance enhancement in the Fun-O compiler.

Dujardin and Amiel's paper "Fast algorithms for compressed multi-dispatch
tables generation" describes another appraoch. To my knowledge this has
not yet been implemented in a Dylan compiler, but Eric Kidd is currently
investigating it for his thesis. 

Also of interest is "Optimization of Object-Oriented Programs Using
Static Class Hierarchy Analysis" (This shows how compilers can use
Dylan's sealing directives.)

http://www.cs.washington.edu/research/projects/cecil/www/Papers/hierarchy.html

> o What GF dispatch algorithm does Dylan use?

Depends on the compiler.

Gwydion Dylan first tries to eliminate GF dispatch altogether using
compile time analysis of the types of the arguments. If it can't do
that, but can narrow it down to a set of methods known at
compile-time, it will often generate a function that does dispatch as
a set of nested if-statements. If it can't do that, it uses a slow,
fully general dispatch algorithm, but caches the types of the last
call. There is also a seperate path for one-argument GFs, which can be
optimized somewhat more efficiently.

> o Why don't objects own methods?

Because using generic functions makes multimethods very natural to use
and provides an elegant solution to the binary method problem.

Consider numbers, and the addition operation on them. We would expect
an OO language to do the natural conversions between (say) integers
and floating point. In a singly-dispatching language, each addition
method would have to know about all of the other classes that it can
receive as an argument. When you add (for example) bignums to the mix,
every addition method of every class needs to be updated. This is
very messy.

In Dylan, you would only need to add exactly the methods to add
bignums, and you wouldn't need to touch the other definitions.

Generic functions also makes the Visitor pattern utterly transparent,
and consequently make the Interpreter pattern trivial to implement.

[example goes here]

> o What is common-dylan?

Common-dylan is the set of libraries and extensions that both Gwydion
and Fun-O have agreed to support. This includes things like the stream
interface, the threading model (though GD doesn't do threads yet), and
so on.

> o Why does it take three files to compile "hello world"?

[I don't know.]

>5. Language Comparison.
>
> o Does Dylan have a MOP?

No. It was apparently deemed to big a performance hit.

> o Can Dylan load arbitrary libraries and methods like Java can?

There's no standard way of doing this. Functional Developer can do it
with LoadLibrary. Note that a lot of what Java uses class loading for
can be replaced with Dylan's first-class types and functions.

> o How do I get Java/C++-style access control in Dylan?

Modules in Dylan are used to control access. A common idiom in
Dylan is to see module declarations like this:

  define module foo-internals
    use dylan;

    export foo, foo-setter, bar, baz, quux, <tharp>;
  end module;

  define module foo
    use dylan;
    use foo-internals,
      export: {<tharp>, baz, quux}
  end module;

> Can I use Dylan for DB/Graphics/Network/XML/etc?

Probably. Ask on comp.lang.dylan.

>6. Resources.
>
> o Where can I find Dylan code on the Internet?
> o Where can I find Dylan tutorials on the Internet?
> o Where can I find Dylan white papers / overviews on the Internet?
> o What books on Dylan are available?



Neel



Follow-Ups: