3 ms·
I agree that for quickly writing code Python is quicker, but I'm not sure it's necessarily to do with dynamic typing. I've been using Go for about a year and a
by afandian 13y ago
I agree that for quickly writing code Python is quicker, but I'm not sure it's necessarily to do with dynamic typing. I've been using Go for about a year and a half and Python for about double that (and other things before that like C#). I'm still trying to pin down the usability differences, and what causes them.
List comprehensions are one of the most obvious things. LINQ and Haskell and co have shown that this is absolutely doable with a static type system.
The lack of genericity is one of those things that will be argued about for the lifetime of Go, I think. Python doesn't need it because of the dynamic typing but the same problems are solved to some extent by the compile-time-duck-typing enabled by its interface system.
I'm not sure I agree re productivity. One on project I reached 30,000 lines of Python, collaborating with 3 other people remotely. Some things would have been a lot easier with static typing. I think.
- nostrademons 13y agoThere's work in progress on type inference and static typing for Python, and Python 3 supports type annotations (PEP 3107). Whether they'll get anywhere remains to be seen - it's a challenging problem, not the least because several of the language built-ins have strange typing rules. (What's the type of multiplication?) type(3 * 5) => int type(3.0 * 5) => float type(3 * 'foo') => string type(3.0 * 'foo') => TypeError
- hershel 13y agoIsn't operator type can be defined using 2 parts: 1. What object calls the operator relevant method 2. Looking at the code of the relevant operator call, we'll see something like if type(obj)==str , do X . so depending on the type of obj , we can deduce output type automatically . Another option is to use the approach mypy uses: let the language mix static type and dynamic type freely, and if we cannot determine type, let the code by dynamic , with the relevant warning . Yes mypy isn't written yet, but it would be interesting to see how useful this approach would be.
- nostrademons 13y agoThere are a few big problems with that... The first is that multiplication is...well, not always commutative in Python, but it has two operands and either of them can be the method receiver. For example: type(5 * 3) => int type(5 * 3.0) => float type('foo' * 3) => string type('foo' * 3.0) => TypeError More generally, multiplication might be a method on either the right or the left type. If __mul__ is defined on the left operand, the interpreter executes the code in it. If not, and __rmul__ is defined on the right operand, the interpreter executes the code in it instead. If neither is defined, the interpreter throws a type error. So typing a * b requires knowing the types of both a and b and merging a set of rules for each of them. The other problem is that you cannot in general determine the type of an expression by inspecting code, unless you apply some rules to the legal expressions in the language. For example, take this code fragment: def foo(fn): if typecheck.static_type(fn) == int: return 'a string' else: return 0 Assuming typecheck.static_type is our hypothetical typechecker and it operates on function objects. What should the type of foo(foo) be? I suspect that any working solution involves some sort of constraint solver that gathers up all the constraints, simplifies them, determines if they're compatible, and then outputs a list of possible types it could be, each subject to certain assumptions on the input types.
- hershel 13y agoAgain i'm missing the problem. If typecheck.static_type evaluates type on an object , typecheck.static_type(foo) returns type 'function'. And our function will return 0 , meaning type == int. if typecheck.static_type does something else , more complex , we could always tell our tool that fn is dynamic.
- nostrademons 13y agotypecheck.static_type is supposed to give you the full type of the object - not just 'function', but 'function(int) -> int'. Or I guess I in this case I was just looking at the return type, so 'int'. Hence the problem - foo is defined so that if its type is int, it returns a string, while if its type is string, it returns an int. The problem with giving up and returning 'dynamic' is that dynamics tend to propagate through the code if you're doing anything moderately complex. If we give up, then any expression that calls foo() now typechecks as 'dynamic', and any expression that calls one of them typechecks as 'dynamic', and so on. You end up with a typechecker that doesn't tell you anything useful about your program, other than that it was dynamically typed. If this is restricted to a few special cases like, say, Django ORM classes or namedtuple, it's not a huge problem, because you can hardcode in specific rules for them (or put in a plugin mechanism). But tricky typing rules abound even in the basic language features; as mentioned above, multiplication does not even have concisely expressible typing rules in Python.