Re: Clean Object Class Design -- Circle/Ellipse

From: Dave Harris <brangdon_at_cix.co.uk>
Date: Thu, 18 Oct 2001 15:27 +0100 (BST)
Message-ID: <memo.20011018152753.28767D_at_brangdon.madasafish.com>


bbadour_at_golden.net (Bob Badour) wrote (abridged):
> All values are immutable, and all variables are mutable. Why shouldn't
> the language recognize that fact directly?

I'll rephrase that as, Why shouldn't the language distinguish between mutable and immutable objects? And the answer is, because it doesn't consider it worth it.

The problem is that the language cannot easily tell the difference between logical state and implementation state. For example, merely knowing that an instance variable is being assigned to, does not tell whether that variable is part of a cache which effects only performance. This means we need something like the "const" keyword C++ uses to annotate methods, and also "mutable", "const_cast<>" and some way to distinguish between "part of" and "uses" references. It is a lot of overhead.

And it is to no avail. Recall that Smalltalk is dynamically typed. Even if Circle is not a subtype of Ellipse, the language will allow variables to be attached to instances of both classes. So the language would not be doing anything with the mutable/immutable distinction. Subtyping in Smalltalk is rather more fluid than in statically checked language. It does not believe in casting such relationships in stone.

Another problem is that classes can be subtypes even if they are mutable. For example, a Point might have methods to change its X and Y coordinates, and a ColouredPoint might have all that plus methods to change its colour, yet we can use a ColouredPoint anywhere a Point is expected, so it is a subtype. You said earlier that immutable Circle is a subtype of immutable Ellipse, and mutable Circle is not a subtype of mutable Ellipse. This is true but it's not a general rule. We need to know more about the semantics of the classes, and the programmer's intentions.

Finally, I don't think I've ever really wanted to have two kinds of Ellipse, mutable and immutable, and then derive the 2 kinds of Circle, and then have the language infer the appropriate subtyping. It may be theoretically possible, but it's not something I seem to need in everyday programming. Nor have I wanted to selectively inherit non-mutating methods only.

Do you have a language in mind which works like that? Or are these just your own ideas? I know several languages, notably C++ and Eiffel, which wanted to distinguish between mutating and non-mutating methods, but which were not very successful at it.

> In other words, one can overcome Smalltalk's deficiency by studiously
> avoiding the definition of any update operations (except assignment)
> on variables of the types in question. To change the state of an
> ellipse variable, replace the entire value of the variable en masse.

Assignment is not an exception. In Smalltalk, assignment is something which happens to variables, not to objects. We never define assignment for instances of Ellipse. There is no "ellipse variable".

There may be a variable which refers to a particular ellipse object, and we can make it refer to a different ellipse object, but this does not change the original ellipse. You say, "replace the entire value" as if the memory used to store the ellipse's representation was being overwritten, but that isn't what happens. Instead a pointer is updated to point to the new representation.

Things like this make me question whether you get what is going on in Smalltalk.

> This might work for a small and simple class such as Ellipse. What
> happens when the class has many more attributes and much more complex
> state? Would the idiom scale?

I don't like the word "state" here, since it is usually means "mutable state". We are talking about Ellipses that have no state. They have representation.

I believe the idiom scales as far as not accidentally adding a mutating method is concerned.

> Are there no advantages to requiring additional expertise and skill
> from the language designer and to requiring less expertise and
> skill from the language user?

This is really the argument about static, compile-time type-checking versus dynamic, run-time type-checking. I don't want to repeat all that here. Smalltalk offers a programming model which is very clear, very simple and very flexible. In particular, it is clear about what is and isn't a variable. Your proposal seems to make the language more cluttered, more complex and less flexible.

I would cite C++ as an example of how complex static declarations of immutability can get. I don't believe it is really helping the inexpert user.

> (I must say: It's refreshing that a sensible Smalltalk programmer has
> finally joined the discussion.)

Thanks. I would feel more flattered if I hadn't already posted several comments before that one. I think what really happened is that you posted a better question.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,

      brangdon_at_cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ | And drunk the milk of Paradise." Received on Thu Oct 18 2001 - 16:27:42 CEST

Original text of this message