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

Tentative [PATCH]: valclone

12 views
Skip to first unread message

Luke Palmer

unread,
Jun 27, 2003, 10:54:26 PM6/27/03
to perl6-i...@perl.org
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;

Leopold Toetsch

unread,
Jun 28, 2003, 3:34:32 AM6/28/03
to Luke Palmer, perl6-i...@perl.org
Luke Palmer <fibo...@babylonia.flatirons.org> wrote:
> 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.

AFAIK no. The default is to pass constant references as arguments. So I
would expect this throwing an exception.
When you have:

sub refinc($var is rw) {

it should increment the object ref.

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

I think the assignment would translate to:

$P0 = new PerlUndef
assign $P0, $P1

Its now up to the set_pmc() vtable to do the right thing for an object
reference.

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

We need both, yes.

> The included tentative patch implements the latter (namely,
> C<valclone>).

This is AFAIK what C<assign> does anyway.

>> PMC* valclone () {
>> PMC* dest = pmc_new(INTERP, SELF->vtable->base_type);
>> memcpy(&dest->cache, &SELF->cache, sizeof(UnionVal));
>> return dest;
>> }

I'm not sure, if we need this.

leo

Luke Palmer

unread,
Jun 28, 2003, 4:37:00 AM6/28/03
to l...@toetsch.at, perl6-i...@perl.org
> Luke Palmer <fibo...@babylonia.flatirons.org> wrote:
> > 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.
>
> AFAIK no. The default is to pass constant references as arguments. So I
> would expect this throwing an exception.
> When you have:
>
> sub refinc($var is rw) {
>
> it should increment the object ref.

That would increment a regular integer too, though.

Am I misinterpreting constant reference? That is, is it a reference
to a constant or is the reference itself constant? IIRC it's the
latter...

> > 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.
>
> I think the assignment would translate to:
>
> $P0 = new PerlUndef
> assign $P0, $P1
>
> Its now up to the set_pmc() vtable to do the right thing for an object
> reference.

Well, I think the difference is that assign puts the burdon on
PerlUndef, while valclone puts the weight on the thing being
cloned/assigned. If we don't like type switches, the the clonee is
probably a better place to put it.

But then, set_pmc() could always call a method on its argument. That
means that there has to be an appropriate vtable entry to call,
though... like, um, valclone :-)

> > 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.
>
> We need both, yes.
>
> > The included tentative patch implements the latter (namely,
> > C<valclone>).
>
> This is AFAIK what C<assign> does anyway.
>
> >> PMC* valclone () {
> >> PMC* dest = pmc_new(INTERP, SELF->vtable->base_type);
> >> memcpy(&dest->cache, &SELF->cache, sizeof(UnionVal));
> >> return dest;
> >> }
>
> I'm not sure, if we need this.

I'm not sure either, but I'm also not sure if we don't need it. Which
is why I'm taking the time here to explore/discuss it.

Luke

K Stol

unread,
Jun 28, 2003, 6:46:41 AM6/28/03
to l...@toetsch.at, perl6-i...@perl.org

This same problem I encountered when generating code for my Lua compiler:
passing args by value or reference.
If all vars on Parrot will be represented by PMCs (in many languages they
will, I presume, if no type checking can be done). It really depends on the
language being compiled if args are passed by ref or by value, so wouldn't
it be favourable to have a general "argument" PMC class or something, which
is language independent, and changes its type to whatever was passed in?
Then, the problem is solved for most (all?) languages that are being
compiled to Parrot (and gives Parrot a standard (and abstracted) way of
handling this issue.

Or is this not possible/desired? Just an idea I had.

Klaas-jan


0 new messages