No, the workaround is to stringify "Node".
def add_sub(self, sub: 'Node'):
def get_subs(self) -> Sequence['Node']: #Or maybe 'Sequence[Node]'
> This complexity helped drive the introduction of the auto keyword to C++. There are many situations where writing the type information isn’t workable. This is especially true when dealing with parametric container classes,
This is absolutely wrong! You cannot annotate a function as returning `auto` in C++. `auto` and its variants in other languages are useful for eliding redundant type declarations. Especially long ones that use generics/templates. `auto foo = MyContainer<Tuple<int, str>>();` or whatever is nice than having to double write the type declaration. But, in C++ or java, if you write a function that returns a Mycontainer<Tuple<int, str>>, you have to write that in the function.
This is an intentional choice: function declarations are your apis, and explicit and clear APIs are useful for human readers of your code. That's why you should annotate the public apis even when you can have them be type inferred. Speaking of which, if you want type inference, check out pytype, it's like MyPy, but does do type inference on unannotated code. But you should still annotate your public apis. It serves as a sanity check that you aren't accidentally returning something you don't expect.
And of course, being familiar with the differences between iterables, iterators, sequences, containers, etc. is not a bad idea.
Maybe I'm misunderstanding something, but one can write a function auto foo() in C++ and the return type is inferred. Lambda functions infer the return type by default.
This excludes, as you mentioned, the return types of a function, its parameter's types, as well as the types of fields in a class.
1. Is gradually typed,
2. Doesn't infer types, and
3. Is strict, in that it doesn't allow operations that change types.
It was originally developed as a replacement for mypy that was faster and scaled better to very large codebases.
You can do that since C++14.
The good thing about inference (especially with a REPL) is you can write it without the annotation, and then use the inferred type (in Haskell, I usually find that when I resist the temptation to explicitly annotate types, the actual types are more general than I would have specified.)
But my coding in Haskell is pretty much personal and toy projects; I like the approach, but it may not be ideal for coding in anger.
Inferred, loose parameter types are great, because while I think it's good to know the differences between iterator, generator, iterable, sequence, container, and so on, it's difficult, and inference will give you the loosest one. But with return values, the inferred type will be the tighest, in other words your function will return a Dict (or worse, a defaultdict) instead of a Mapping or MutableMapping. You almost always want a Mapping.