-
-
Notifications
You must be signed in to change notification settings - Fork 142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AbstractVar's that are also static #472
Comments
Hmm. So right now this is best handled by doing: class AbstractFoo(eqx.Module):
a: AbstractVar[int]
class ConcreteFoo(AbstractFoo):
a: int = eqx.field(static=True) as the intention of a Doing something like this is actually surprisingly complicated. (Inside baseball: abstract variables are a lower-level piece of functionality, below both (a) dataclasses and (b) pytrees. This can basically be reduced to how this dataclass-making function should handle abstract variables.) Off the top of my head I'm not sure how we might implement this, but I'd welcome a PR / further discussion. |
I tried some simple (but a tad convoluted) ideas in that pull request. Mainly keeping an additional list of abstractvars that were declared to be static. When the abstract attribute is finally made concrete, we add a This allows the following: from dataclasses import fields
import equinox as eqx
class Abstract(eqx.Module):
a: eqx.AbstractVar[int] = eqx.field(static=True)
class Concrete(Abstract):
a: int = 2
assert fields(Concrete())[0].metadata["static"] == True # works What do you think? |
Thanks for writing the PR! I think what I'd probably suggest instead is to have I think that should be a much smaller change. That would result in the syntax: class Abstract(eqx.Module):
a: eqx.AbstractVar[int] = eqx.field(static=True)
class Concrete(Abstract):
a: int = eqx.field(default=2, static=True) |
Aha! Then in your example, My original dream was a mechanism that raises an error if users forget to specify the value of a certain (static) attribute without them needing to think much about fields at all. But for that case, it might just be easier to have a |
I think having Moreover, that's not true without the AbstractVar annotation: class A(eqx.Module):
x: int = eqx.field(static=True)
class B(A):
x: int
[field] = dataclasses.fields(B)
print(field.metadata) # doesn't include static |
Interesting! I didn't notice that if a subclass declares the same field with a type hint, the field metadata is cleared. I had the wrong assumption that class A(eqx.Module):
x: int = eqx.field(static=True)
class B1(A):
x: int = 1
class B2(A):
x = 1 If static fields are not inherited in that way and the field declared with I will go with checking for those variables in At least, I learned a bit about equinox's internals :) |
Hmm. FWIW something like this is fairly common: one has an abstract class, and wishes to check some invariants after initialisation. However, if a downstream class implements Maybe we should add a new method -- call it Of course (b) does mean you can't override this in a subclass, but arguably that's kind of the point. |
Alright, I've just written #492. This adds a new |
I like it! Solves my usecase elegantly. PS: I made a comment to the documentation here |
Great! In that case I'm going to close this issue, and this will appear in the upcoming release (v0.11.0) of Equinox. Thanks for the discussion, this has turned out to be really useful. |
I'd like to indicate to downstream users that a static instance attribute of a abstract base class should be overwritten by its sub-classes, e.g. using
AbstractVar
. However, it's not possible to combine them right now asAbstractVar
s do not allow default values.Is there any chance one could do something along the following lines?
The text was updated successfully, but these errors were encountered: