Proposal: consider a numeric value "in range" when it's inside the range space

163 views
Skip to first unread message

charlott...@gmail.com

unread,
Feb 8, 2017, 10:48:28 AM2/8/17
to elixir-lang-core
Right now when you write something like
x in -1..1
elixir compiles it to
is_integer(x) and x >= -1 and x <= 1

If we were to write
x in Enum.to_list(-1..1)
It would have the exact same effect (as x would have to be an int that is bigger than or equal to -1 and lesser than or equal to 1 to pass) which makes sense when we look at Ranges as being just a lazily-evaluated enumerable (like a Stream).

But i think that we should consider a range (atleast in the context of an "in" operation) equal to a space. Right now if we were to check if a float is inside a range, it would always fail (which, again, makes sense if we see the Range as a lazy enum).

What i propose is that elixir accepts floats when executing "in" for a range. I believe it semantically makes sense (as in "0.5 is a number in the -1..1 range ?" instead of "0.5 is inside the list of integer produced by the -1..1 range/sequence")

So, tl;dr, changing Kernel's macro in_range_literal/3 to
(is_integer(x) or is_float(x)) and increasing_compare(a, b, c)

That way we can easily check things like
def valid_probability?(val), do: val in 0..1
def contains_enough_products(amount), do: is_integer(amount) and amount in 1..10

Note that in the above example i shown that you explicitly checks if the value is integer when you want it to be, which i believe is not a bad side-effect to this proposal (and i think that it is not obvious that this is the default behaviour, specially because the documentation doesn't states that ranges won't succeed with floats)

José Valim

unread,
Feb 8, 2017, 11:09:45 AM2/8/17
to elixir-l...@googlegroups.com
Ranges originally worked as you proposed but we changed it to the restrict form we have today exactly because of the confusion that arose from the fact ranges with floats cannot be enumerated as in Enum.to_list/2. This meant that:

    Enum.member?(1.5, 1..2) #=> true

but

    Enum.to_list(1..2) #=> [1, 2]

and it also meant that:

    Enum.member?(1.5, 1.0..2.0) #=> true
    Enum.to_list(1.0..2.0) #=> raises

Those inconsistencies are not worth the small benefits.

José Valim
Skype: jv.ptec
Founder and Director of R&D

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/4a5be52c-59eb-43e5-bc40-abcf5034a59f%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

charlott...@gmail.com

unread,
Feb 8, 2017, 11:17:18 AM2/8/17
to elixir-lang-core, jose....@plataformatec.com.br
This is sad but okay, it's better to ensure consistency, otherwise some bug reports could arise of people enumerating a range and reusing it with different output :/
 
Should i PR to add a comment to the "in" to state that it will only succeed with ranges if the value is an integer ?

To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.

José Valim

unread,
Feb 8, 2017, 11:21:25 AM2/8/17
to elixir-l...@googlegroups.com
Yes, definitely. PRs are welcome!



José Valim
Skype: jv.ptec
Founder and Director of R&D

To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/f3c0619d-45e5-4746-a6cb-f75841824e1f%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages