3 ms·
Did you take note of the context in which this conversation is taking place? Because it doesn't make sense as a response within that context.
by cxr 3y ago
Did you take note of the context in which this conversation is taking place? Because it doesn't make sense as a response within that context.
- mrkeen 3y ago(My top-level reaction to TFA, for background. I left it out because no-one asked.) > Writing code for both computers and humans Show me what you got. > isNaN(defaultValue) ? NaN : defaultValue Yuck. > This made me pause for a moment. Of course it did. I still pause every time I re-read it! > This ternary is much better. This is expert-level programming. This is how to write code with empathy for other programmers. No, it makes me pause every time I read it, and I cannot follow the path from "made me pause" to "expert-level programming". Back to your comment: >> dynamically typed so[...] > It's not about dynamic typing in this case. It is about dynamic typing. isNaN should not exist (except for specific cases such as machine floats where NaN means something concrete). > If you saw that, your spidey-sense might start tingling, “This is a number—did they consider the NaN case?” I want tingle-free programming. Let the compiler do the tingling for me. A Number-which-may-or-may-not-be-a-Number is not statically typed. I don't care if it's in a .ts file. There are 15 more references to NaN in that module and they do not make for easy reading: // Clamp to min and max, round to the nearest step, and round to specified number of digits let clampedValue: number; if (isNaN(step)) { clampedValue = clamp(parsed.current, minValue, maxValue); } else { clampedValue = snapValueToStep(parsed.current, minValue, maxValue, step); } Why doesn't the above code match its comment? Why doesn't it look something like: // Clamp to min and max, round to the nearest step, and round to specified number of digits let output = input |> roundNearest(step) |> clamp(min, max) |> roundToDigits(numDigits) Their code either calls into clamp() or snapValueToStep() based on whether 'step' is a number. Does that imply 'step' needs to be a number for the snapValueToStep case? If so, 'step' will need to be checked again inside that method. Why didn't they accept a typed number as input? Or - if they were forced to accept a string - check it at the top of the method? Oh wait - they did! Twice in two lines! let clampStep = !isNaN(step) ? step : 1; if (intlOptions.style === 'percent' && isNaN(step)) { clampStep = 0.01; } So now 'step' and 'clampStep' are both in scope. They may or may not be numbers (insofar as the coder is willing to keep scrolling back up and re-reading code that at first "makes them pause", but then later makes them feel like it's "expert code".) Why not: const clampStep = case parseNum strStep of Just step -> step Nothing | intlOptions.style == Percent -> 0.01 | otherwise -> 1 * One definition site, so you can read all possible values from the leaves {step, 0.01, 1} * The possibly-a-String step has been demoted to 'strStep :: String', so that 300 lines later, the coder cannot not accidentally pass 'step' to another function (and if he did, the compiler would stop it immediately). * clampStep is actually a number, so no more NaN checks. But hey, that's all par for the course: Java programmers don't think they hit NPEs, C++ programmers don't think they have ("modern") memory issues, and dynamic programmers don't think they have type problems. What really prompted me to comment was your suggestion that it would have been better to skip the confusing checks, keep passing through an untyped object, and let some downstream expression blow up.
- cxr 3y agoHalf of what you wrote here has nothing to do with the context of this discussion (again), and the half that's at least superficially relevant is materially irrelevant as a consequence of being a strawman. > Java programmers don't think they hit NPEs, C++ programmers don't think they have ("modern") memory issues, and dynamic programmers don't think they have type problems Aside from the obvious category error, you aren't talking to a "dynamic programmer" who "[doesn't] think they have type problems". (It may also shock you to learn that I'm not an advocate of NodeJS/NPM, the programming style exemplified by the Adobe project identified in the blog post, or even TypeScript. That doesn't change the fact that I'm right about the things I said before—and the fact that I am right means it wouldn't matter even if I were a "dynamic programmer", anyway.) The _entire_ point of what I wrote is laid out in my first paragraph: "People accustomed to strongly typed languages and thinking mostly of monolithic apps always pin things on dynamic typing even where it's not the cause." I even made it more explicit. This problem is not because of dynamic typing. This is a problem because of code mobility and separate compilation. I even provided references, FFS. You'd get the _same_ problem in languages that are not JS or TypeScript—including static languages. Why? Because this is a problem arising from code mobility and separate compilation—not static versus dynamic typing. > What really prompted me to comment was your suggestion that it would have been better to skip the confusing checks Not what I said, Holmes. The strength of your powers of divination don't merit the confidence you seem to have in them. This is where I exit.
- mrkeen 3y agoI don't know how you can think I'm arguing some mysterious, unrelated tangent. -------------- >>>> {If `useControlledState` were just vanilla JS and no one were doing typechecking during development and build [1]}, there would have been {no problem with passing something else as an argument [2]}, because it will of course {evaluate to NaN anyway [3]} when undergoing the number treatment. >>> The point of typing is to make sure this situation [3] doesn't happen. >> Did you take note of the context in which this conversation is taking place? Because it doesn't make sense as a response within that context. > What really prompted me to comment was your suggestion that it would have been better to {skip the confusing checks [1]}, {keep passing through an untyped object [2]}, and {let some downstream expression blow up [3]}. -------------- >>> It's not about dynamic typing in this case. >> It is about dynamic typing I feel like you are so selectively blind to { isNaN(defaultValue) ? NaN : defaultValue; } being a wart of dynamic typing (not to mention TFA who had to slow down to understand it) that I couldn't do anything but submit other examples of selective blindness to see if they struck home: >> Java programmers don't think they hit NPEs, C++ programmers don't think they have ("modern") memory issues, and dynamic programmers don't think they have type problems. Why is it that you can write "People accustomed to strongly typed languages and thinking mostly of monolithic apps" but you bristle when I write "dynamic programmers"? > The _entire_ point of what I wrote is laid out in my first paragraph: "People accustomed to strongly typed languages and thinking mostly of monolithic apps always pin things on dynamic typing even where it's not the cause." I even made it more explicit. This problem is not because of dynamic typing. It's crystal clear and I'm contradicting you, not missing your point.