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.

Reply via email to