After a week's delay where I've just been too busy,
I thought I'd resurrect the corpse of a thread I was involved in.....

First off,

on Wed, 07 Feb 2001 14:37:33, Dan Sugalski <[EMAIL PROTECTED]> wrote:
> At 07:05 PM 2/7/2001 +0000, David Mitchell wrote:
> >Dan, before I followup your reply to my list of nits about the PDD,
> >can I clarify one thing: destruction.
> >
> >I am assuming that many PMCs will require destruction, eg calling
> >destroy() on a string PMC will cause the memory used by the string
> >data to be freed or whatever. Only very simple PMCs (such as integers)
> >need to do no detruction.
> >
> >Is this the same as your perception of reality :-) ?
> 
> Nope. The things that call destroy will be those things that have some sort 
> of active destruction. Freeing memory doesn't count in this case, since the 
> plan is to have some sort of external garbage collector that handles that.
> 
> >I also gather that PMCs will have a flag saying whether they need destroying,
> >(eg ints say no, strings say yes), and that calls to destroy() are preceeded
> >by a check on this flag for efficiency?
> 
> Yep, though strings will be a no in this case.

Ah, I see. I really must get my head round this GC business (my copy of
the GC book is on order, but alas hasn't yet arrived :-( ).

As a quick aside, If a PMC contains a pointer to a string, is there ever
any need to set that pointer to NULL to allow the GC to reclaim the string?


Given that PMCs will have a flag saying whether they need destroying,
the naive view is that the external API definition for vtables will
say 'you must check the NEED_DESTROY flag, and if true, you must call
the destroy() method'. I'd regard this an implementation and optimisation
detail which should be hideen from the user. Instead, I'd prefer
that there be a standard set of macros to invoke methods, and that
the macro for destroy() checks the flag before calling the real
method. Then the API docs just say 'you must always call destroy()'.

Similarly, I suggest that PMC flags appear (via the use of macros)
to be identical to vtable methods. So that as implementations change,
whether something can be determined purely by examining a flag or needs
to be done via a full method call, is hidden from the user.

Or to put it another way, PDD 2 should pretend that everything is
a method, and whether some of these get optimised into checks
for flag bits or conditional calls, is an implementation detail
that we can hide from the user by the judicious use of macros or whatever.


> > > =item new
> > >
> > >    void               new(PMC[, key]);
> > >
> > > Creates a new variable of the appropriate type out of the passed PMC,
> > > destroying the current contents if there are any. This is a class
> > > function.
> >
> >As an aside, am I right in assuming that there will be a function somewhere
> >(outside the scope of this PDD) that creates new, empty PMCs, which can then
> >be acted upon by new() to turn them into PMCs of a particular type?
> 
> Probably, yes. More likely, PMCs will be declared nukable unless a "clean 
> me up" flag is set, in which case we'd just stomp on what was in there. 
> (Since we generally don't care about the contents of a PMC when trashing 
> it, with some relatively rare exceptions)
> 
> >Will PMCs that have just been new()ed have a default null value, eg
> >0/"" ?  Note that they wont be undefined - at least, I'm assuming that
> >undefined is handled by a separate class.
> >Perhaps we need instead a range of new()s that initialise to various
> >string, numeric etc values?
> 
> I'm figuring that'll be handled by the bits that deal with constants, but 
> there's no reason that a plain new PMC can't be undef. (Basically set the 
> private data pointer to NULL and the vtable pointer to the undef class vtable)

Hmm, there doesnt seem to be anything related to handling constants in PDD 2.

> 
> >The above definition of new() implies that it first calls destroy()
> >to release any previous contents. I think it would be better to define
> >new() as operating on an empty PMC (so it is the the caller's responsibility
> >to call destroy() first, if necessary).
> 
> destroy will only be called if the PMC needs it. Most PMCs will just get 
> their contents trashed and let the GC clean up after.

yes, but we have to agree whether its the callers or callee's responsibilty
to determine whether to check for nuke requirements. I think it should
be the caller's responsibity: often the caller will know that the thing
it is passing has already been nuked, so it knows not to waste time
checking.
> 
> >Actually, I suspect that the whole area of new/clone/destroy etc will need to
> >be examined carefully in the light of a 'typical' variable lifecycle,
> >to avoid to unecessary transitions. For example, my $a = 'abc' might
> >involve $a going from empty -> undef -> empty -> "" -> "abc" or similar,
> >if we're not careful.
> 
> That's an area for the optimizer. I'd like it to go from empty->"abc", 
> assuming we don't skip the empty step.

But its also a task for us to define PDD 2 carefully enough so that
the optimiser is allowed to do things optimally.

> 
> > >    void               clone(PMC1, PMC2 [, int flags[,key]);
> > >
> > > Copies C<PMC2> into C<PMC1>. The C<flags> parameter notes whether
> > > a deep copy should be done. (Possibly other things as well, if someone
> > > thinks of something reasonable)
> >
> >One flag that would be very useful is 'destroy', which tells clone() to
> >destroy PMC2 immediately after the clone operation.
> 
> That makes no sense to me. If we're cloning PMC2 then trashing it, why not 
> just set PMC1 to point to PMC2 and be done with it? (Just swap aliases 
> essentially)

Well, consider

$a = foo();

Assuming that foo() returns a temporary PMC of some description (t say),
we want to copy the guts of t onto $a's PMC, then destroy t (assuming it
needs destroying).

We would expect the compiler to generate opcodes that do the equivalent of

t = call_func('foo'); /* or whatever */
a->assign(t);
if (t->flags && NEEDS_DESTROY) t->destroy();

If a is a simple type, then a's assign method just calls b's clone
method. b's clone method then copies itself all over a. If b's clone
method knows that shortly after it has copied itself, it will be deleted,
then it may be able to do the copy much more efficienty.

For example, a string type when asked to clone itself, may duplicate
the entire string; when asked to clone and destroy, will just copy the string
pointer.

Unless I've misunderstood the purpose of clone().

 
> >I alo think that clone should expect PMC1 to be empty - ie it assumes the
> >caller has already called destroy() if necessary.
> 
> Assuming a trashable PMC is fine, though not necessarily an empty one. 
> Leaving destruction of destructable data to an explicit opcode's OK.

As long as the revided PDD makes it clear that clone() isnt expected to
(conditionally) destroy() its target before stomping on it.
> 

> > >    void               morph(PMC, type[, key]);
> > >
> > > Tells the PMC to change itself into a PMC of the specified type.
> >
> >I dont really see what the difference is between this and new().
> 
> New creates a new variable of a particular class. Morph tells a variable 
> "become this type". For example, if you told an integer array to morph into 
> a scalar array, it'd need to go through itself and change all its ints to 
> scalars.

Hmm, this could be quite a tricky operation to demand of classes.

> > >    void               destroy(PMC[, key]);
> > >
> > > Destroys the variable the PMC represents, leaving it undef.
> >
> >(See also my comments earlier about new/clone/destroy etc).
> >
> >I think destroy should leave an empty PMC rather than an undef one,
> >since as I said earlier, I think undef is a class in its own right.
> 
> Trashed things are traditionally undef in perl, and I don't see why we 
> should change that. Granted it'll be tough to see this as it'll all be 
> hidden, but still...

Given that I misundersood what destroy() was for, there now seems to be
no 'offical' way of turning a 'live' PMC back into an empty or undef one,
unless we do Undef_Class->new(PMC), or global_undef_constant->clone(PMC),
which both seem somehow tacky.


Reply via email to