0

In a new project, instead of defining methods inside the bodies of my classes, I would like to use multimethods exclusively and define nothing inside my classes except for data members.

In other words, instead of this:

class A():
    x: int = 0

    def f(self):
        print(f"A.f(self): x = {self.x}")

I would like to write this:

class B():
    x: int = 0


@multimethod
def g(b: B):
    print(f"g(b: B): x = {b.x}")

Now, I can call f using method syntax:

a = A()
a.f()

And g using function syntax:

b = B()
g(b)

However, not the other way around:

a = A()
f(a) # NameError: name 'f' is not defined
b = B()
b.g() # AttributeError: 'B' object has no attribute 'g'

This means I have to give up a lot of convenience. In particular, implementing something like __str__ as a multimethod does not give me the kind of behavior I would get if it was implemented inside a class.

class B():
    x: int = 0


@multimethod
def __str__(b: B) -> str:
    return f"B({b.x})"

Calling print(B()) outputs something along the lines of <__main__.B object at 0x7fb229c6a5b0> instead of B(0).

Going another step further, it would even be imaginable for an arbitrarily named function having the correct signature (like somefn below) to fill in for __str__.

class B():
    x: int = 0


@multimethod
def somefn(b: B) -> str:
    return f"B({b.x})"

Is there a way to keep the bodies of my classes empty and make the appropriate multimethods act as though they were defined inside the respective body?

Admittedly, what I am trying to do here is kind of like opting out of the built in object oriented features of Python and, at least partially, replacing them with something more general. This seems like bending the language quite a bit. So, even if multimethods does not fully support this interoperability in the moment, is it likely that interfacing between traditional classes and multiple dispatch will become more ergonomic in the future?

  • 2
    Excuse me, what is `multimethod`? – mkrieger1 Mar 27 '21 at 17:09
  • 1
    I mean multimethod both in the sense of this concrete package https://pypi.org/project/multimethod/ and the concept https://en.wikipedia.org/wiki/Multiple_dispatch. – lambdakappatheta Mar 27 '21 at 17:18
  • There's no real answer to this question that isn't conjecture. But leaving that aside for a moment, I don't see how this would work in practice. What if there is more than one `__str__` that accepts a `B` as its argument (for example in different modules or packages)? How would the interpreter know that some arbitrary function `f(b: B) -> str` is the canonical string representation as opposed to returning (say) the string representation of some attribute of `B`? – snakecharmerb Mar 27 '21 at 19:04
  • Yes, AFAIU, as opposed to single dispatch where a method belongs to a single type exclusively, with multiple dispatch a method can belong to multiple types. Therefore, if a method belongs to, say, type A and type B equally then it does not seem right conceptually to implement it inside A or B. However, outside of A and B, all implementers are equal which can introduce ambiguity. With `somefn` I have gone a bit too far I think. It is one thing to have some ambiguity between methods with the same name but calling a different function just because its signature is a good fit?! – lambdakappatheta Mar 27 '21 at 23:01
  • More to the point, what I would like to know is whether what I am trying to do is possible and if it is not why? Performance, difficulty of integration with existing features would, for instance, come to my mind.. but I would also like to hear if someone has a good reason for why using multimethods exclusively is a good/bad idea. – lambdakappatheta Mar 27 '21 at 23:23

0 Answers0