3 ms·
> You shouldn't write test to validate types in the fist place. Testing for the correct behavior should be enough. Yeah but with dynamic typing there's a whole
by mjr00 4y ago
> You shouldn't write test to validate types in the fist place. Testing for the correct behavior should be enough.
Yeah but with dynamic typing there's a whole bunch of behaviors you need to think about. You pass an int into a method that expects a string, what's the expected behavior? Or maybe something more nefarious, like a method that expects a Python dictionary but is passed in a pandas Dataframe, which has similar syntax with totally different meaning; what's the expected behavior?
Much easier to just specify what types you're expecting to work with and let a compiler or type checker deal with it.
- skydhash 4y agoThe two examples are human errors easily avoidable by reading the documentation. And some mechanism that uses types like method overload should be transparent from a behavior perspective.
- mjr00 4y ago> The two examples are human errors easily avoidable by reading the documentation. Okay, but that doesn't answer the question. We're in dynamic typing world; my method accepts any data type by design. What's the expected behavior when it doesn't receive the expected type? Do I add assertions and fail with an assertion error? Let the runtime fail for me? Silently convert the type? In any case, I need to add a test for that. If your answer is "humans shouldn't make a mistake when calling the method," that's arguing for static typing, not against, because that's exactly what static typing prevents: a human making a mistake. Turns out static typing makes for a really good baseline level of documentation, as well. > And some mechanism that uses types like method overload should be transparent from a behavior perspective. Your method might work today for both a dict and a dataframe because it's only using simple accessors. But what if someone wants to go back and change it and they use something that's only on dictionaries, like the * operator? Your code would fine, your unit test cases probably all use dictionaries so they're fine, and it's only when you deploy to production and find out that someone's code elsewhere was incorrectly passing in a Dataframe that just happened to work, no longer does. Static typing has a solution for behavior-based types too, they're called interfaces. Even better in languages like Go and Python (with Protocols) that use structural type checking for interfaces, rather than explicit interface implementations.
- skydhash 4y ago> In any case, I need to add a test for that. You don’t test types. If you have a ‘trim’ method that accepts a string, you don’t unit test it with an array, unless you plan to add a test for every possible types. Static typing can help prevent a human calling it with the wrong type, but won’t prevent calling it with the wrong runtime values, like after casting an Any to string. Static typing do syntax check, not runtime check. When I’m talking about testing behavior, it’s about testing that the code does what it’s supposed to. Not what the arguments is. So you test that ‘trim’ works on all strings, including empty. What static typing helps in checking assumptions when programming, but every bet is off when executing. Especially when interacting with the outside world. If someone changes the code, it’s on them to notify everyone about breaking changes. If the documentation says that the method accept dict, and you call it with dataframes, it’s on you to check that it will continue to work with dataframes, not on me to ensure that someone is calling it with dataframes if I use specific code related to dict.
- mjr00 4y ago> If someone changes the code, it’s on them to notify everyone about breaking changes. If the documentation says that the method accept dict, and you call it with dataframes, it’s on you to check that it will continue to work with dataframes, not on me to ensure that someone is calling it with dataframes if I use specific code related to dict. This is equivalent to re-implementing static types and a compiler with human processes. This isn't scalable.
- skydhash 4y agoMaybe, but using static types is not a panacea either. It only make it easier to assume that someone have correctly constructed the value and that all manipulation have been correct so far. The type checker helps by checking that if the assumption is true, everything down the line is also true. But only in the context of the code, not in the context of the process itself, where the assumption may be incorrect, or the chain is broken somewhere due to bad logic (that’s when off-by-one errors arise). Nothing is a silver bullet. Static types can make life easier by preventing some meaningless code, but they don’t ensure correct programs.
- goto11 4y ago> You pass an int into a method that expects a string, what's the expected behavior? Probably an exception, depending on the language. E.g. if the method expects the argument to support the method "substring()" it would be expected to throw an exception if the passed object does not have such a method. If you pass an object which support the expected interface but with a completely different semantics, then you probably get a weird unexpected behavior. But that would also be the case in a statically typed language.
- darthrupert 4y agoThe flip side of all that is that a lot of times those other data types that have the same interface will just work without needing to go through generic hoops. Of course, if your software is the kind that cannot tolerate errors, that's not good enough. Most software isn't like that, and the flexibility is often more useful than extreme safety.