Also note that there's is_map_key/2 guard that serves the same purpose when used as `is_map_key(arg, :__struct__)`, allowing only maps but not structures: https://hexdocs.pm/elixir/1.14.2/Kernel.html#is_map_key/2
On Thursday, 22 December 2022 at 4:22:30 pm UTC+1 halos...@gmail.com wrote: > I think that this is an interesting idea, but as Enumerable is a protocol, > it is possible to implement enumerability for any given struct, as `MapSet` > is enumerable. > > This SO answer > <https://stackoverflow.com/questions/39609255/how-can-i-check-whether-the-protocol-is-implemented#39609295> > suggests > using the Protocol.impl_for/1 callback instead. It can’t be used as a > guard, but it gives a more accurate answer. > > Whether `is_real_map/1` (or a different name) is more readable than `when > is_map(term) and not is_struct(term)`, I can’t say because if I need to > handle structs differently, I would generally use two different function > heads (`def foo(term) when is_struct(term) do term |> Map.from_struct() |> > foo() end` and `def foo(term) when is_map(term) do … end`). > > -a > > On Thu, Dec 22, 2022 at 1:25 AM vtm <vtmil...@gmail.com> wrote: > >> hey all, thanks for you work on such a beautiful lang. >> >> Small proposal. People sometimes get confused about data structures which >> based on maps. >> for instance: >> ``` >> iex(3)> {:ok, datetime} = DateTime.now("Etc/UTC") >> {:ok, ~U[2022-12-22 05:53:36.228720Z]} >> iex(5)> is_struct(datetime) >> true >> iex(6)> is_map(datetime) >> true >> ``` >> but here i got an error >> ```elixir >> iex(11)> Enum.each(datetime, &Function.identity/1) >> ** (Protocol.UndefinedError) protocol Enumerable not implemented for >> ~U[2022-12-22 05:53:36.228720Z] of type DateTime (a struct) >> ``` >> >> i have in a codebase in function definition something like >> `where is_map(map_name) and not is_struct(map_name)` >> what i suggest to do is to create a macro `is_real_map` to check only >> real maps as a key-value storage with Enumerable impl >> ```elixir >> @doc """ >> Returns true if `term` is a map and not is struct; otherwise returns >> `false`. >> >> Allowed in guard tests. >> >> ## Examples >> >> iex> is_real_map(%{oi: :blz}) >> true >> >> iex> is_real_map(URI.parse("/")) >> false >> >> """ >> @doc since: "1.16.0", guard: true >> defmacro is_real_map(term) do >> case __CALLER__.context do >> nil -> >> quote do >> case unquote(term) do >> %_{} -> false >> %{} -> true >> _ -> false >> end >> end >> >> :match -> >> invalid_match!(:is_real_map) >> >> :guard -> >> quote do >> is_map(unquote(term)) and not :erlang.is_map_key(:__struct__, >> unquote(term)) >> end >> end >> end >> ``` >> >> >> >> >> -- >> 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-co...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/elixir-lang-core/1f26dae3-9c67-446b-91d0-51bf1c5f3666n%40googlegroups.com >> >> <https://groups.google.com/d/msgid/elixir-lang-core/1f26dae3-9c67-446b-91d0-51bf1c5f3666n%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> > > > -- > Austin Ziegler • halos...@gmail.com • aus...@halostatue.ca > http://www.halostatue.ca/ • http://twitter.com/halostatue > -- 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+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/90368793-c5b7-47d2-9dfd-f0ee6221f387n%40googlegroups.com.