15

Possible Duplicate:
How to deal with Python ~ static typing?

I'm basically a Java programmer with little knowledge of python.I really like the syntax of python and the ease with which a programmer is able to express his idea's but also I'm aware that python is dynamically typed and thus is not as fast as Java.My question is why can't python infer type like languages such as scala ?

Community
  • 1
  • 1
Emil
  • 13,577
  • 18
  • 69
  • 108
  • 4
    Scala has types. You just do not have to type them all the time (pun intended). – Thilo Oct 20 '10 at 07:08
  • 1
    I don't think that is a duplicate. The other question is more about "why Python does not need typing at all". – Thilo Oct 20 '10 at 07:11
  • 1
    @Emil: Why do every one want all programming language to look the same? – pyfunc Oct 20 '10 at 07:12
  • 1
    @pyfunc: Emil did not ask about changing the look of Python. He just asked why type inference (which could lead to better compile-time error checking and improved performance) is not done. – Thilo Oct 20 '10 at 07:15
  • 2
    While it is true that Python is usually not as fast as Java in many common applications, I fail to see what that has to do with static vs. dynamic typing. – MAK Oct 20 '10 at 07:34
  • @pyfunc: Again, no one is proposing to make any change to the Python language. And while we need many languages, not every language needs its own runtime backend. – Thilo Oct 20 '10 at 07:44
  • There were 2 votes for duplicate, 1 for off-topic, and 1 for subjective and argumentative. I voted for duplicate because it's closely related even if someone doesn't want to call it a duplicate, and because I'd rather include that link than close as subjective and argumentative. –  Oct 20 '10 at 09:30
  • @Emil: Looks like the Pythonistas didn't like your question... – soc Oct 20 '10 at 11:17
  • Pycharm, WingIDE, emacs, and Pydev come with pylint that does type inference, but Python itself does not. MonkeyType can generate types from Python code after it is run, but instead of types, I suggest you look at values though which can be generated with sys.set_trace like http://chrislaffra.blogspot.com/2016/12/auger-automatic-unit-test-generation.html – aoeu256 Sep 21 '19 at 18:49

3 Answers3

27

It is not that Python can't, but it doesn't. The difference is in the type systems that the designers of the languages choose to follow.

Python uses duck typing and has typed objects but untyped variable names. Type constraints are not checked at compile time; rather, operations on an object may fail, signifying that the given object is not of a suitable type. Despite being dynamically typed, Python is strongly typed, forbidding operations that are not well-defined (for example, adding a number to a string) rather than silently attempting to make sense of them.

Scala is a statically typed language, that is, types are checked at compile time. A local type inference mechanism takes care that the user is not required to annotate the program with redundant type information. Operations that break type constraints leads to compiler errors, not runtime errors. Also see The Purpose of Scala's Type System, especially the section where duck typing is discussed.

Michael Mior
  • 28,107
  • 9
  • 89
  • 113
