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

Remove Defaults and Change Relations #125

Open
saulshanabrook opened this issue Feb 26, 2024 · 1 comment
Open

Remove Defaults and Change Relations #125

saulshanabrook opened this issue Feb 26, 2024 · 1 comment

Comments

@saulshanabrook
Copy link
Member

To simplify the model, there is an open conversation/proposal to remove the ability to specify `defaults for functions.

This would entail changing how Unit/relation is implemented, since currently relation desugars to a function that returns a Unit type of () constructor as a default.

Instead, I believe the proposal is to desugar relation into a function that returns a fresh eqsort. That way, you can't union multiple relations.

It comes from this PR egraphs-good/egglog#309 but I don't believe there is a public issue/PR describing the proposal yet.

I was trying to think about how to implement this in Python. In a few places currently, I don't use the relation helper, but manually create functions that return Unit and have a default, since they are methods instead of top-level functions, like here:

@method(default=Unit())
def eval_py_object(self, globals: object) -> Unit:
"""
Evaluates the program and saves as the py_object
"""

So how should this be typed?

One option would be to keep the same typing, returning a Unit type, but just remove the default and do a pre-processing step to translate any functions that return Unit to relations.

However, I think a better way could be just to use the builtin Unit type in Python, None. So the Unit type would be removed, and any function that returns the None type would be translated to a relation. We would still provide the top level relation constructor as well.

This would work well because it would mean that you couldn't pass the result of relations into other functions, i.e. it would no longer be valid to take Unit as an arg. This could be checked statically in Python now.

There is one confusion, that currently some functions can take None arguments, which are upcast to Option<X> types:

class OptionalInt(Expr):
none: ClassVar[OptionalInt]
@classmethod
def some(cls, value: Int) -> OptionalInt: ...
converter(type(None), OptionalInt, lambda _: OptionalInt.none)

I don't think this would cause any ambiguities though, since this None conversion for upcasting would only take place for args, which a Unit couldn't be, and the return of None only is for Unit. The only other place we return None currently as a type annotation is for functions which mutate their args, like __setitem__:

def __setitem__(self, key: IndexKey, value: NDArray) -> None: ...

This is translated into function which returns a new changed NDArray, so it doesn't return Unit. This is automatically set for builtin functions that mutate their arguments, but can also be set for any function that mutates its first arg:

@function(mutates_first_arg=True)
def assume_dtype(x: NDArray, dtype: DType) -> None:
"""
Asserts that the dtype of x is dtype.
"""

So the behavior would be, that for any function with returns None, if it is mutates_first_arg then it will return the type of the first arg. Otherwise, it will be relation.

@saulshanabrook
Copy link
Member Author

I got a question if None in Python is intended to be used as a "Unit" type.

Let's see what the Python docs have to say about this:

None: An object frequently used to represent the absence of a value, as when default arguments are not passed to a function. Assignments to None are illegal and raise a SyntaxError. None is the sole instance of the NoneType type.

From the typing docs:

When used in a type hint, the expression None is considered equivalent to type(None).

Compare to the definition in Wikipedia of:

a unit type is a type that allows only one value (and thus can hold no information)

It does say in that article in Python, the NoneType works as a Unit type.

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

No branches or pull requests

1 participant