3 ms·
Isn'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'l
by hershel 13y ago
Isn'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.