Skip to content

Multiple dispatch issue with inherited class #335

Description

@softmattertheory

Method MD: subclass of a class from another module matches untyped overload

Summary

When a method has both an untyped overload and typed overloads on a parent class, and the argument’s class is a subclass defined in a different module than the method, multiple dispatch incorrectly selects the untyped overload.

  • Same overload set as free functions: correct (typed parent).
  • Method + subclass in the same module/file: correct.
  • Method in module A, subclass in module B (or main after import A): wrong (untyped).
  • Instance of the parent class itself: still correct on the method.

Environment

  • Morpho v0.6.4

Expected

Closest typed match wins. For class Sub is Scene {} and

open(commands) { ... }    // untyped
open(Graphics g) { ... }
open(Scene g) { ... }

receiver.open(Sub()) should return / run open(Scene).

Actual

receiver.open(Sub()) runs open(commands) (untyped).
receiver.open(Scene()) still correctly runs open(Scene).

Minimal example

receiver.morpho (module):

import xgraphics   // or whatever module defines Scene / Graphics

class Receiver {
  open(commands) { return "untyped" }
  open(Graphics g) { return "Graphics" }
  open(Scene g) { return "Scene" }
}

Driver (separate file / REPL after import):

import receiver
import xgraphics

class Sub is Scene {}

var r = Receiver()

print(r.open(Scene()))   // Scene   (OK)
print(r.open(Sub()))     // untyped (BUG — should be Scene)
print(r.open("hi"))      // untyped (OK)

/* Free functions with the same signatures are fine */
fn f(commands) { return "untyped" }
fn f(Graphics g) { return "Graphics" }
fn f(Scene g) { return "Scene" }

print(f(Sub()))          // Scene   (OK)

Same-file control (no bug):

import xgraphics

class Receiver {
  open(commands) { return "untyped" }
  open(Graphics g) { return "Graphics" }
  open(Scene g) { return "Scene" }
}

class Sub is Scene {}

print(Receiver().open(Sub()))   // Scene (OK)

Impact

Any API like View.open(Scene) that also has an untyped open(commands) break for user subclasses defined outside the module that declares View (e.g. class Plot is Scene in another package). Call sites such as View(plot) then pass the object into the string/command path and fail later.

Workaround

Type the catch-all overload:

open(String commands) { ... }

so a Scene subclass cannot match it; dispatch then selects open(Scene).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions