Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to match on non-existing key of map in function head

I have a function that maintains some values as state for its recursion and in order to be flexible with the order of its arguments, I am using a Map to store the state and pass it around between calls.

My base case is that the function gets called without a socket, so there should be a case where only that setup is done. However, I can't find a way to match a non-existing key of a Map.

Attempts:

def measure(args = %{socket: nil}) ...

def measure(args = %{socket: socket}) when not is_port(socket) ...

However, these patterns only match when there exists a key socket that is nil/not a port.

Is there a way of specifying a pattern that does match a non-existing key? Or do I have to create another entry function that provides default values for my Map?

like image 749
iStefo Avatar asked Dec 25 '22 21:12

iStefo


2 Answers

With Elixir version 1.10.0 there is a new guard intruduced called is_map_key (https://hexdocs.pm/elixir/Kernel.html#is_map_key/2)

You can now handle non existing keys in maps like:

def measure(args) when not is_map_key(args, :socket) do
  handle_without_socket(args)
end

def measure(args = %{socket: socket}) do
  handle_socket(socket, args)
end
like image 149
alabama Avatar answered Jan 06 '23 16:01

alabama


You need a clause that matches on any value for that and add another one after:

def measure(args = %{socket: socket}) do
  handle_socket(socket, args)
end

def measure(args) do
  handle_without_socket(args)
end

Generally speaking, the preferred way of using maps is via the strict syntax. You would just match on :socket or call args.socket and it will fail if a socket is not available as key.

If you are passing optional data, maybe you want to use a keyword list instead of a map.

like image 40
José Valim Avatar answered Jan 06 '23 15:01

José Valim