From: Allison Randal <[EMAIL PROTECTED]>
   Date: Wed, 11 Apr 2007 01:12:57 -0700

   Alek Storm wrote:
   > On 4/11/07, Bob Rogers <[EMAIL PROTECTED]> wrote:
   >> Surely you are not suggesting that any random "add_method" should
   >> require creating a new class?  Did you mean "add_attribute" (or
   >> whatever)?

   I did mean that, but only if the class has already been instantiated. 
   ('add_method' can add an additional multi, for example, so it can modify 
   existing behavior.)

Hmm.  If a Lisp implementation ever worked this way, FWIW, it would be
considered buggy.  It would also make developing Lisp code harder than
necessary, as it is normal to start development of a class by defining
it interactively, creating a few instances, adding methods, calling
them, adding more methods, making more instances, and so on, all within
the same session.  Lisp uses expect that newly-defined methods will work
immediately for old instances of those classes.

   Come to think of it, I also do the same sort of thing in Perl 5:  At
some time during the execution of my program, I load a file that adds
methods to another class defined elsewhere (though the class may not
actually have instances at that point).  It's not terribly clean in Perl
5, 'tis true, but it can't be that rare.

   But now that I've brought up Lisp, I should clarify my position.  I'm
still not sure how I would go about implementing ANSI-compliant Lisp
objects for Parrot.  As a result, I have stayed mostly silent on objects
because (a) I don't know what I want yet, and (b) I assume I will have
to do a lot of PMC subclassing anyway, so that would allow me to
override whatever doesn't work for me.  In any case, Lisp only uses
multimethods -- the first arg to add-method (and remove-method) is a
generic function, not a class -- so I don't expect to need add_method
anyway.

   So I mention Lisp behavior not because I think Parrot ought to behave
that way, but as a way of explaining why this surprises me.

   >> The remove_* operations could stay, they would just
   >> throw errors on instantiated classes.

   They could, but how often are people going to add a bunch of attributes 
   and methods and then remove them immediately before they ever 
   instantiate the class? . . .

When the class is cloned, the 'instantiated' bit should be cleared,
because there are as yet no instances of the cloned class.  So then
remove_* would be useful on the clone.  True?

   > Not all languages want to clone their classes on modification.  These
   > languages would use their own class PMCs that don't clone themselves.

   They might not clone their classes from the user perspective, but 
   internally it's the only truly safe way to modify a class that already 
   has objects instantiated (especially when you're talking about remove 
   operations). Otherwise, you have objects referencing attributes that 
   don't exist any longer in the class, or methods referencing attributes 
   that were never initialized in the object. The closest they can come is 
   the option 1) I listed.

Note that Lisp uses a form of option 1, where an old instance is updated
to the new class structure at some time before its slots (attributes)
are next accessed [1].  I understand there are ways of making this
update relatively cheap, without slowing down other method dispatch, but
I'm afraid I'm not familiar with them.  In any case, it need not be all
that cheap, because it's not really needed in production code.

   > If one of their classes is passed to and cloned by a different HLL,
   > their class system will be screwed up/inconsistent.  I'm not sure how
   > requiring HLLs to deal with explicit cloning would be simpler than
   > having it abstracted away.  This system is much more flexible.

The normal use case for this class-changing API, it seems to me, is to
redefine an HLL class definition incrementally by recompiling it.
Having one HLL mutate the class of another HLL seems relatively arcane.
Are you suggesting that this is a bad idea simply because it can be
abused in this manner?

   Despite being arcane, and assuming the operation makes sense at all,
I would argue that this scenario still ought to work.  If the basic
Parrot classes support mutation, then even an HLL that normally defines
inflexible classes ought to inherit that mutability, unless it does
something explicit to disable it.  In which case, it ought to disable
the "clone" op as well.

   The point about abstraction is a good one. It can also be satisfied by 
   the 'clone' method/vtable. If a class has a different way of handling 
   modifications, it can return a modified version of itself instead of 
   returning a new clone (in those cases where the cloning operation was 
   flagged as a modification of an existing class).

Would the code that does the class mutation need to do anything
different with the result in the "clone" vs. "no clone" case?  I.e. in
terms of mutating it further, or doing something to finalize the
changes?

   What if the mutated class has subclasses?  I imagine they would need
to be cloned (automatically or not) as well?

   >> Error recovery would also be easier for explicit cloning; what happens
   >> if one of the class-mutating methods throws an error?
   > 
   > I'm afraid you lost me.  How would this be different?  Could you
   > provide some more information?

   Essentially, what if you call 'add_method', it automatically clones the 
   class, and the automatic cloning fails for some reason? Then you get a 
   mysterious exception about "failed to clone class", leaving the average 
   user wondering why it was trying to clone a class in the first place.

   Allison

Here's another example:  Suppose you change a class definition in such a
way that several attributes are deleted, and a few more are added.  If
that looks like an single operation at the HLL level, even though it
takes a slew of Parrot ops, then you want to be sure that the class
manipulation succeeds completely before replacing the original class
definition as the one that find_class should return.

                                        -- Bob

[1]  http://www.lispworks.com/documentation/HyperSpec/Body/04_cf.htm

Reply via email to