https://stackoverflow.com/questions/21019902/why-cant-javasc...
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
[min, num, max].sort((a, b) => Math.sign(a - b))[1]
An entirely different alternative is poor man's match: switch (true) {
case num > max: return max;
case num < min: return min;
default: return num;
} .sort((a, b) => a - b)Only by defining a `const subtract = (a, b) => a - b;`, which isn't really point-free.
Or by using a different language.
[ROT 13] spoiler: cnefrVag frpbaq nethzrag vf onfr, znc frpbaq nethzrag vf vaqrk va neenl. 10 vf gur frpbaq nethzrag, vaqrk 1. cnefrVag(10, 1) unf vyyrtny onfr
I really love this! I’m not sure whether to laugh, cry, or applaud, but I love how it makes me feel all those emotions at the same time.
[10, 2, 100].sort()[1] //returns 100 function clamp(n, min, max) {
return [min, n, max].sort((a, b) => a - b)[1];
}
for (var i = 0; i < 10000000; i++) {
clamp(Math.random() | 0, Math.random() | 0, Math.random() | 0);
}
However, I was pretty disappointed when it seemed to be calling sort each time :( Perhaps I profiled it incorrectly? jsc's profiling data shows that it never hit FTL and nothing ever got inlined. The bytecode for DFG and Baseline is identical: Compilation clamp#CChm91-1-Baseline:
arg0: predicting OtherObj
arg1: predicting BoolInt32
arg2: predicting BoolInt32
arg3: predicting BoolInt32
[ 0] enter
[ 1] get_scope loc4
[ 3] mov loc5, loc4
[ 6] check_traps
[ 7] mov loc11, arg2
[ 10] mov loc12, arg1
[ 13] mov loc13, arg3
[ 16] new_array loc10, loc11, 3, 3
[ 22] get_by_id loc7, loc10, 0
[ 27] new_func_exp loc9, loc4, 0
[ 31] call loc7, loc7, 2, 16
[ 37] get_by_val loc6, loc7, Int32: 1(const0)
[ 42] ret loc6
Compilation clamp#CChm91-2-DFG:
arg0: predicting OtherObj
arg1: predicting BoolInt32
arg2: predicting BoolInt32
arg3: predicting BoolInt32
[ 0] enter
[ 1] get_scope loc4
[ 3] mov loc5, loc4
[ 6] check_traps
[ 7] mov loc11, arg2
[ 10] mov loc12, arg1
[ 13] mov loc13, arg3
[ 16] new_array loc10, loc11, 3, 3
[ 22] get_by_id loc7, loc10, 0
[ 27] new_func_exp loc9, loc4, 0
[ 31] call loc7, loc7, 2, 16
[ 37] get_by_val loc6, loc7, Int32: 1(const0)
[ 42] ret loc6(Shots fired)
The array implementation sidesteps this by not semantically defining a max and min, instead sorting three arbitrary numbers.
If that is the version of clamp you need, the sort based solution reveals something profound and unexpected: it’s not just the two end points of the range that are equivalent, but all three numbers. Keeping value A between B and C is the same as keeping B between A and C or C between A and B. It’s completely arbitrary which pair you consider to be a range.
If I wanted it to automatically flip the values to ensure a sensible range is defined, I would probably use "a" and "b" or "endpoint1" and "endpoint2" or something, because "max" has now become "max or min," which is not the same.
I still found your approach interesting and it's rare there's a perfect approach so don't take it to heart.