Ticket #784 (closed bug: fixed)

Opened 5 years ago

Last modified 4 years ago

subclassing breaks multi dispatch

Reported by: coke Owned by:
Priority: blocker Milestone:
Component: core Version: branch
Severity: medium Keywords:
Cc: Language: tcl
Patch status: Platform:

Description

This code looks like it should print "1" twice...

.sub main :main
  .local pmc int_c
  int_c = get_class "Integer"

  .local pmc sub_c
  sub_c = subclass int_c, "MyInt"

  $P1 = new 'Integer'
  $P1 = 4
  $P1 -= 3
  say $P1

  $P1 = new 'MyInt'
  $P1 = 4
  $P1 -= 3
  say $P1
.end

But dies on the subclass subtraction.

$ ./parrot foo.pir
1
Multiple Dispatch: No suitable candidate found for 'i_subtract_int', with signature 'PI'
current instr.: 'main' pc 24 (foo.pir:14)

Change History

in reply to: ↑ description   Changed 5 years ago by pmichaud

This looks like a duplicate of RT #60036; if so, we should probably forward that ticket here.

Pm

follow-up: ↓ 4   Changed 5 years ago by pmichaud

Also note that RT #60036 is one of the "mmd" tickets that is left over from the mmd refactor that needed cleaning up (i.e., so don't immediately close it out -- it's on the general task list for resolving mmd issues).

Pm

  Changed 5 years ago by bsdz

This is the same as bug #562 I filed months ago. I also sent several messages to the newsgroups and asked several questions in IRC. However, no one wanted to rise to the challenge and decide how this should work - no architect (or perhaps, one more interested in being in control rather than deciding on important behaviour). It was this bug or at least the way key players in the parrot team lacked interest in it that led me to feel that Parrot isn't interested in supporting any language other than Perl 6. This just made it all a bit too cliquey for me.

in reply to: ↑ 2   Changed 5 years ago by bacek

Replying to pmichaud:

Also note that RT #60036 is one of the "mmd" tickets that is left over from the mmd refactor that needed cleaning up (i.e., so don't immediately close it out -- it's on the general task list for resolving mmd issues).

Hello.

There is totally hackish and non-kosher patch for Pmc2c to "register" VTABLE in MMD.

diff --git a/lib/Parrot/Pmc2c/PMCEmitter.pm b/lib/Parrot/Pmc2c/PMCEmitter.pm
index 868c08d..f39c8e3 100644
--- a/lib/Parrot/Pmc2c/PMCEmitter.pm
+++ b/lib/Parrot/Pmc2c/PMCEmitter.pm
@@ -312,6 +312,7 @@ Generate switch-bases VTABLE for MULTI
 sub pre_method_gen {
     my ($self) = @_;
 
+    $self->gen_multi_for_vtable;
     $self->gen_switch_vtable;
 
     1;
@@ -1113,6 +1114,48 @@ sub gen_defaul_case_wrapping {
     }
 }
 
+=item C<gen_multi_for_vtable>
+
+Generate switch-bases VTABLE for MULTI
+
+=cut
+
+sub gen_multi_for_vtable {
+    my ($self) = @_;
+
+    # Convert list of multis to name->[(type,,ssig,fsig,ns,func)] hash.
+    my %multi_methods;
+    foreach (@{$self->find_multi_functions}) {
+        my ($name, $ssig, $fsig, $ns, $func, $method) = @$_;
+        my @sig = split /,/, $fsig;
+        push @{ $multi_methods{ $name } }, [ $sig[1], $ssig, $fsig, $ns, $func, $method ];
+    }
+
+    # vtable methods
+    foreach my $method ( @{ $self->vtable->methods } ) {
+        my $vt_method_name = $method->name;
+        next if $vt_method_name eq 'class_init';
+
+        next unless $self->implements_vtable($vt_method_name);
+        next unless $self->vtable_method_does_multi($vt_method_name);
+        next if exists $multi_methods{$vt_method_name};
+
+        # Get parameters.      strip type from param
+        my @parameters = map { s/(\s*\S+\s*\*?\s*)//; $_ } split (/,/, $method->parameters);
+
+        my $body = 'return STATICSELF.' . $vt_method_name. '(' . join(', ', @parameters) .');';
+        my $multi = $method->clone({
+                body => Parrot::Pmc2c::Emitter->text($body),
+        });
+        Parrot::Pmc2c::MULTI::rewrite_multi_sub( $multi, $self );
+        $multi->type(Parrot::Pmc2c::Method::MULTI);
+        $multi->symbol($vt_method_name);
+        $self->add_method($multi);
+    }
+
+
+    1;
+}
 
 1;
 

Proper solution is just register appropriate VTABLEs in MMD directly without creating proxy function but I'm not ready to heavy refactor pmc2c. Especially because pmc2c is reaching End Of Life.

So, is there any objections against this patch or I can commit it?

(Yes, at least all parrot's tests are passed.)

-- Bacek

  Changed 5 years ago by allison

This patch isn't the right solution. It does work around the bug in subclassing, but it also makes a large number of vtable functions available as MULTI's that shouldn't be. The same principle as TT #789 applies here, fix the bug rather than wallpapering over it.

If you'd like some guidance on where to look, first examine the set of MULTI's in the Integer and scalar PMCs. I found a number of core PMCs that were using multi-dispatch incorrectly, resulting in symptoms similar to these. I fixed the ones I found, but probably didn't catch all of them, so that's the first thing I'd check.

Allison

  Changed 5 years ago by treed

Coke pointed me to this bug as possibly related to a problem I'm having with Cardinal, so I started poking at the test given above. I thought I'd share my results. Adding the following code to the PIR file:

.namespace ['MyInt']

.sub 'i_subtract_int' :vtable :method
    .param pmc other
    $I0 = other
    $I1 = self
    $I2 = $I1 - $I0
    self = $I2
.end

Causes the bug to be routed around, and the script prints 1 twice as expected. Hence, I don't think it's related to my problem (where I *have* reimplemented the op, but it's still not being found), but I thought I'd stick this here anywhere.

  Changed 5 years ago by jkeenan

  • component changed from none to core

  Changed 4 years ago by chromatic

  • status changed from new to closed
  • resolution set to fixed

Fixed in r44414.

Note: See TracTickets for help on using tickets.