patrick-kidger / patrick-kidger/equinox

Using class composition on abstract interfaces w/ methods and fields

Open
#1,069 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

question
Dominant language
Python
Stars
3k
Forks
213
Avg merge
8d 4h
Merged PRs (30d)
2

Description

I am wondering what the recommended practice is for class composition on abstract interfaces with both methods and fields. Concretely, here's what I'm talking about:

Forwarding the methods of an abstract interface is easy:

class AbstractModule(eqx.Module):

    @abc.abstractmethod
    def some_method(self):
        raise NotImplementedError()

class ConcreteModule(AbstractModule):

    @override
    def some_method(self):
        ...


class ForwardedModule(AbstractModule):

    example_module: ConcreteModule

    def __init__(self, example_module: ConcreteModule):
        self.example_module = example_module

    @override
    def some_method(self):
        return self.example_module.some_method()

Forwarding fields is also easy:

class AbstractModule(eqx.Module):

    some_field: eqx.AbstractVar[int]

class ConcreteModule(AbstractModule):

    some_field: int

    def __init__(self, some_field: int):
        self.some_field = some_field


class ForwardedModule(AbstractModule):

    some_field: int

    def __init__(self, example_module: ConcreteModule):
        self.some_field = example_module.some_field

What to do if there are both fields and methods? This must be such that there is only one value of "some_field" in the pytree.

class AbstractModule(eqx.Module):

    some_field: eqx.AbstractVar[int]

    @abc.abstractmethod
    def some_method(self):
        raise NotImplementedError()

class ConcreteModule(AbstractModule):

    some_field: int

    def __init__(self, some_field: int):
        self.some_field = some_field


    @override
    def some_method(self):
        # use `some_field` somehow
        ...


class ForwardedModule(AbstractModule):

    some_field: int

    def __init__(self, example_module: ConcreteModule):
        self.some_field = example_module.some_field

    @override
    def some_method(self):  # how to implement? 
        ...

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the AbstractModule, ConcreteModule, and ForwardedModule examples in the issue, then inspect how eqx.Module fields and pytree values interact with abstract methods. Establish whether a supported composition pattern can preserve one some_field value while forwarding some_method; done means the recommended approach is documented or implemented with a demonstrated working example.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
machine-learning
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.