Vijay Mathew
  • 26,737
  • 4
  • 62
  • 93
  • There are some Python compilers that can infer types automatically, such as [RPython](https://rpython.readthedocs.io/en/latest/translation.html?highlight=%22type%20inference%22). This is only possible because RPython is a statically-typed subset of Python. – Anderson Green Jul 08 '19 at 18:27
  • Try using doctests to understand programs, and if not try this: http://chrislaffra.blogspot.com/2016/12/auger-automatic-unit-test-generation.html – aoeu256 Sep 21 '19 at 18:51
  • There are also a few Python libraries that can infer types of functions at run-time, like [MonkeyType](https://github.com/Instagram/MonkeyType). – Anderson Green Sep 08 '20 at 20:28
3

Python doesn't do static type inference, because it wants to let you do things that are impossible under such a scheme. For example:

def myfn():
  if random.random() > 0.5
    return "howdy"
  else:
    return 7

x = myfn() #  Am I a string or an integer?

What should the type of x be?

EDIT : example was:

def myfn(x):
  try:
    return str(x[0]+1) + " is my favourite"
  catch IndexError:
    return x+1

myfn(1) #  = 2
myfn( [2,4,6] ) # = "3 is my favourite"
Michael Anderson
  • 70,661
  • 7
  • 134
  • 187
  • 1
    Well... it could generate two behind-the-scene functions: Sequence -> str (or maybe Sequence -> Sequence) and int -> int. Kind of like overloading. – Ionuț G. Stan Oct 20 '10 at 07:28
  • OK, I'll ajust it to something that is even more trivial yet harder to track. – Michael Anderson Oct 20 '10 at 07:37
  • 1
    def myfn(x: Array[Int]) = try Left(str(x(0) + 1) catch { case e: ArrayIndexOutOfBoundsException => Right(x + 1) – Ricky Clarkson Oct 20 '10 at 08:01
  • You're right, that's trickier. In my opinion though, it matters a lot how that function is used, so in this latest case, the compiler knows that `myfn` returns a string or an int and can at least ensure that you're not calling list methods on the return value. Now, that's a strange example anyway, and I can't really see a real world usage of it, which tells me that some trade-offs can be employed, like forbidding functions returning really different type of arguments. – Ionuț G. Stan Oct 20 '10 at 08:02
  • Why would you ever want to use functions like these? – Tom Crockett Oct 20 '10 at 09:01
  • @peletom - Maybe you need a function that returns an array or single value depending on whether you pass the "all" or "first" as the search_type argument. – Michael Anderson Oct 20 '10 at 09:29
  • 3
    Impossible? `def myfn = if (util.Random.nextBoolean) "rowdy" else 7; val x = myfn` <-- perfectly valid Scala. – Daniel C. Sobral Oct 20 '10 at 12:57
  • @Michael Anderson: but then you need to dynamically check the type of the result before you do anything with it, so what have you gained over always returning an array and then checking the size? – Tom Crockett Oct 20 '10 at 16:42
  • @pelotom - Since I passed it the argument as either "all" or "first" I know whether I'll be getting back an array or a single value, no need to check anything. – Michael Anderson Oct 20 '10 at 22:21
  • @Michael how's that different than calling ".first()" on the result? I see no real advantage here. – Tom Crockett Oct 20 '10 at 22:26
  • @daniel - In this case is the return type of myfn just Any? Then I expect that in a lot of pythonesque situations you end up passing around a lot of Any typed objects which the system then has to type check at run time... thus losing the benefits of scalas type inference? (I'm assuming a lot about how scala behaves that may well be wrong) – Michael Anderson Oct 20 '10 at 22:29
  • @Michael - yes, you would end up with the most general type that could contain two completely dissimilar types, which is usually Any. And yes, you would lose all the benefits of static type checking, but it would be no worse at that point than the situation in python. So the point is, you can do this in Scala, but why would you want to? I can think of one big reason *not* to: it becomes very hard to reason about what exactly your functions do. – Tom Crockett Oct 20 '10 at 22:35
  • 1
    @Michael The return type is `Any`, indeed, and Scala won't let you do almost anything with it unless you match for its type or type cast it. The difference is that Scala won't let you call a method unless it knows at compile time that the object supports it, while Python will let you call any method, whose applicability will only be known at run-time. Using a dynamically typed language is like saying to the compiler "trust me, I know what I am doing." Using a statically typed language is like saying "check this to see if I am right." – Daniel C. Sobral Oct 21 '10 at 13:04
  • Lots of python IDEs do type inference but they are not guaranteed. If you want to know what a giant piece of code of Python code you didn't write does, try using set_trace like http://chrislaffra.blogspot.com/2016/12/auger-automatic-unit-test-generation.html – aoeu256 Sep 21 '19 at 18:53
  • This function could return `Union[int, str]`, if we would use mypy types ;) https://mypy.readthedocs.io/en/stable/kinds_of_types.html#union-types – Maksim Apr 10 '20 at 17:33
-2

Python is dynamically-typed, whereas type inference is only possible in statically typed languages. Static typing would be impossible to implement without dropping support for features such as lists of arbitrary objects.

Gintautas Miliauskas
  • 7,744
  • 4
  • 32
  • 34
  • Not sure. For "x = 123" the compiler should be able to infer that x is an integer. – Thilo Oct 20 '10 at 07:13
  • 1
    @Thilo: "x = 123; x = str(x); x = [c for c in x]" , is x an int, a string, or a list? – Lie Ryan Oct 20 '10 at 07:18
  • 1
    @Lie Ryan, I guess the compiler could rewrite the identifier names, so that all can live together. `x_int = 123; x_str = str(x_str); x_list = [c for c in x_str]`. – Ionuț G. Stan Oct 20 '10 at 07:23
  • 1
    @Ionuț G. Stan: let's assume the compiler does that, how would you rewrite `x = 123 # assume this is from function argument`; `if x in [123, '234']:`; ` x = '123'`; `else:`; ` x = ['2', '3', '4']`; `print x if '3' in x else 'no 3'`; it gets really messy to retranslate that to statically typed names. – Lie Ryan Oct 20 '10 at 07:36
  • @Lie. Of course it would not work in all cases. That does not mean that it is not a useful optimization in cases where it does work. – Thilo Oct 20 '10 at 07:45
  • 1
    @Thilo: Psyco does a limited form of type inference at runtime. It basically detects the type of the objects, recompiles the python to x86 instructions under that type assumption, and then injects the compiled code into the running code and adds some type checking to ensure that the type inference is not violated; if the type inference do gets violated, two things can happen: the python version will get invoked or psyco will generate a second version of the compiled code using the second type assumption. – Lie Ryan Oct 20 '10 at 07:48
  • I assume that in effect something like this also happens on the Hotspot JVM for Jython. If this works well, type checking in the language compiler would be premature optimization (as some people claim) at least for the performance aspect. Compile-time error checks would still be nice (even if they would necessarily not be as comprehensive as for Java or Scala). – Thilo Oct 20 '10 at 07:56
  • Type inference is not the same as static typing. It is entirely possible to do type inference on a dynamically typed language. For example, if you have a block of code `x = 3` and nothing else touches `x`, then `x` is definitely an integer. Of course you can apply much more complicated rules, but that's the idea. – Michael Mior Dec 17 '15 at 17:30
  • @LieRyan Rust language has type inference, and this code would be valid there: `let x = 123; let x = x.to_string(); let x = x.chars().collect(); // Will be array of characters` – Maksim Apr 10 '20 at 17:27