vyperlang / vyper

Pythonic Smart Contract Language for the EVM
https://vyperlang.org
Other
4.91k stars 802 forks source link

VIP: Allow declaring tuple types at the definition site #2480

Open charles-cooper opened 3 years ago

charles-cooper commented 3 years ago

Simple Summary

Something like this should compile:

(a: bool, b: uint256) = True, 1

Motivation

External calls can return tuples. Let's say there is an interface like def foo() -> (bool, uint256): view

Currently the way to use it is

a: bool = False
b: uint256 = 0
a, b = <some contract>.foo()

Everybody understands what is happening but it's not very ergonomic. This would be more ergonomic (and save a couple MSTOREs too):

(a: bool, b: uint256) = <some contract>.foo()

I don't really see any downside to allowing this besides a bit more complexity in the type checker.

Will also make https://github.com/vyperlang/vyper/issues/2400 easier to use, the pattern will be like follows:

(success: bool, ret: Bytes[...]) = raw_call(<some contract>, ..., revert_on_failure=False)

Backwards Compatibility

Backwards compatible

Dependencies

References

Copyright

Copyright and related rights waived via CC0

fubuloubu commented 3 years ago

Note that this is currently invalid Python syntax (as of Python 3.8), so a custom parser would be needed.

charles-cooper commented 3 years ago

Assuming we had a custom parser, what would the ideal syntax be?

fubuloubu commented 3 years ago

I think the mentioned syntax or even just a: bool, b: uint256 =...

charles-cooper commented 3 years ago

I think the mentioned syntax or even just a: bool, b: uint256 =...

OK I like this, with the caveat that if PEP484 ever gets updated to allow this (declaring tuple types at the definition site), for syntactic compatibility with python we should throw out our way of doing it in favor of the PEP484 way.

charles-cooper commented 2 years ago

we can do this by adding a pre-parser rule which translates to valid python by mangling the identifiers together. for instance,

preparser:
x: int, y: int = 1, 1 => x___y: (int, int) = 1, 1

then later in the analysis we can handle these mangled identifiers, e.g.

ast analysis:
if Name.contains("___")
... handle tuple annotation like for t in Name.split("___")...

h/t to @electriclilies for the idea of handling in the pre parser

charles-cooper commented 2 years ago

better solution for mangling! in the python AST, non-name nodes can be the target. see the docs https://docs.python.org/3/library/ast.html#ast.AnnAssign, especially that these examples are syntactically valid: a.b: int, a[1]: int.