dwark
Trouble understanding a warning: incompatible types
The following code results in a warning that is difficult for me to understand:
defmodule Mod do
def hello(name) do
map = Map.new(words: ["world"])
IO.inspect(length(map.words), label: :before)
map = %{map | words: [name | map.words]}
IO.inspect(length(map.words), label: :after)
end
end
This yields the following warning:
warning: incompatible types:
%{words: [var1 | var2]} !~ %{words: var2}
in expression:
# lib/mod.ex:7
map.words
where "map" was given the type %{words: [var1 | var2], words: var2, optional(dynamic()) => dynamic()} in:
# lib/mod.ex:6
map = %{map | words: [name | map.words]}
where "map" was given the type %{words: [var1 | var2], optional(dynamic()) => dynamic()} (due to calling var.field) in:
# lib/mod.ex:7
map.words
HINT: "var.field" (without parentheses) implies "var" is a map() while "var.fun()" (with parentheses) implies "var" is an atom()
Conflict found at
lib/mod.ex:7
The warning goes away if:
-
The first IO.inspect with
label: :beforeis commented out. Then the following two
lines (6 and 7) are not longer at odds with each othertype-wise. -
OR: Leave the IO.inspect as-is, but change the line following it (the map update) to
one of the following:
map = %{map | words: [name] ++ map.words}
# or
map = %{map | words: [name | map[:words]]}
-
OR: Use a struct instead of a dynamic map.
-
OR: change the first IO.inspect to inspect
map[:words]instead ofmap.words
So the warning is about conflicting types for %{words: [var1 | var2]} !~ %{words: var2}
- line 6 →
%{words: [var1 | var2], words: var2, optional(dynamic()) => dynamic()} - line 7 →
%{words: [var1 | var2], optional(dynamic()) => dynamic()}
both mention optional(dynamic()) => dynamic(), the first seemingly only for var2 in the prepending of the list, the latter for the list itself?
In both cases, map is a (dynamic) map, the atom key :words’s value is a list so I expected
both to be of the same type, since [var1 | var2] is prepending var1 to the list var2,
much like the [var1] ++ var2 variant. This is what confuses me.
It all seems related to using the dot-notation to access an atom key in a dynamic map.
The docs say:
To access atom keys, one may also use the map.key notation. Note that map.key will raise a KeyError if the map doesn’t contain the key :key , compared to map[:key] , that would return nil .
as well as:
The two syntaxes for accessing keys reveal the dual nature of maps. The map[key] syntax is used for dynamically created maps that may have any key, of any type. map.key is used with maps that hold a predetermined set of atoms keys, which are expected to always be present. Structs, defined via defstruct/1, are one example of such “static maps”, where the keys can also be checked during compile time.
So should I read the above to always use map[key] for dynamic maps even if the key is an atom, and map.key only for static maps like a struct?
Most Liked
sabiwara
The code seems fine, I think this one is a bug in the compiler.
Opened an issue: Incorrect incompatible type warning on map dot access · Issue #13335 · elixir-lang/elixir · GitHub
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex









