6 ms·
I saw someone describe python as “stressful” for this reason and I couldn’t agree more. It’s difficult to have confidence in any change I make or review. I need
by aomix 1y ago
I saw someone describe python as “stressful” for this reason and I couldn’t agree more. It’s difficult to have confidence in any change I make or review. I need to sit down and manually exercise codepaths because I don’t get the guarantees I crave from the language or tooling. While with the small amount of Rust code I’ve written lately I could yolo changes into production with no stress.
- pnathan 1y agoAgreed. I had to work in a larger Python codebase after spending a few years with Go and Rust and the drop in logical confidence around the language was remarkable. I have, roughly, sworn off dynamic languages at this point. Although I have dreams of implementing a firm typed system over Common Lisp.
- -__---____-ZXyw 1y agoFirm like: https://coalton-lang.github.io/20211010-introducing-coalton/ ?
- pnathan 1y agoI need to spend some quality time with Coalton. I don't think it's _quite_ what I want, but its in the same key.
- shermantanktop 1y agoSame, though my trauma was Ruby. Those Rubyists who were apparently born with the language spec in their heads can do amazing things, but I am a mere mortal who needs to be told I wrote bad code right when I wrote it, not told at 2am on a production server.
- stinkbutt 1y agodo you not test your code?
- pavel_lishin 1y agoIn a large enough code base, there is no "your code". There is the code you wrote today, there is the code you wrote two years ago, there's all the code people are writing around you. I change a function's arguments, I'm _pretty_ sure I caught every place it's called (spoiler alert: I didn't, because someone calls functions dynamically based on their names with call_user_func_array, maybe), and I ran the test suite - everything works, and I've fixed what doesn't. Except some of that old code written 8 years ago didn't have good tests, or didn't have any tests at all, or didn't cover the specific code path. And now it's 2am on the production server. Now, you could tell me - Pavel, you're an engineer, you should be sufficiently dedicated to your craft to verify that the tests are testing those paths, you should find all those instances where that function is called (a few dozen times across the codebase), and check that those tests exist and are good. And you're not wrong! I should be doing cleanup in the codebase as I go, washing those dishes while I wait for pasta to boil or whatever... ... but now I've given myself two more actual engineer-weeks of work for a change that just needed to add a flag to a function to make sure only premium users get emails when something happens. My manager will be thrilled to hear it. Do you think I'll get a raise?
- deleted 1y ago[deleted]
- felipeccastro 1y agoI’m assuming that Python code base didn’t have thorough type hints. What if it had? Would Go still feel safer? I know these aren’t checked in runtime, but Python type system seems more thorough than Go’s, so shouldn’t a Python code base fully typed be even safer than Go? If so, why not? (I know Python type checks aren’t mandatory, but for this question assume that the type checker is running in CI)
- pnathan 1y agoSince Python type checking is functionally optional, it implies that somewhere, somehow, someone has opted out, or has used a type checker that differs subtly but unpleasantly from the one you're using. Python's type checker systems are fundamentally a _linter_ more than something like Java or C...or Rust. It's not about feeling. It's about the theorems you can make about the codebase. With Python the answer actually is ¯\_(ツ)_/¯.
- misiek08 1y agoYou mean compiler vs client reporting issues? Never safer.
- felipeccastro 1y agoYes, but in practice, is the difference significant enough to matter? I’m genuinely looking to see if I’m missing anything when favoring Python type system over Go’s.
- pansa2 1y agoOne difference is that Python's type system is unsound. You can write code that passes `mypy --strict` but still contains functions that, for example, claim to return an `int` but actually return a `list` [0]. AFAIK it's not possible to circumvent Go's type system in such a way. [0] https://news.ycombinator.com/item?id=43508152 https://news.ycombinator.com/item?id=43508152
- kbolino 1y ago
- jlarocco 1y ago> I need to sit down and manually exercise codepaths Isn't that exactly what unit tests are for?
- airstrike 1y agoExcept now you're writing and maintaining twice the amount of code instead of relying on the compiler and/or type checker to help you catch those errors
- jlarocco 1y agoSorry, but I don't agree that static typing is a replacement for unit tests. I can see static languages having fewer unit tests, but it's not going to eliminate them.
- alternatex 1y agoStatic typing is a replacement for unit tests aimed to catch type bugs. Also, no one has 100% code coverage so might as we get some guarantees for granted. I understand that statically typed code doesn't mean bug-less code, but I always find it odd that dynamic language enthusiasts feel like they need to stretch the benefits. Dynamic languages are great for many things. Strictness is not one of them and that's fine.
- esafak 1y agoIt's obviously not a replacement. You can get the types right but the values wrong due to faulty logic.
- MrJohz 1y agoSure, but only some of the unit tests are about values. Others, at least in my experience, are any handing various aspects of the implied types of values, and those can largely be removed. Moreover, a good type system can also force the values to be right by enforcing certain invariants directly in the type system. For example, let's say I have a function `deleteProjectAs(user, project)` that deletes a project, but it only works if the user is an admin, otherwise it throws an error. I can write a bunch of tests that validate that this function checks that the user is an admin in all sorts of different cases, but with a type system I can write something like `deleteProjectAsUser(user: Admin, project: Project)`, and this guarantees at the type level that no non-Admin user can delete a project. The point here is not that types can replace all tests, but that well-designed types can get rid of a lot of them.
- je42 1y agoWhen using dynamic languages, either minimize code dependencies / function calls and complexity or ensure high test coverage.
- bormaj 1y agoIf using python with type annotations, linters like ruff and mypy do a great job at identifying issues. It's no substitute for tests and nor will it give you the same guarantees that rust will at compile time. But I think it improves the base quality of the code.
- mabster 1y agoThe thing I find annoying with MyPt is trying to tell it I'm doing variable shadowing. E.g. X is a list of strings Translate X to a list of indices Translate X back to a list of strings. In that paragraph the input and output types are the same, but not complains about the second line. I always have to introduce a variable with a new name.
- bormaj 1y agoYeah I see what you mean, you can always disable specific features, but I think that's a habit mypy tries to enforce. They consider redefining a variable bad practice. Even in rust you have to be explicit about doing the same thing with an extra "let" statement.
- mabster 1y agoYeah that's fair enough, and I've lived with it because of how good MyPy is. But I always end with weird variable names like uuids_as_list as a result!
- d0mine 1y agoDo you believe that Rust's type system is as flexible, powerful, and easy to maintain as unit tests in Python?
- MrJohz 1y agoOne of the big advantages of Rust's type system is that, if you decide you want to change something (add a parameter, give a type a lifetime, rewrite an entire module), you can just do that, and then follow the errors until they're all gone. Often, once the types have been fixed again, the result will work first time when you try and run it. In this regard, Rust (and other languages where lots of data invariants can be encoded in the type system) is very flexible and easy to maintain indeed, because you can easily make changes, even in very old or poorly-maintained code, without having to worry about the consequences. Moreover, rather than writing all the unit tests yourself, it's as if the compiler is writing the unit tests for you. In fairness, you can't encode everything in the type system, so you still need unit tests in top of that, but in my experience you can get away with far fewer. In general, I would say that Rust's type system, when combined with unit tests, is far more flexible, powerful, and easy to maintain than dynamic Python with only unit tests.
- airstrike 1y agoNo, it's more flexible, more powerful, and easier to maintain than unit tests in Python.
- 12_throw_away 1y agoI write and test a lot of both rust and python, so I can say quite confidently: 1. Of course a type system is not as "flexible" as arbitrary test code. 2. Compiler-enforced type safety is many orders of magnitude easier to maintain than the equivalent unit tests 3. Defining rigorously enforced invariants with a type system is far, far more powerful than hoping you remembered to test all the important cases.
- d0mine 1y agoYour 2-3 points remind me of the quote by Ludwig Wittgenstein: “The limits of my language means the limits of my world.” Of course if you limit yourself only to problems that can be effectively solved by type system, then it may work. It is like limiting yourself only to those text processing tasks where regexs work. Yes, some text processing tasks may be much more effectively solved using a regex. But it is obvious that at some point in a more general case grep can’t replace python. It may be less apparent for compiler vs. python case but the general logic is the same.