Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basics.clamp doesn't passthrough NaN #1080

Open
malaire opened this issue Apr 13, 2020 · 2 comments
Open

Basics.clamp doesn't passthrough NaN #1080

malaire opened this issue Apr 13, 2020 · 2 comments

Comments

@malaire
Copy link

malaire commented Apr 13, 2020

If clamp is given NaN as third argument it should return it unchanged, but instead it returns the given upper limit:

elm repl
> clamp -100 100 (0/0)
100 : Float

I don't understand why this happens. clamp is defined as (source)

clamp : number -> number -> number -> number
clamp low high number =
  if lt number low then
    low
  else if gt number high then
    high
  else
    number

Since both comparisons should be False, number should be returned unchanged, but that doesn't happen.

I can't test gt myself, but its corresponding > does return False as expected:

elm repl
>  (0/0) > 100
False : Bool

Maybe related to #1050

@github-actions
Copy link

Thanks for reporting this! To set expectations:

  • Issues are reviewed in batches, so it can take some time to get a response.
  • Ask questions a community forum. You will get an answer quicker that way!
  • If you experience something similar, open a new issue. We like duplicates.

Finally, please be patient with the core team. They are trying their best with limited resources.

@rlefevre
Copy link
Member

rlefevre commented Apr 13, 2020

Basics.clamp is compiled to:

var $elm$core$Basics$clamp = F3(
    function (low, high, number) {
        return (_Utils_cmp(number, low) < 0) ? low : ((_Utils_cmp(number, high) > 0) ? high : number);
    });

and because _Utils_cmp does:

function _Utils_cmp(x, y, ord)
{
    if (typeof x !== 'object')
    {
        return x === y ? /*EQ*/ 0 : x < y ? /*LT*/ -1 : /*GT*/ 1;
    }

with both x === y and x < y returning false with NaN, it will return GT, therefore the clamp higher value will be returned:

> Basics.compare (0/0) 100
GT : Order

(>) (0/0) 100 returns False because it is optimized by the compiler to (0 / 0) > 100 in javascript without using _Utils_cmp.

If you trick the compiler to avoid the optimization, you get True for NaN > 100:

> (>) (0/0) 100
False : Bool

> gt = (>)
<function> : comparable -> comparable -> Bool

> gt (0/0) 100
True : Bool

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants