I wrote: > > Overloading "final" was Java's rather inept attempt to > > define objects with value semantics rather than container semantics
John M. Dlugosz <[EMAIL PROTECTED]> wrote: > Can you tell me more about that, or point to something? Alas I can't point to anything, it's just a personal conclusion after years of trying to get Java to do things it was never intended to do. In Java, "final" is used to denote both a *class* that can't change (extend), and *value* that can't change (a constant member of the class). Except that if the latter is another object, it does nothing of the kind. It merely ensures that you can't change which object it points at, not that you can't change the members of that object. (There isn't even C++'s saving grace of const member functions.) So both of these are technical solutions looking for problems. Preventing class extension does mean you can optimize dynamic despatch, but that rather assumes that dynamic despatch is your limiting factor to begin with. (Fortunately P6 leaves finalization up to the user of the class rather than the author.) Anyway, optimizing dynamic despatch is just a combination of compile-time constant folding (establishing the method ID as a constant) and possibly generic "lifting" optimizations. Unfortunately lifting optimizations are actively thwarted by pervasive use of "container" semantics rather than "value" semantics. My favourite -- and worst -- example of "how not to do it" is Java's collection time-related classes (java.util.DateTime et al), which are containers in which you can keep a Date/Time value. Which is good, BUT there are no Date/Time classes that actually act as *values*: something that doesn't change, no matter where you got it from or who you give it to. With the standard Java classes you always have the mutator methods present: you can't get rid of them, you can't disable them, you can't nag about them at compile time, and in finalized classes you can't even override them to throw some sort of "DontUseMe" exception. So you can't be sure that the "value" that you're basing your computation on won't change when say you call the "print" function. And more importantly, neither can the compiler, which means a bunch of advanced optimisation techniques are unavailable. The current pervasive object model leaves it up to the class to decide whether it should behave as a value or a container, but offers no help or encouragement to the programmer to ascribe one or other intent to a class. I would like for P6 to have a way for a class to promise to the compiler that it provides immutable "value" semantics, not just "const" or "final" like Java, and for the compiler to check on that the class is sticking to that promise. And I'd like to hope that it will be easier (shorter) to write value classes than container classes, so that decent optimization will be available most of the time, instead of only when the programmer thinks to add the "immutable" tag (however it's eventually spelt). Some suggestions: 1. The very shortest way to denote a "value" rather than a "container" is also the simplest: if you make an assignment to an otherwise undeclared "variable" (omitting any declarator like "my"), you don't get a new container; rather, you define -- for the same scope as if it had "my" -- a value; a true, deep constant. Any subsequent assignment operator in the same or any inner scope is a compile-time error (including ++). If you *really* want a new constant with the same name in an inner scope, it has to be declared with "let". 2. A class can be declared using the keyword "Value" instead of "Class", in which case mutable (container) members are not allowed, and you get a warning if any base classes are not value classes (while in the background substitutes "BaseClass is immutable" for each "BaseClass"). 3. Define two methods VALUE() and CONTAINER(). Calling VALUE() gets you an object whose effective value can never change, even if you start with a mutable container. Calling CONTAINER() gets you an object which can be changed even if you started with a constant value. Pass a value to a function that expects a constant, and VALUE is implicitly called; conversely, pass a constant to a function that doesn't say it wants a constant, and CONTAINER is implicitly called. There are logically two ways that CONTAINER() can work: either (a) clone the object, changing its type and the types of any members (recursively) to non-constant members; or (b) create a new object which has one member that holds a reference to the original value object, and acts as a proxy for all other method calls. Whichever method is used, VALUE() does the corresponding reverse -- either it recursively clones an object with container semantics changing the type of each member to a constant value type, or it simply extracts the reference member. Either way, calling .VALUE() on a value object simply returns SELF. Option (a) is really only useful if you know how deep to go, which means you have to have seen the "container" class definition (and possibly have derived the "value" class automatically). So it makes sense to associate these two approaches with the suggested Value and Class keywords. -Martin (Or you could call them CONSTANT and VARIABLE I suppose; the names aren't important at this stage.) ----------------------------------------------------------------------------------------------- Have you seen our website?.... http://www.vodafone.co.nz Manage Your Account, check your Vodafone Mail and send web2TXT online: http://www.vodafone.co.nz/myvodafone CAUTION: This correspondence is confidential and intended for the named recipient(s) only. If you are not the named recipient and receive this correspondence in error, you must not copy, distribute or take any action in reliance on it and you should delete it from your system and notify the sender immediately. Thank you. Unless otherwise stated, any views or opinions expressed are solely those of the author and do not represent those of Vodafone New Zealand Limited. Vodafone New Zealand Limited 20 Viaduct Harbour Avenue, Private Bag 92161, Auckland 1030 Telephone + 64 9 355 2000 Facsimile + 64 9 355 2001