dimitarvp

dimitarvp

Can a defguard definition match against a struct?

Hello,
Is it possible to check if an argument to a guard is a particular structure?

Context: I am trying to have a defguard definition that checks if something is an Ecto query – which means it can either be a module (e.g. atom) or it can be an %Ecto.Query{}. But I cannot seem to find a way to do it via defguard.

defmodule A do
  defguard is_query(q) when is_atom(q) or ... # <- what do we put here?
end

Tried with match?(%Ecto.Query{}, q) but that did not compile.

Something I am missing?

Marked As Solved

msimonborg

msimonborg

The simpler way to do this now is defguard is_query(a) when is_struct(a, Ecto.Query) using Kernel.is_struct/2, which was introduced after this thread was last active. PR #9470

As for your question, I am not 100% sure, but if what you have created is an Ecto.Query struct, it will match

Also Liked

idi527

idi527

As for your actual question:

defguard is_query(a) when is_map(a) and :erlang.map_get(:__struct__, a) == Ecto.Query
dimitarvp

dimitarvp

Ha, I like this a lot. Thanks for pointing it out.

wojtekmach

wojtekmach

Hex Core Team

It is impossible to do in a defguard. I think it is possible, with big caveats so maybe actually impossible too, with a defmacro. If the protocol is consolidated, you can grab the list of modules implementing it. So if your protocol is consolidated by the time you call your guard, which generally may not necessarily be the case, that should work. Here’s a sketch:

defmodule Macros do
  defmacro is_impl(term, protocol) do
    protocol = Macro.expand(protocol, __ENV__)

    impls =
      case protocol.__protocol__(:impls) do
        {:consolidated, impls} ->
          impls

        :not_consolidated ->
          raise "#{inspect(protocol)} is not consolidated"
      end

    quote do
      unquote(term).__struct__ in unquote(impls)
    end
  end
end

defmodule Foo do
  import Macros

  def f(enumerable) when is_impl(enumerable, Enumerable) do
    Enum.to_list(enumerable)
  end
end

besides the caveat around consolidation time, in the list of impls we have things like Atom, Integer, …, Any, and they all would have to be handled too.

So yeah, not worth it. :slight_smile:

Where Next?

Popular in Questions Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Other popular topics Top

dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 45766 226
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 49522 488
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

We're in Beta

About us Mission Statement