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}

Last Post!

Sebb

Sebb

Sorry guys, I had a rough time and completely forgot about this thread.

Thanks for the insights.

As it seems we can’t exploit “errors in guards” inside a defguard, so I’ll go with your proposal.

Where Next?

Popular in Questions Top

vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
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
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
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
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

Other popular topics Top

KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36689 110
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 40082 209
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 44608 311
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

We're in Beta

About us Mission Statement