4 ms·
I think it is pretty easy to illustrate why fewer tests are needed in certain statically-typed languages. JS function max(a, b) { if (a < b) {
by mgraczyk 7y ago
I think it is pretty easy to illustrate why fewer tests are needed in certain statically-typed languages.
JS
function max(a, b) {
if (a < b) {
return b;
}
return a;
}
console.log(max(1, 2));
// 2
console.log(max(2, 1));
// 2
console.log(max([1,2,3]));
// [1,2,3]
Rust
fn max<T: PartialOrd>(a: T, b: T) -> T {
if a < b {
b
} else {
a
}
}
println!("{}", max(1, 2));
// 2
println!("{}", max(2, 1));
// 2
println!("{}", max([1, 2, 3]));
// Compiler error
In JS, it would be prudent to test for reasonable misuse of this kind (return undefined, throw Error, etc). The author claims _This is a dynamically typed language. You get exceptions when you mess up the types._ That isn't true in this case and it is not clear from the code what would/should happen.
In rust, you don't need any tests like this.
- z3t4 7y agoA common philosophy in JavaScript is to make it just work. For example if an array is passed, sort it and return the max value, which was probably what the programmer intended.
- SideburnsOfDoom 7y agoWhich would need even more tests, because now there a set of types that will work (e.g. numbers, arrays of numbers), with code to make them work and tests on that; and other types do not work, and tests on that.
- z3t4 7y agoYes, you write a new test for each new feature. But if you do the same thing in a statically typed language, once you've allowed arrays, and what not, how do you know if the function still works, besides carefully studying it.
- mgraczyk 7y agoThe point is that you need more tests. In statically typed languages, you typically don't make it "just work" and hence need fewer tests.
- AnimalMuppet 7y agoWell, you don't make it "just work" for all conceivable input shapes. You make it work for the one and only accepted input shape, which is 1) much easier to make work, 2) means that you don't miss possible input shapes, and 3) is much easier to test thoroughly.
- almostdeadguy 7y agoThe max value of what? The array in one of the arguments? What if there are two arrays? Or an array and a number? Or a multi-dimensional array of numbers and any of the above? I think this attempt to come up w/ reasonable interpretations for unanticipated usages of a function is kind of a rabbit hole. Beyond that I think it's also problematic to assume that all usages of a function in a language without a type system are intended usages, i.e. that programmers _mean_ to pass arrays whenever an array appears as one of the arguments.
- z3t4 7y agoSometimes you want to call a function with something else, or are not using an IDE (no argument hinting), and just call the function intuitively. Instead of converting the input, or writing a middle-man, you edit the function to accept it as is. You don't even have to pass values in the right order, the function will figure it out.
- almostdeadguy 7y agoThere's nothing wrong w/ polymorphic functions, but there has to be a reasonable rule to apply for what kinds of shapes of data are permitted. Trying to aggressively handle unforeseen cases instead of indicating an error doesn't actually help anyone, it's akin to swallowing exceptions. It's why falsey values and automatic type conversion are some of the most problematic features in javascript. Your example of how to handle max for array arguments is exactly the kind of thing I would discourage in js code, because it overloads the meaning of "maximum" to data that don't have a natural way of assigning an ordering if heterogeneous arguments are permitted (actually it sounds like you're saying something like max([1], [9]) should return "9", which doesn't correspond to an intuitive understanding of "maximum" at all given it returns something that isn't either of the passed arguments). Whereas the rust code can use the "PartialOrd" trait to ensure we only try to produce a maximum of like elements with a defined ordering relation. That's fine for a limited number of cases where its easy to show type equivalence in js, but I think it's problematic as a general design principle, and because you don't have ways to express the limits of polymorphism I've seen this kind of thing proliferate to unsafe uses of a function very quickly.