Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Initializers, finalizers, and fallbacks

16 views
Skip to first unread message

Dan Sugalski

unread,
Mar 3, 2004, 12:39:08 PM3/3/04
to perl6-i...@perl.org
Okay, here's a sketch of where I'm going with the initialization,
finalization, and fallback method locating. We need to do this
because we're in the semi-unenviable position of supporting multiple
languages that do this but that *don't* aggree on method names. So we
can't depend on those.

What I'm thinking of instead is to put properties on the class
namespace PMC that indicate which method, if any, in the namespace is
the proper method. And because initialization and finalization are...
interesting (don't ask, we'll go there later) we actually have two of
each.

So, what we're going to do is introduce six properties:

FALLBACK
CONSTRUCT
BUILD
FINALIZE
DELETE
CLEANUP

FALLBACK is the method we look for if we've redispatched up the whole
darn tree and haven't found what we're looking for. It's the
equivalent of perl's AUTOLOAD.

CONSTRUCT is the method we call when we're building the object from
scratch. We call it on the object and if the object wants to
redispatch to parents, it better do so. We'll catch that it's being
redispatched and call the proper parent class method even if it has a
different name.

BUILD is the method we call when we're building the object. We call
this on *every* class in the object's hierarchy that it exists in. No
redispatching, it's all automatic.

FINALIZE is the method we call when we're destroying the object. It's
the equivalent of perl's DESTROY or python's __del__ method. We call
this on the object like a normal method--we find one and call it and
that's it. If a class wants to redispatch it better do so. (And we'll
catch redispatching __del__ in a python class that inherits from a
perl class and call perl's DESTROY instead, as we're redispatching
based on the function not the method name)

DELETE is the equivalent of a C++ destructor. It's called on every
class in an object's hierarchy that it exists in.

CLEANUP is the method that's called when an object dies. It's a class
method rather than an object method. (It's a ruby thing, I'll get
more details later)

What happens if a class hierarchy has a mix of CONSTRUCT and BUILD
methods, or FINALIZE and DELETE methods? Beats me.

Also, these properties are on *names*, not method PMCs. We get a
two-step "look up the property, then look up the method the property
names" thing, so we don't have sync issues when people replace the
method body PMCs at runtime by redefining the methods. (Or when we've
got locally obscured namespaces and should then pick up the current
version of the method)

At the moment I think we're going to allow reparenting, but that's
going to require catching pointer stores, so that means we're going
to need to start shimming in the pointer store function stuff that
we've been mildly pondering for the generational GC.
--
Dan

--------------------------------------"it's like this"-------------------
Dan Sugalski even samurai
d...@sidhe.org have teddy bears and even
teddy bears get drunk

Leopold Toetsch

unread,
Mar 3, 2004, 5:43:48 PM3/3/04
to Dan Sugalski, perl6-i...@perl.org
Dan Sugalski <d...@sidhe.org> wrote:

> What I'm thinking of instead is to put properties on the class
> namespace PMC that indicate which method, if any, in the namespace is
> the proper method. And because initialization and finalization are...
> interesting (don't ask, we'll go there later) we actually have two of
> each.

WRT properties: that's fine for the general case, and if the class
really installs special handlers. But - and if I get it right - we could
map:

BUILD -> __init
CLEANUP -> __destroy

to delegate PMC's vtables. The dispatch to __init is in CVS, albeit it's
lacking the calls to parent classes first.

Especially object construction and destruction should't get another
penalty, if that isn't really needed.

Finally we still have the problem of destruction ordering during DOD -
or not yet - but we'll have it with objects.

> So, what we're going to do is introduce six properties:

> FALLBACK
> CONSTRUCT
> BUILD
> FINALIZE
> DELETE
> CLEANUP

which are optional?

leo

Chromatic

unread,
Apr 2, 2004, 1:29:14 AM4/2/04
to Dan Sugalski, perl6-i...@perl.org
On Wed, 2004-03-03 at 09:39, Dan Sugalski wrote:

> Okay, here's a sketch of where I'm going with the initialization,
> finalization, and fallback method locating. We need to do this
> because we're in the semi-unenviable position of supporting multiple
> languages that do this but that *don't* aggree on method names. So we
> can't depend on those.
>

> So, what we're going to do is introduce six properties:
>
> FALLBACK
> CONSTRUCT
> BUILD
> FINALIZE
> DELETE
> CLEANUP

Suppose I have, for the sake of argument, a pointer to a struct that
comes from an external C library. In which method under this scheme
would I tell that library to free the memory?

(I'm happy to let global destruction handle that at the moment, but it'd
be nice to release memory I know will go unused.)

-- c

Leopold Toetsch

unread,
Apr 6, 2004, 4:33:50 AM4/6/04
to Dan Sugalski, perl6-i...@perl.org
Dan Sugalski <d...@sidhe.org> wrote:
> Okay, here's a sketch of where I'm going with the initialization,
> finalization, and fallback method locating.

As the current init scheme isn't really flying (and not in sync with
this proposal) here is a first hack to get it running.

> CONSTRUCT is the method we call when we're building the object from
> scratch. We call it on the object and if the object wants to
> redispatch to parents, it better do so. We'll catch that it's being
> redispatched and call the proper parent class method even if it has a
> different name.

> BUILD is the method we call when we're building the object. We call
> this on *every* class in the object's hierarchy that it exists in. No
> redispatching, it's all automatic.

[ ... ]

> Also, these properties are on *names*, not method PMCs. We get a
> two-step "look up the property, then look up the method the property
> names" thing,

Here is a sample program:

$ cat o.imc
.sub _main
$P0 = newclass "A"
$P1 = new PerlString
$P1 = "_new"
setprop $P0, "BUILD", $P1
$I0 = find_type "A"
$P2 = new PerlString
$P2 = "argument\n"
.local pmc obj
obj = new $I0, $P2
print "done\n"
end
.end

.namespace ["A"]

.sub _new method
.param pmc arg
print "new\n"
print arg
.end
.sub __init method
print "init\n"
.end

The new scheme is currently turned on only, if the environment variable
CALL__BUILD is set so that old code isn't broken immediately:

$ CALL__BUILD=1 parrot o.imc
new
argument
done

$ parrot o.imc
init
done

The "obj = new Iclass" can now take an optional initializer which is
passed as first PMC arument to the BUILD or CONSTRUCT method. It's up to
the class what this is, but we should probably define some scheme for
HLL interoperbility.

Comments welcome,
leo


--- parrot/include/parrot/objects.h Sat Apr 3 18:00:20 2004
+++ parrot-leo/include/parrot/objects.h Tue Apr 6 10:10:56 2004
@@ -44,6 +44,7 @@
PMC *Parrot_remove_parent(Parrot_Interp, PMC *, PMC *);
PMC *Parrot_multi_subclass(Parrot_Interp, PMC *, STRING *);
void Parrot_instantiate_object(Parrot_Interp, PMC *);
+void Parrot_instantiate_object_init(Parrot_Interp, PMC *, PMC *);
INTVAL Parrot_object_isa(Parrot_Interp interpreter, PMC *, PMC *);
PMC *Parrot_new_method_cache(Parrot_Interp);
PMC *Parrot_find_method_with_cache(Parrot_Interp, PMC *, STRING *);
--- parrot/src/objects.c Mon Apr 5 11:24:49 2004
+++ parrot-leo/src/objects.c Tue Apr 6 10:21:56 2004
@@ -440,6 +440,7 @@

/* Reset the init method to our instantiation method */
new_vtable->init = Parrot_instantiate_object;
+ new_vtable->init_pmc = Parrot_instantiate_object_init;
new_class->vtable = new_vtable;

/* Put our new vtable in the global table */
@@ -458,16 +459,32 @@
return new_type;
}

+static PMC*
+get_init_meth(Parrot_Interp interpreter, PMC *class, const char * init_name)
+{
+ PMC *prop;
+ STRING *prop_s, *meth;
+ prop_s = const_string(interpreter, init_name);
+ prop = VTABLE_getprop(interpreter, class, prop_s);
+ if (!VTABLE_defined(interpreter, prop))
+ return NULL;
+ meth = VTABLE_get_string(interpreter, prop);
+ return Parrot_find_method_with_cache(interpreter, class, meth);
+}

static void
-do_initcall(Parrot_Interp interpreter, PMC* class, PMC *object)
+do_initcall(Parrot_Interp interpreter, PMC* class, PMC *object, PMC *init)
{
-
SLOTTYPE *class_data = PMC_data(class);
PMC *classsearch_array = get_attrib_num(class_data, PCD_ALL_PARENTS);
PMC *parent_class;
INTVAL i, nparents;
+ int free_it;
+ /*
+ * XXX compat mode
+ */

+ if (!Parrot_getenv("CALL__BUILD", &free_it)) {
nparents = VTABLE_elements(interpreter, classsearch_array);
for (i = nparents - 1; i >= 0; --i) {
parent_class = VTABLE_get_pmc_keyed_int(interpreter,
@@ -476,12 +493,60 @@
object, parent_class);
}
Parrot_base_vtables[enum_class_delegate]->init(interpreter, object);
+ }
+ else {
+ /*
+ * 1) if class has a CONSTRUCT property run it on the object
+ * no redispatch
+ */
+ PMC *meth = get_init_meth(interpreter, class, "CONSTRUCT");
+ if (meth) {
+ /* XXX S0 isn't set - create runops_method */
+ PMC *p2 = REG_PMC(2); /* preserve current self */
+ REG_PMC(2) = object;
+ if (init)
+ Parrot_runops_fromc_args_save(interpreter, meth, "vP", init);
+ else
+ Parrot_runops_fromc_save(interpreter, meth);
+ REG_PMC(2) = p2;
+ }
+ /*
+ * 2. if class has a BUILD property call it for all classes
+ * in reverse search order - this class last.
+ */
+ nparents = VTABLE_elements(interpreter, classsearch_array);
+ for (i = nparents - 1; i >= 0; --i) {
+ parent_class = VTABLE_get_pmc_keyed_int(interpreter,
+ classsearch_array, i);
+ meth = get_init_meth(interpreter, parent_class, "BUILD");
+ if (meth) {
+ PMC *p2 = REG_PMC(2); /* preserve current self */
+ REG_PMC(2) = object;
+ if (init)
+ Parrot_runops_fromc_args_save(interpreter, meth, "vP",
+ init);
+ else
+ Parrot_runops_fromc_save(interpreter, meth);
+ REG_PMC(2) = p2;
+ }
+ }
+ meth = get_init_meth(interpreter, class, "BUILD");
+ if (meth) {
+ PMC *p2 = REG_PMC(2); /* preserve current self */
+ REG_PMC(2) = object;
+ if (init)
+ Parrot_runops_fromc_args_save(interpreter, meth, "vP", init);
+ else
+ Parrot_runops_fromc_save(interpreter, meth);
+ REG_PMC(2) = p2;
+ }
+ }
}

/*

=item C<void
-Parrot_instantiate_object(Parrot_Interp interpreter, PMC *object)>
+Parrot_instantiate_object(Parrot_Interp interpreter, PMC *object, PMC *init)>

Creates a Parrot object. Takes a passed-in class PMC that has sufficient
information to describe the layout of the object and, well, makes the
@@ -491,9 +556,24 @@

*/

+static void instantiate_object(Parrot_Interp, PMC *object, PMC *init);
+
+void
+Parrot_instantiate_object_init(Parrot_Interp interpreter,
+ PMC *object, PMC *init)
+{
+ instantiate_object(interpreter, object, init);
+}
+
void
Parrot_instantiate_object(Parrot_Interp interpreter, PMC *object)
{
+ instantiate_object(interpreter, object, NULL);
+}
+
+static void
+instantiate_object(Parrot_Interp interpreter, PMC *object, PMC *init)
+{
SLOTTYPE *new_object_array;
INTVAL attrib_count;
SLOTTYPE *class_array;
@@ -536,7 +616,7 @@
/* We really ought to call the class init routines here...
* this assumes that an object isa delegate
*/
- do_initcall(interpreter, class, object);
+ do_initcall(interpreter, class, object, init);
}

/*

Dan Sugalski

unread,
Apr 6, 2004, 11:51:33 AM4/6/04
to chromatic, perl6-i...@perl.org
At 10:29 PM -0800 4/1/04, chromatic wrote:
>On Wed, 2004-03-03 at 09:39, Dan Sugalski wrote:
>
>> Okay, here's a sketch of where I'm going with the initialization,
>> finalization, and fallback method locating. We need to do this
>> because we're in the semi-unenviable position of supporting multiple
>> languages that do this but that *don't* aggree on method names. So we
>> can't depend on those.
>>
>> So, what we're going to do is introduce six properties:
>>
>> FALLBACK
>> CONSTRUCT
>> BUILD
>> FINALIZE
>> DELETE
>> CLEANUP
>
>Suppose I have, for the sake of argument, a pointer to a struct that
>comes from an external C library. In which method under this scheme
>would I tell that library to free the memory?

Should be FINALIZE.

As I look at that list I get a distinct "What the *hell* was I
thinking?" feeling, though. I'm trying to figure out what the point
of DELETE and CLEANUP were.

Andy Wardley

unread,
Apr 7, 2004, 3:15:03 AM4/7/04
to Dan Sugalski, chromatic, perl6-i...@perl.org
Dan wrote:
> Should be FINALIZE.

Although some in the non-US English speaking world might say it should
be FINALISE.

Perhaps FINAL might be a better choice? That would please more of the
people for more of the time (or displease them for less of the time).

A

Tim Bunce

unread,
Apr 7, 2004, 6:09:14 AM4/7/04
to Andy Wardley, Dan Sugalski, chromatic, perl6-i...@perl.org
On Wed, Apr 07, 2004 at 08:15:03AM +0100, Andy Wardley wrote:
> Dan wrote:
> > Should be FINALIZE.
>
> Although some in the non-US English speaking world might say it should
> be FINALISE.

FYI: FINALIZE is the spelling used by the Oxford English Dictionary.

See http://www.askoxford.com/asktheexperts/faq/aboutspelling/ize
reproduced below.

Tim.

Frequently Asked Questions

Spelling

Are spellings like 'privatize' and 'organize' Americanisms?

No, not really. British spelling has always recognized the existence
of variant spellings using the suffix -ize/-ise. When American
spelling was standardized during the 19th century (mainly through
the efforts of the great American lexicographer Noah Webster), the
consistent use of -ize was one of the conventions that became
established. However, since then, the -ise spellings have become
more popular in Britain (and in other English-speaking countries
such as Australia), perhaps partly as a reaction against the American
custom. Spellings such as organisation would have struck many older
British writers as rather French-looking. The Oxford English
Dictionary favoured -ize, partly on the linguistic basis that the
suffix derives from the Greek suffix -izo, and this was also the
style of Encyclopedia Britannica (even before it was American-owned)
and formerly of the Times newspaper.

The main advantage of the modern -ise habit? Lazy spellers do not
have to remember that there are several important words which cannot
properly be spelt with -ize. These include words which are not
formed by the addition of the -ize prefix to a stem, but by some
other root which happens to end in the same syllable, such as -vise
(as in televise), -cise (as in incise), and -prise (as in comprise).

The American system resulted in the creeping of z into some other
words where it did not originally belong. Writers of American English
should be aware of some spellings that are regarded as incorrect
in the UK, notably analyze.


Leopold Toetsch

unread,
Apr 8, 2004, 11:54:14 AM4/8/04
to perl6-i...@perl.org, d...@sidhe.org
Leopold Toetsch <l...@toetsch.at> wrote:

[ I'd like to have that scheme in P6E2, *if* we use it ]

> [ ... ]

> .namespace ["A"]

> Comments welcome,
> leo

> /*

> */

> /*

leo

0 new messages