dwark

dwark

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:

  1. The first IO.inspect with label: :before is commented out. Then the following two
    lines (6 and 7) are not longer at odds with each other type-wise.

  2. 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]]}
  1. OR: Use a struct instead of a dynamic map.

  2. OR: change the first IO.inspect to inspect map[:words] instead of map.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?

Showing Posts 1 to 3

sabiwara

sabiwara

Elixir Core Team

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

dwark

dwark OP

Ok, thanks.

dwark

dwark OP

For future readers: this was already fixed in 1.16 (I was on 1.15.7).

— All posts loaded —

Where Next? Top

Trending in Questions Top

katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
achenet
Hello, I’m trying to build a basic Phoenix web-app, and I’d like to use Tailwind. However, when I launch mix phx.server, I get an error...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
Cxx-mlr
I’m working on a small exercise involving update_in/3, and I came up with this solution: data = %{ name: "Periodic Table", category:...
New
ChrisAmelia
I’ve got trouble wrapping my head around the order in which functions are called in this snippet (from Phoenix’s authentication): toke...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews