pyteal icon indicating copy to clipboard operation
pyteal copied to clipboard

Settle on Best Practice for Union / Optional Type Annotations

Open tzaffi opened this issue 3 years ago • 5 comments

Problem

PEP 604 allows the pipe symbol (|) to annotate unions of types. In particular:

X | Y $\equiv$ Union[X,Y]

and

X | None $\equiv$ Optional[X]

However, type forwarding does not work with this new capability. I.e. "Xtype" | Y doesn't work (though "Xtype | Y" does actually work).

Currently our repo is inconsistent when it comes to union types.

Solution

We should settle on a best practice for such annotations, change all usages to adhere to the best practice, and add it to our style guide.

I propose that we disallow | because of its incompatibility with forwarded types. But I'm open to discussion and don't have a strong opinion, except that we should have some convention.

Dependencies

None

Urgency

Very low

tzaffi avatar Dec 19 '22 21:12 tzaffi

My preference is to use | everywhere, even if it requires quoting types already available to be included in the quotes e.g:

class MyClass:
    def me(self) -> "MyClass | None":
        return self

as opposed to:

from typing import Optional

class MyClass:
    def me(self) -> Optional["MyClass"]:
        return self

Where, obviously, None by itself would not normally require quoting.

Reasons:

  • Brevity in declaration
    • Opinion: this makes it easier to read at a glance, I personally find it hard to quickly parse using Optional and Union especially when they're nested
  • Less chance of requiring to import typing in simple cases
  • Consistency with other languages e.g. TypeScript
    • Normally I wouldn't consider this note worthy, but considering there's no PyTeal equivalent for TypeScript currently, I think this bears mentioning.
    • Also it's possible for developers from other languages in general to not immediately grok that Optional[X] means you can pass an instance of type X or None, especially if None doesn't follow it as an initial/default value. Optional could imply omitting the value altogether in a function call but that's not necessarily valid unless it has a default value. It's a notion that one will quickly figure out, but again, since this library is something that's likely to be read by developers from multiple languages, it bears mentioning.

achidlow avatar Dec 19 '22 23:12 achidlow

I'm convinced by @achidlow's argument. Anyone else care to opine? @michaeldiamant @jasonpaulos @ahangsu

tzaffi avatar Dec 19 '22 23:12 tzaffi

I have no objections

jasonpaulos avatar Dec 20 '22 00:12 jasonpaulos

either way's fine with me

ahangsu avatar Dec 20 '22 00:12 ahangsu

I'll follow the majority opinion. I'm less concerned here because the decision feels like it can be changed with minimal friction should a compelling alternative arise later.

michaeldiamant avatar Dec 20 '22 14:12 michaeldiamant