tjchambers
I am using 1.20.0-rc4 and discovered a bug I introduced today. Wanted to share mostly because I want to understand the extent of how set theoretic typing will or will not address this kind of bug. The code snippet:
result = Cachex.incr(:cache, :key, 1, default: 0)
if result > 5 do
…
end
What I forgot in my haste was that the return from that Cachex function is a tuple, {:ok, integer()} not integer(). And I got no warning. Had I done something similar in a guard expression comparing a tuple to an integer IMHO would not have indicated any warning under set theoretic typing.
So a function signature like:
def x(y) when y >= 5, do: nil
where y is a type of tuple should NOT generate a type warning. It should not only because of the Elixir type heirarchy.
It seems this is a very possible common bug when dealing with libraries where Bang methods tend to return some Elixir type and non-bang functions tend to return a tuple with the second element being some Elixir type and the first element being an atom such as :ok, or :error.
I am interest in others thinking, and mostly to help me understand what can or cannot be done to help locate these errors. If all of our libraries we use day in and day out had set theoretic typing contribution to our app compilations, this seems to be something of value.
Anyway - please comment and help me reason about this.
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #blog-post
- #ai
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
cmo
It’s a gotcha for sure. I always add an
is_integer(x)to guards that do less/greater than checks.def x(y) when is_integer(y) and y >= 5, do: nilNobbZ
I’d not expect a typewarning here, but rather a “is always true/false” kind of warning, if indeed
yis always a tuple.tjchambers
Here is I believe a test case:
and results are
iex [03:36 :: 1] > TestTuple.format_tuple({1,2})
“This is the tuple: {1, 2}”
No compile error or warnings.
So I would say this scenario is undetected by current set theoretic typing compilation.
cmo
I believe you need to do something to indicate the type for the compiler to catch it. e.g.
Atom.to_string(x)tells the compiler thatxis an atom.You’re telling it there is a tuple.
>=is not an integer only operator so it’s not going to complain about that. Maybe if you put anis_integerguard with it it might tell you that clause is unused. Dunno if that is or will be implemented.manhvu
Type specs and set-theoretic types don’t raise a warning here because any types can be compared (this comes from Erlang—I’m not sure about the reasoning behind that
). Sometimes type checks are missed before comparing data, which leads to logic errors.
LostKobrakai
Once you remove the function indirection there is a warning though - because the tuple will always result in the same comparison result. The issue seems to be with the type knowledge propagating through the callstack.
matt-savvy
That’s because
tuple >= 5is not only valid, but returnstrue.Elixir allows comparisons between elements of different types.
See Kernel — Elixir v1.21.0-dev
TLDR; any tuple is considered to be greater than any integer.
matt-savvy
In this case, you compared a tuple like
{:ok, 1} > 5, which will always returntrue.Also, every atom is considered greater than every number, so if you were using a function that returned
{:ok, integer() | :error}, either way,result > 5is always going to returntrue.This is one place where I hope eventually we’ll be able to use types, to show a warning that this expression is always going to return
true.tjchambers
Exactly my point @matt-savvy . Because there is an Elixir type heirarcy in play, it seems as though we lose some ability to detect what I consider to be a bug, because precisely it is a valid comparison.
tjchambers
I don’t feel like I was making myself clear here. I would hope eventually in this situation that given the subsequent function, that it would announce that subsequent function would never be reached. Even as confusing at first as that may seem.
Ideally (in my selfishness) I would like it to tell me more precisely that I was comparing disparate types, but the language type hierarchy already permits that comparison. If somehow that type hierarchy could be indicated to not be in play (comparing for example atoms to tuples to lists with greater than or less than) it would increase the value of type checking.
I do realize if I indicated the expected type of the parameters with a guard then I would be encouraging the type checking accuracy. However one of the purposes afaict of the lovely approach to gradual theoretic typing is NOT relying on code changes or type hinting. So far it seems this propagation of type knowledge has been IMHO highly (remarkably?) successful.