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 <vtmilya...@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-core+unsubscr...@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 • halosta...@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/CAJ4ekQtcuNm-ow1UiQbMVK8m3oJ8ZMi%3DvwGRjHjFOoEgR-AY%3DA%40mail.gmail.com.

Reply via email to