Skip to content
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

refactor[next]: new type system #1428

Closed
wants to merge 7 commits into from
Closed

refactor[next]: new type system #1428

wants to merge 7 commits into from

Conversation

petiaccja
Copy link
Contributor

No description provided.

Copy link
Contributor

@egparedes egparedes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very preliminary and high-level review of the core aspects of the PR, just to start a conversation. I gave feedback on some Python implementation details and in the compatibility with scalar type specifications in Python libraries.

import dataclasses


class Trait:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this class is empty it can only be used for type annotations or isinstance() checks, so it works as a Union type, which python already defines and supports exactly these two cases. I would remove the empty class and add the explicit union type at the end of the file.

Trait = SignednessTrait | FromTrait | ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue with this approach is that if you create a new SomethingTrait outside of this file, you won't be able to make it a subclass of Trait for the annotations and isinstance checks.

Comment on lines 14 to 18
class SignednessTrait(Trait):
"""Specifies the signedness of a type."""
@abc.abstractmethod
def is_signed(self) -> bool:
...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An abstractmethod can only be used inside a class inheriting from abc.ABC, otherwise it's useless. In this case, since the abstract class is only defining and interface and not implementing any common functionality, it would make even more sense to define the class as a runtime checkable protocol (which is also an ABC class), and thus inheriting from it would be completely optional.

Suggested change
class SignednessTrait(Trait):
"""Specifies the signedness of a type."""
@abc.abstractmethod
def is_signed(self) -> bool:
...
@runtime_checkable
class SignednessTrait(Protocol):
"""Specifies the signedness of a type."""
@abc.abstractmethod
def is_signed(self) -> bool:
...

The same comment applies to all Trait classes in this file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I added the ABC as base class for all of them that had abstract methods.

I don't think this is very well suited for protocols though. Protocols help you decide if an object fits a well-known interface after you've made the object, while abstract base classes help you create an object after you decided it fits a well-known concept. Signedness is a well-known concept, but there is no well-known interface for it in this context, hence the abstract base class that defines the interface.

IMO it's also useful that you can look at a Type and tell at a glance what Traits it implements just from the list of base classes instead of having to go through its methods and matching them against all the different Traits. There is also the possibility of a Trait with no methods, in which case you couldn't use runtime checkable.

from .traits import FunctionArgument


class Type:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class is not needed. See my comment in traits.Trait.



@dataclasses.dataclass
class IntegerType(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These IntegerType and FloatType definitions make sense to me. However, the concepts here deviate a bit from the most common conventions in array/tensor libraries used in the community. Ideally, we could represent arithmetic types in a way that is compatible with both dtype-like descriptors used by array libraries at runtime for data exchange and allocation, and internally in our description of the ASTs. A first step into this direction are the DType definitions on gt4py._core.definitions based on DLpack (https://dmlc.github.io/dlpack/latest/) and the Python Array API standard (https://data-apis.org/array-api/latest/API_specification/type_promotion.html#type-promotion). The current implementation there still needs to be polished and extended so I think it would make sense to try to unify those with the definitions here, instead of having two similar but incompatible representations for the same concept.

Actually, I think the core part of the new_type_system could be moved into gt4py._core to make things simpler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really think it's a good idea to include these tasks in this PR. First, the goal of this PR was to find a cleaner representation of AST types, and it delivers that in a self-contained package. Turning it into an open-ended task would just delay it and reduce quality. Second, if the DType definitions and their use cases and usage patterns are not clear, it's difficult to decide if merging makes sense at all, and if it does, how it should be done. And, third, this type system is only for gt4py.next, so unless it's backported to the cartesian version, I don't see the benefits of lifting it out of next.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future, yes, it might make sense to do these changes, but if the code is kept clean and well-tested such refactorings should be fairly straightforward.

@petiaccja petiaccja closed this by deleting the head repository Mar 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants