develooper Front page | perl.perl6.internals | Postings from February 2001

Re: PDD 2, vtables

Dan Sugalski
February 7, 2001 09:42
Re: PDD 2, vtables
Message ID:
At 03:09 PM 2/7/2001 +0000, David Mitchell wrote:
>Some comments about the vtable PDD...
>First a general comment. I think we really need to make it clear for
>each method, which arg respresents the object that is having its method
>called (ie which is $self/this so to speak). One way to make this clear
>would be to insist that the first arg is always $self,
>but failing that, it should be explicity mentioned for each function.

The docs are unclear there. I'll patch 'em up.

FWIW, generally the first argument is the destination.

>Also, can I suggest a bit of terminology, which I will use below?
>I define an *empty* PMC as a PMC which exists, but does not have a valid
>vtable ptr or content (and so whose methods must not be called under
>any circumstances). I specifically contrast this with a undefined PMC,
>which has a valid vtable pointer that points to a bunch of methods that
>mostly call carp("use of undefined value ...").

This is an area that needs addressing, that's for sure. I'll deal with that 
as well.

> > The C<key> parameter is optional, and if passed it refers to an array
> > of key structure pointers.
>A mere detail, but would it not be more efficient to just pass them
>as extra args, ie add(PMC1, PMC2, PMC3, key1, key2, key3),
>rather than having to potentially create and populate a tmp struct
>just to call the function???

Well, extra arguments cost. I'd originally had only a single key optionally 
passed in, but that meant potentially two of the three PMCs had to be real, 
rather than keyed into containers. (And thus possibly virtual) Hence the 
key array.

I admit it's not a swell decision--I'm not sure whether the single optional 
parameter is better, or several optional (or required) parameters are 
better. I can see it going either way, and I didn't put all that much 
thought into it.

> >    IV            type(PMC[, subtype]);
> >
> > Returns the type of the PMC. If the subtype is passed (int, string,
> > num) it returns the subtype of the PMC. This is generally a class
> > function rather than a variable one, but the PMC is passed in just in
> > case. (And so we can have the subtype be a vararg parameter)
>I dont understand the subtype bit. If for example we pass an optional
>2nd arg of INT (assuming this is some sort of enum?), what does type()

If you pass in INT, you'll get back NATIVE or BIGINT, depending on which 
one the PMC would rather be. STR would get BINARY, NATIVE, FOREIGN, or UTF_32.

Basically, subtype says "If I asked you what kind of string you were, what 
would you tell me?"

> > =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)

>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.

>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.

> >    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 

>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.

>I guess we also need an assign() method, to handle
>$a = $b and the like.

Yep, you're right.

>Note that assign and clone are very different operations (although assign
>may well call clone): assign() copies *to* itself, while clone() copies
>*from* itself.
>Note that if $a is a 'simple' variable, $a->assign($b) will
>itself just fall through to $b->clone($a) and let $a be wiped; while
>if $a is magic or tied or whatever, then $a->assign($b) will take
>a more active role in setting its own value, based on the value of $b.

Yup. Like, for example, if you're assinging an integer to a variable marked 
as forced to string--you'd need to change the integer to a string, or pitch 
a fit. (Depending on how things are defined to work)

> >    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 

> >    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...

> > =item exists (x)
> >
> >    BOOL               exists(PMC1[, key]);
>Presumably we also need defined(). (where most classes will always return
>false, while the 'undefined' classs class always returns true.)

Yep. The autoinc and autodec operators too, which I forgot.


--------------------------------------"it's like this"-------------------
Dan Sugalski                          even samurai                         have teddy bears and even
                                      teddy bears get drunk Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About