Personally I am in love with the language but worried about it not gaining enough traction and ending up abandoned because of it.. that's keeping me from using it for non-trivial side-projects.
The proposal for square brackets List[int] in generics is the weirdest thing. There is a standard un-surprising way to do this and it is angle brackets List<int>. What is the reason for forcing developers to use this jarring syntax?
Angle brackets cause difficulties during parsing: since there is a '>>' operator, getting a type like 'List<List<int>>' to parse properly would require either a hack in the lexer or requiring a space between closing angle brackets (as in 'List<List<int> >')
I can think of one reason: `<` and `>` are comparison operators in Python, and they are easily overloaded with the `__gt__` and `__lt__` magic methods. So, if `List` was an instance of an object with those overridden magic methods, it's unclear what you actually want to do (i.e., `List<int` might evaluate to True, and then `True>` would lead to a syntax error). `[` and `]` have no such limitations.
"`List<int` might evaluate to True, and then `True>` would lead to a syntax error"
You are confusing parsing and reduction. In most languages - and almost certainly in Python - these are separate steps. "Parsing it wrong leads to a syntax error" is a good thing - it means you're forced to parse it right. It would be worse if there were multiple syntactically-valid interpretations (which there may well be).
Here's the problem:
`a<b>c` is already valid python. `3<5>2` evaluates to true, because python allows operator overloading. Because the < and > operators can be overloaded, there is no guarantee that an object of type "class" will not have them (this would, I believe, require some metaclass hackery, but still).
So, given that `object<int>()` throws a type error in python and not a syntax error, you can't unambiguously parse that.
Note that Guido's proposal doesn't add any syntax changes. The idea is not to modify the language but rather to have a unified format for defining type annotations. Function annotations have been there for many years now, and the only thing that will be added for now is some support in the standard library for the objects that will be used as type annotations.
This was a bikeshed in the Rust community as well a pretty long time ago. They went with the `List<int>` style, which makes sense in light of C++ programmers being a large target audience of theirs, but that's far less a consideration in Python's case. I personally slightly prefer the square brackets, because it seems to imply "contains" because of its association with retrieving values from containers.
Has anyone explored the potential for these hints to be a front-end to Cython, or provide optimizations in CPython/PyPy? Static typing has big perf benefits too right, is that included in the eventual goals?
At least for Python, there are a different set of goals for programmer-productivity type hints (such as these) and for static-compilation type hints (such as you would need to provide optimizations).
One particular point is Python subclasses: it makes a lot of sense to say that a Python subclass is a subtype of the parent class, but in reality there are no guarantees about any relationship. This means that a compiler/VM would most likely have a hard time making use of type annotations since it would have to have to support the user passing arbitrary subclasses with completely different behavior.
They're certainly a bit obscure though. Julia is the only new language that I'm aware of that prominently features multiple dispatch as a first-class language feature: http://julia.readthedocs.org/en/latest/manual/methods/
I think I could get over that, but the idea of putting this hinting in comments is troubling for me:
x = {} # type: Dict[str, str]
I mean, it's very human-readable so it makes sense as a comment. It's optional, so not every declaration will have it. Still, something about the interpreter reading my comments is off-putting.
Yeah, that gives me the heebie jeebies. Fair enough if you want to use magic comments for an entirely third-party system like MyPy, but using them for a built-in language feature feels wrong.
Besides, how necessary is it? Presumably those constrained types can be instantiated:
x = Dict[str, str]()
The constrained type's __new__ would be annotated appropriately, and return an ordinary dict. It's a bit less "pure" in that this is no longer strictly an annotation, but I'd much prefer that bit of impurity than magic comments.
- Editors and IDEs can use them to provide better autocompletion for you. That way you can discover how to use APIs while you write code without having to look at the docs all the time.
- Static analysers can tell you when you're making trivial errors just after you type them.
- They provide a form self documentation. In practice, most medium to large Python projects already add type signature information in the form of docstrings, using thing like '@param'. This is better because it's more uniform.
This is not against duck typing, you can use Abstract Base Classes to define an interface for some behaviour and match objects that provide that behaviour even if they don't belong to any specified type hierarchy.
Finally, this is completely optional. You can keep coding without types for your small scripts or private functions, while using type information for the APIs of big libraries.
On the other hand, this could be used for some nice "duck type checking".
Rather than the classic interface pattern, where the passed object must be a subclass of a certain type, these annotations could be used inversely to that. Something like:
Where other classes don't need to explicitly inherit from foo, but rather, a checker can raise a warning where you are passing something that doesn't have an integer attribute (or getter function) called n, and the x and y functions. This allows some nice analysis, while still allowing good duck typing.
There are ways to do this without special keyworks too... that was just a quick first example. (maybe something like:)
class foo:
def x(): pass
def y(a: int) -> str: pass
n: int
def bar(it: duck_as(foo)) ->str: pass
You can have this today by inserting an explicit decorator that validates annotated arguments. You can even skip the decorators by dynamically wrapping callables with the validator.
It looks quite simple/elegant. Plus what they're added is meant to be used by static analysis tools and IDEs, not actually for validating things at runtime.
Having these checks available for development does allow you full confidence in the type safety if the entire call stack has type annotations.
If you're using some code that doesn't have these annotations, you might catch problems during development, or might not. But that's just the old familiar situation, and it allows you to iterate quickly while choosing which parts are more critical.
Note that this is analogous to the design choice made by Typescript, while the designers of Atscript chose to extend Typescript with runtime assertions as well.
Nonstatic typing brings down productivity very noticeably whenever I use it on anything beyond a small script. It introduces a large category of errors to make that static typing prevents; static typing makes the program more cohesive, structured, rigorous, and predictable. The only compelling reason for taking it away is laziness that'll hurt you in the long run, or if the problem/script is very small or trivial.
Who modded that down? He has a good point. This is a bad idea. In particular, "Python's static type-checking would be optional - programs can still be run even if the static checker has complaints." is a really bad idea. It means the type annotations can't be used for optimizations. Or we'll have code that only runs with optimization turned off, or on some compilers.
1. The default will be dynamic typing. But you can change that.
2. You can specify a specific module you release as static. This will only affect the internal parts of the module, with one exception - when you call something of that module with the wrong type, you'll get a warning "this runs XX times slower because of a wrong type, change..." , but when you run it with the right type, you'll get great speedup ?
1. The default will be dynamic typing. But you can change that.
2. You can specify a specific module you release as static. This will only affect the internal parts of the module, with one exception - when you call something of that module with the wrong type, you'll get a runtime type exception, so there's no problem working with dynamic code with a fast module.
1. The default will be dynamic typing. But you can change that.
2. You can specify a specific module you release as static. This will only affect the internal parts of the module, with one exception - when you call something of that module with the wrong type, you'll get a warning "this runs XX times slower because of a wrong type, change..." , but when you run it with the right type, you'll get great speedup ?
1. The default will be dynamic typing. But you can change that.
2. You can specify a specific module you release as static. This will only affect the internal parts of the module, with one exception - when you call something of that module with the wrong type, you'll get a runtime type exception, so there's no problem working with dynamic code with a fast module.
1. The default will be dynamic typing. But you can change that.
2. You can specify a specific module you release as static. This will only affect the internal parts of the module, with one exception - when you call something of that module with the wrong type, you'll get a runtime type exception, so there's no problem working with dynamic code with a fast module.
"Pythonic" is the "patriotic" of programming language world. The term is disgusting. Your language will eventually become lederhosen, beer and bratwurst or apple pie, hamburgers and the Fourth of July. It might make you feel good, but it doesn't mean anything.
Sure, but isn't the comment obviously a demonstration of formal parameter syntax rather than functionality? Surely the more idiomatic Python would be not to write the function at all if it does nothing (and then there's no example code to illustrate with).