Hacker News new | past | comments | ask | show | jobs | submit login

python will never be "properly typed"

what it has is "type hints" which is way to have richer integration with type checkers and your IDE, but will never offer more than that as is




> what it has is "type hints" which is way to have richer integration with type checkers and your IDE, but will never offer more than that as is

Python is strongly typed and it's interpreter is type aware of it's variables, so you're probably overreaching with that statement. Because Python's internals are type aware, it's how folks are able to create type checkers like mypy and pydantic both written in Python. Maybe you're thinking about TS/JSDoc, which is just window dressing for IDEs to display hints as you described?


I don't think you can say that a language is strongly typed if only the language's internals are. The Python interpreter prevents you from summing an integer to a string, but only at runtime when in many cases it's already too late. A strongly typed language would warn you much sooner.


Your example is bang on when describing a "strongly typed" language. That said, strongly typed is different from "static typing", which is what you described later in your post. Python is both strongly typed and dynamically typed. It is all rather confusing and just a big bowl of awful. I have to look up if I haven't referenced it in a while, because the names are far too similar and there aren't even good definitions around some of the concepts.

https://stackoverflow.com/questions/2690544/what-is-the-diff...

https://wiki.python.org/moin/Why%20is%20Python%20a%20dynamic...


s/will never be/already is/g

https://github.com/mypyc/mypyc

You can compile python to c. Right now. Compatibility with extensions still needs a bit of work. But you can write extremely strict python.

That's without getting into things like cython.


It is properly typed: it has dynamic types :)


Then we have very different ideas of what proper typing is :D Look at this function, can you tell me what it does?

  def plus(x, y):
    return x+y
If your answer is among the lines of "It returns the sum x and y" then I would ask you who said that x and y are numbers. If these are strings, it concatenates them. If instead you pass a string and a number, you will get a runtime exception. So not only you can't tell what a function does just by looking at it, you can't even know if the function is correct (in the sense that will not raise an exception).


It calls x.__add__(y).

Python types are strictly specified, but also dynamic. You don't need static types in order to have strict types, and indeed just because you've got static types (in TS, for example) doesn't mean you have strict types.

A Python string is always a string, nothing is going to magically turn it into a number just because it's a string representation of a number. The same (sadly) can't be said of Javascript.


> It calls x.__add__(y)

Your answer doesn't solve the problem, it just moves it: can you tell me what x. __add__(y) does?


Whatever it's defined to do, and nothing else.

Dynamic typing, but strong typing.

There's no magic going on here, just an attribute lookup. It's still possible to write terrible Python code -- as it is in any language -- and the recommendation is still "don't write terrible code", just as it is in any language. You don't have to like it, but not liking it won't make it any different.

The older I get, the more I like writing statically-typed code. I wrote a lot more Python (for my own use) in my youth, and tend towards Rust nowadays. Speaking of which: if you dislike the dynamic typing of Python then you must hate the static typing of Rust -- what does

    fn add<T:Add<U>, U>(a: T, b: U) -> T::Output { a + b }
do?


Yeah and even with static typing, a string can be many things. Some people even wrap their strings into singleton structs to avoid something like sending a customerId string into a func that wants an orderId string, which I think is overkill. Same with int.


In theory it's nice that the compiler would catch those kinds of problems, but in practice it doesn't matters.


It's very hard to write long-running daemons in python partially for this reason, when you make a typo on a variable or method name in an uncommon code path.


It can matter also in practice. Once I was trying some Python ML model to generate images. My script ran for 20 minutes to then terminate with an exception when it arrived at the point of saving the result to a file. The reason is that I wanted to concatenate a counter to the file name, but forgot to wrap the integer into a call to str(). 20 minutes wasted for an error that other languages would have spotted before running the script.


Both Haskell and OCaml can raise exceptions for you, yet most people would say that they are properly typed.

The plus function you wrote is not more confusing than any generic function in a language that supports that.


> you can't tell what a function does just by looking at it

You just did tell us what it does by looking at it, for the 90% case at least. It might be useful to throw two lists in there as well. Throw a custom object in there? It will work if you planned ahead with dunder add and radd. If not fix, implement, or roll back.


> You just did tell us what it does by looking at it, for the 90% case at least

The problem is that you can't know if the function is going to do what you want it to do without also looking at the context in which it is used. And what you pass as input could be dependent on external factors that you don't control. So I prefer the languages that let me know what happens in 100% of the cases.


Protection from untrusted input is something that has to be considered in any language.

Not yet been a real world concern in my career, outside webforms, which are handled by framework.


> Protection from untrusted input is something that has to be considered in any language

Sure, but some languages make it easier than others. And that was just one example, another example could be having a branch where the input to your function depends on some condition. You could have one of the two branches passing the wrong types, but you will only notice when that branch gets executed.


When is the last time you had a bug IRL caused by passing the wrong kind of thing into plus(x, y), which your tests didn't catch?


It never happened to me, because I don't use Python ;)

On a more serious note, your comment actually hints at an issue: unit testing is less effective without static type checking. Let's assume I would like to sum x and y. I can extensively test the function and see that it indeed correctly sums two numbers. But then I need to call the function somewhere in my code, and whether it will work as intended or not depends on the context in which the function is used. Sometimes the input you pass to a function depends from some external source outside your control, an if that's the case you have to resort to manual type checking. Or use a properly typed language.


This isn't an actual problem people encounter in unit testing, partially because you test your outer interfaces first. Also, irl static types often get so big and polymorphic that the context matters just as much.


And if you specify that they are numbers then you lose the ability of the function to generalize to vectors.

Indeed assuming it adds two things is correct, and knowing that concatenation is how Python defines adding strings is important for using the language in the intended way.


What about the case of passing a number and a string?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: