|
|
|
|
|
by dkarl
1229 days ago
|
|
This makes it easier for errors to go unnoticed in large codebases. If the function expects to take a list, and someone passes a tuple, it's likely that they passed the wrong value by accident. For beginners, and in toy examples, it's kind of neat when code bends over backwards to work. Take this example: >>> def all_uppercase(lst):
... return [s.upper() for s in lst]
...
>>> all_uppercase('hi')
['H', 'I']
>>>
Kind of neat, right? It's almost like a joke in code. Ha ha, iterating over a string gives you strings! But the charm of finding cute things to do with unexpected inputs doesn't scale. What is a helpful attitude at a small scale translates to "errors should manifest as far away as possible from the programming mistake that caused them" at a large scale. 99 times out of 100, if your code expects a list and somebody passes a tuple, they want a stack trace, not a return value.> I have worked on making python libraries and there accepting a wide range of inputs is an important part of usability I work with a large Python codebase at work, and this is a frequent source of frustration. I frequently track down bugs and find that on some untested code path our code passes nonsensical values of the wrong type to a third-party library, and the library just... finds some way of interpreting it. Even if all the code paths get tested, they can't be tested with every possible input. Property-based testing seems like overkill for our application, and our tests are already almost slow enough to be annoying. And what if the third-party library is side-effecting in a way that's hard to test? It gets mocked out. And I find that the mocks are configured to expect the nonsensical values, because the original programmer found that they "work." All because libraries don't want to make an unfriendly impression by throwing a stack trace. |
|