Sebb

Sebb

Exploit "Errors in guards" in defguard

I have this helper function where I exploit the Errors in Guards feature.

def non_empty(val, _msg) when length(val) > 0, do: {:ok, val}
def non_empty(val, _msg) when map_size(val) > 0, do: {:ok, val}
def non_empty(val, _msg) when tuple_size(val) > 0, do: {:ok, val}
def non_empty(_val, msg), do: {:error, msg}

(I can call non_empty({:foo}, "") though length({:foo}) raises)

Is there a way to put this into a defguard - without using is_list/1 etc?

defguard enum_size... ???

Marked As Solved

eksperimental

eksperimental

This is how I would rewrite your clauses into just two.

  def non_empty(val, _msg)
      when is_list(val) and val != []
      when is_map(val) and map_size(val) > 0
      when is_tuple(val) and tuple_size(val) > 0 do
    {:ok, val}
  end

  def non_empty(_val, msg), do: {:error, msg}

by checking for the type, it does not raise (anyway that is not a problem if you only have one when clause), but in my example it is needed, othewise later when clauses will never be evaluated if any prior clause raises.
Personally I consider good practice to check for types.

Also Liked

eksperimental

eksperimental

@kartheek definitely yours is more performant.

Here’s another version I think even simpler, that builds on your idea.
defguard is_non_empty(term) when term not in [{}, [], %{}]

kartheek

kartheek

size is constant time O(1), where as length is linear time -O(N) - Naming conventions — Elixir v1.20.2

Isn’t non_empty for lists a bit more expensive operation - depending on size of list?

Enum.empty?/1 just compares to when it is list.

def empty?(enumerable) when is_list(enumerable) do
    enumerable == []
end

Maybe your non_empty can be changed to this ?

def non_empty(val, _msg) when map_size(val) > 0, do: {:ok, val}
def non_empty(val, _msg) when tuple_size(val) > 0, do: {:ok, val}
def non_empty([], msg), do: {:error, msg}
def non_empty(val, _msg) when is_list(val), do: {:ok, val}
def non_empty(_val, msg), do: {:error, msg}

or something like this only if you pass enumerable or tuple, else this will return {:ok, val} for strings, numbers, etc

  def non_empty([], msg), do: {:error, msg}
  def non_empty({}, msg), do: {:error, msg}
  def non_empty(%{} = val, msg) when map_size(val) == 0, do: {:error, msg}
  def non_empty(val, _msg), do: {:ok, val}
eksperimental

eksperimental

please don’t! It totally changes the logic of the function, unless you are fine with it.
As mentioned by @karthheek, it will return {:ok, } in case of an uncovered type.

non_empty(0, "it is empty") will return {:ok, 0}

Where Next?

Popular in Questions Top

sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
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
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
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
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: The documentation above suggests that while ...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
marick
I had some trouble figuring out how to make many-to-many associations work. Once I got it working, I wrote a blog post. Because I’m a nov...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

Other popular topics Top

Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
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
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement