Consider this Perl 6 code: sub refinc($var) { my $myvar = $var; $myvar += 1; }
If you pass an integer in here, it should do nothing. However, if you pass an object with an overloaded += in, it should have the side-effect of adding one to that object. It's just a value/reference semantics thing. If Perl compiles that code with $var and $myvar as PMCs, and it uses C<set> to get $var into $myvar, PerlInt won't work right. And if it uses C<clone> to get $var into $myvar, an object won't work right. There are two ways to solve this: make a PerlRef class (which will eventually have to be done anyway) or make a polymorphic assignment which lets the PMC decide whether it has value or reference semantics. The included tentative patch implements the latter (namely, C<valclone>). So we have (for PMCs): * C<set>: Always reference semantics * C<clone>: Always value semantics * C<valclone>: PMC's choice Is this a good way to go about solving this problem? Luke [ As an added bonus, this patch implements clone_p_p_k and clone_p_p_ki ] Index: core.ops =================================================================== RCS file: /cvs/public/parrot/core.ops,v retrieving revision 1.293 diff -r1.293 core.ops 246,247d245 < < 612a611,614 > =item B<clone>(out PMC, in PMC, in KEY) > > =item B<clone>(out PMC, in PMC, in INTKEY) > 621c623 < $2->vtable->clone(interpreter, $2, $1); --- > VTABLE_clone(interpreter, $2, $1); 623a626,664 > } > > inline op clone(out PMC, in PMC, in KEY) { > $1 = pmc_new_noinit(interpreter, $2->vtable->base_type); > VTABLE_clone_keyed(interpreter, $2, $3, $1); > goto NEXT(); > } > > inline op clone(out PMC, in PMC, in INTKEY) { > $1 = pmc_new_noinit(interpreter, $2->vtable->base_type); > VTABLE_clone_keyed_int(interpreter, $2, &$3, $1); > goto NEXT(); > } > > =item B<valclone>(out PMC, in PMC) > > =item B<valclone>(out PMC, in PMC, in KEY) > > =item B<valclone>(out PMC, in PMC, in INTKEY) > > Creates a copy of the pmc in $2 and puts it in $1, respecting reference > semantics when it should; i.e. PerlInts clone themselves, while PerlArrays > just do a plain old C<set>. > > =cut > > inline op valclone(out PMC, in PMC) { > $1 = VTABLE_valclone(interpreter, $2); > goto NEXT(); > } > > inline op valclone(out PMC, in PMC, in KEY) { > $1 = VTABLE_valclone_keyed(interpreter, $2, $3); > goto NEXT(); > } > > inline op valclone(out PMC, in PMC, in INTKEY) { > $1 = VTABLE_valclone_keyed_int(interpreter, $2, &$3); > goto NEXT(); Index: vtable.tbl =================================================================== RCS file: /cvs/public/parrot/vtable.tbl,v retrieving revision 1.38 diff -r1.38 vtable.tbl 30a31,34 > PMC* valclone() > PMC* valclone_keyed(PMC* key) > PMC* valclone_keyed_int(INTVAL* key) > Index: classes/default.pmc =================================================================== RCS file: /cvs/public/parrot/classes/default.pmc,v retrieving revision 1.54 diff -r1.54 default.pmc 172a173,188 > PMC* valclone () { > return SELF; > } > > PMC* valclone_keyed (PMC* key) { > internal_exception(ILL_INHERIT, > "valclone_keyed() not implemented in class '%s'\n", > caller(INTERP, SELF)); > return NULL; > } > > PMC* valclone_keyed_int (INTVAL* key) { > PMC* r_key = INT2KEY(INTERP, key); > return DYNSELF.valclone_keyed(r_key); > } > Index: classes/scalar.pmc =================================================================== RCS file: /cvs/public/parrot/classes/scalar.pmc,v retrieving revision 1.6 diff -r1.6 scalar.pmc 22a23,28 > PMC* valclone () { > PMC* dest = pmc_new(INTERP, SELF->vtable->base_type); > memcpy(&dest->cache, &SELF->cache, sizeof(UnionVal)); > return dest; > } > Index: t/pmc/perlarray.t =================================================================== RCS file: /cvs/public/parrot/t/pmc/perlarray.t,v retrieving revision 1.28 diff -r1.28 perlarray.t 3c3 < use Parrot::Test tests => 22; --- > use Parrot::Test tests => 23; 1214a1215,1244 > output_is(<<'CODE', <<'OUTPUT', "valclone"); > # Regular clone > new P0, .PerlArray > set P0[0], 10 > clone P1, P0 > set P1[0], 20 > set P2, P0[0] > set P3, P1[0] > print P2 > print "\n" > print P3 > print "\n" > > # valclone (works like ordinary set in this case) > new P0, .PerlArray > set P0[0], 10 > valclone P1, P0 > set P1[0], 20 > set P2, P0[0] > set P3, P1[0] > print P2 > print "\n" > print P3 > print "\n" > CODE > 10 > 20 > 20 > 20 > OUTPUT Index: t/pmc/perlint.t =================================================================== RCS file: /cvs/public/parrot/t/pmc/perlint.t,v retrieving revision 1.3 diff -r1.3 perlint.t 3c3 < use Parrot::Test tests => 5; --- > use Parrot::Test tests => 6; 152a153,183 > > output_is(<<'CODE', <<'OUTPUT', "valclone"); > # Normal set > new P0, .PerlInt > set P0, 10 > set P1, P0 > set P1, 20 > print P0 > print "\n" > print P1 > print "\n" > > # valclone (in .PerlInt's case, excactly like clone) > new P0, .PerlInt > set P0, 10 > valclone P1, P0 > set P1, 20 > print P0 > print "\n" > print P1 > print "\n" > > end > CODE > 20 > 20 > 10 > 20 > OUTPUT > > 1;