Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> They lack static type checking, but I find that a thorough test suite catches most type errors anyway.

Maybe ruby is different than python in this regard, but with python I see a lot of “assert isinstance(arg, dict)” in functions which would not be necessary with type checking.

Feeding an unexpected type into a function, and having it carry on as normal, is really scary.



I've seen this too, but I tend to think of it as an antipattern.

The fact is, in most cases a Python function won't carry on as normal if you feed it an unexpected type, because while Python's type system isn't static, it is fairly strong. In general I am a fan of strong types and I would like it if Python's type system were a lot stronger.

But ultimately this isn't what my post was about: I'm talking about modeling your domain with types, not type checking.


What do you mean it's fairly strong? Not challenging you, I'm just trying to get my head around all the type stuff.


As hwayne said, most of the time Python won't do implicit type coercion. What this means is, if you try to do something that doesn't make sense based on the types, it will throw an error rather than go on. For example:

    ~/$ python
    Python 3.7.4 (default, Oct 12 2019, 18:55:28) 
    [Clang 11.0.0 (clang-1100.0.33.8)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> hello = 'Hello, world'
    >>> one = 1
    >>> hello + 1
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: can only concatenate str (not "int") to str
To put this in context, type systems can be roughly divided into 4 categories along the strong/weak and static/dynamic axes:

1. Strong static types (makes a lot of assertions about type, checks these assertions at compile time; Haskell, ML, OCaml, Rust, C# are reasonable examples--Haskell folks would probably laugh at me including C# here, but it's the only example in widespread non-academic use). Example (C#):

    var hello = "Hello, world";
    var one = 1;
    var result = hello + one // Doesn't compile
2. Strong dynamic types (makes a lot of assertions about type, checks these assertions at run time; Python is the best example I have, but to be honest, it's not a great example--I think the type system could be a lot stronger). See the Python code above for an example.

3. Weak static types (makes few assertions about type, checks these assertions at compile time; C, C++ are good examples, although it's arguable that C actually does more checking at run time than at compile time). Example (C):

    char* hello = "Hello, world";
    int one = 1;
    char* result = hello + one; // Happily compiles
4. Weak dynamic types (makes few assertions about type, checks these assertions at run time; JavaScript is a great example of this). Example (JavaScript):

    >>> var hello = "Hello, world"
    undefined
    >>> var one = 1
    undefined
    >>> hello + 1
    "Hello, world1"
In general, I have a slight preference for static types over dynamic types, but I think that difference is overrated. I care a lot more about my preference for strong types over weak types.


Awesome thanks!


Most of the time Python doesn't do implicit type coercion.


"Feeding an unexpected type into a function, and having it carry on as normal, is really scary."

That is how duck typing works. Generally you shouldn't use "is instance" but more use a set of "callable" checks to make sure the structure has the required functions.

Things like Go Interface types are, of course, a formalisation of duck typing and is what has helped static typing come back into fashion.


This still produces a runtime error, to make code maintainable you want to be able to check the types without having to run the program. The type annotations help with that, they allow to spot bugs in the code and make an IDE to correctly refactor code and provide autocomplete.


> This still produces a runtime error, to make code maintainable you want to be able to check the types without having to run the program.

I strongly disagree. There are plenty of ways to write maintainable code. Static types can help, but it's quite possible to write maintainable code in dynamically typed languages.

And, for the record, running unit tests doesn't require me to run the whole program.

And, even if I never explicitly test types (assert isinstance(foo, str) is an antipattern anyway), behavioral tests of my code will turn up most type errors.

The obsession with checking types at compile time rather than 30 seconds later while running the unit tests doesn't serve anyone.


Type checks don’t actually enforce anything though, and as far as I can tell don’t even produce a warning in vscode unless everything is typed (a typed var fed into a typed function signature).


Correct, the annotations in python don't enforce anything, although there are packages that make them produce errors, but again, those errors are at runtime.

You can run mypy which will list problems. Also PyCharm understands the annotations and does all the things I mentioned it do: proper autocomplete, proper refactoring functionality and highlighting errors




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

Search: