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;

Reply via email to