19 ms·
This is what undefined behavior is for. You specify a contract for your function, and then the implementation of the function assumes that the contract is satis
by MathMonkeyMan 1y ago
This is what undefined behavior is for. You specify a contract for your function, and then the implementation of the function assumes that the contract is satisfied. It does not check, and does not try to diagnose errors.
It's not about performance, it's about separating concerns: the caller handles the not-a-number case, so the callee doesn't have to.
Then you add optional runtime checking of the contract, preferably in a different build mode (or a different version, e.g. "my-lib1.2-debug"), to get sensible diagnostics quickly in tests and canary deployments. The checks are redundant by definition. Defensive programming.
- sesm 1y agoAlso known as "garbage in - garbage out" approach. That's how Clojure standard library is designed.
- pwdisswordfishz 1y agoAnd C/C++.
- chowells 1y agoNow, consider that that the program might be rejected for being incorrect, without being run. Wouldn't that be even better?
- MathMonkeyMan 1y agoAll other things being equal, yes. Static types work well for constraints on function parameters. "Parse, don't validate" and all that. Some contracts are more difficult to express, though. The worst kind involve sequences of behavior, e.g. "start() must have been called," or "must have been obtained from a previous call to 'allocate()' on the same object." Even value parameter constraints can be tricky. "The input must be sorted." I haven't studied type systems, but I like the idea of values picking up attributes as they pass through functions. Imagine a "sort" function that bestows its output with the "sorted" type attribute. But then what happens when you append to that value? Is it still sorted? At some point it's convenient to be permissive with the parameter's static type and to constrain the caller with a contract.