|
That's pretty much what's going on.
I don't mean that to be insulting. The problem is, you're having a very hard time
grasping the ideas of Dylan, because you're trying to think about them in terms of
the concepts of more traditional languages like C and C++.
In my various attempts to explain Dylan to non-Lisp people, I've discovered that
the biggest hurdle is getting people to see past the ideas of pointers, and call-by-
reference versus call-by-value parameter passing. Those concepts are all
borrowed from the Algol family languages, which Dylan isn't part of.
In Dylan, you pass *objects* around as parameters. Down in the implementation,
that's probably implemented as pointers, but it doesn't have to be. The key thing
is that when you pass a parameter, you're actually passing an *object*, which
has identity. If you insist on thinking of it as a pointer, you're going to get
confused. You're not passing a *value*, and you're not passing a *pointer*; you're
passing an *object*.
An object comes with a set of methods, exported from its home module, that
allow you to perform operations on that object. The implementor of the object's
class may give you access to operations that alter the object in some way, if that
makes sense for the object. That's fine - those operations still preserve the
object's *identity*.
In C++, you worry about passing a pointer to an object because that gives you
the ability to alter the objects identity, by writing a new object into the memory
that was formerly used by the original object. You have the ability to alter its
*identity* through it's pointer. In Dylan, you can't do that. Object identity is
guaranteed to be preserved. The attributes of the object might be altered, but the
identity remains the same.
Without the ability to alter an objects identity, all that you can do to it are perform
the operations that the implementor of that object gave you access to. That is,
anything that you can do to alter an object from outside of its defining class is
something that the implementor decided was OK for you to do! You can't
"damage" the object, because the only things that you can do to it are the things
that are "safe" for the definition of the object.
For example, if you perform a function on a mutable set, you can add items to
that set. That's because it makes sense to be able to perform alterations on a
mutable set, so its mutation operations are accessible to you. But if you get a
non-mutable set, you won't be able to add elements to it, because the
implementor won't export any mutation operators that act on it.
So what it all really comes down to is you end up with a different model of safety.
In languages like Dylan, guarantees of safety are provided by the implementor of
the class in terms of the operations provided for acting on instances of the class.
That's sufficient for making a strong guarantee of safety in Dylan, because of its
preservation of identity. If you're using to a language like C++, it seems like that's
not enough - because in C++, to make a program safe, you need to worry about
preserving identity *as well as* the kinds of safety that you need in Dylan.
This all means that the style of programming in Dylan is radically different. Safe
programming styles in C++ are very value oriented - the operate more on values
than on objects. They copy things all over the place, and use value equality rather
than object equality for comparison. In C++, you design objects to be used that
way - you expect things to be copied like crazy. You write operations on objects
in ways that don't make any real effort to preserve identity, because you know
that no one is going to rely on it. In Dylan, you expect copying to be very rare,
and write your programs in a fashion that is strongly reliant on the preservation of
identity.
|