chan11347

chan11347

How to put a if else in a function

i want to add a condition in the add_entry to limit the input such like if else in java, any help

server.ex

def add_entry(todo_server, new_entry) do
    GenServer.cast(todo_server, {:add_entry, new_entry})
  end
@impl GenServer
  def handle_cast({:add_entry, new_entry}, {name, todo_list}) do
    new_list = Todo.List.add_entry(todo_list, new_entry)
    Todo.Database.store(name, new_list)
    {:noreply, {name, new_list}}
  end

list.ex

def add_entry(todo_list, entry) do
    entry = Map.put(entry, :id, todo_list.auto_id)
    new_entries = Map.put(todo_list.entries, todo_list.auto_id, entry)

    %Todo.List{todo_list | entries: new_entries, auto_id: todo_list.auto_id + 1}
  end

Marked As Solved

lucaong

lucaong

If your map contains keys like :date, :time, etc., then your code above won’t work (because it matches an entry with key :entries).

There are a few possible ways to solve this. First, you could check if any of the entry fields is blank. Remember that maps are Enumerable, so you can enumerate them as a collection of {key, value} with the Enum module:

def add_entry(todo_server, new_entry) do
  if Enum.any?(new_entry, fn {_key, value} -> value == nil || value == "" end) do
    IO.puts("input cannot be empty!")
  else
    GenServer.cast(todo_server, {:add_entry, new_entry})
  end
end

Instead of printing an output though, it would be better to return an error, so the caller can pattern match easily. Usually, one would return :ok or {:error, reason}:

def add_entry(todo_server, new_entry) do
  if Enum.any?(new_entry, fn {_key, value} -> value == nil || value == "" end) do
    {:error, "input cannot be empty!"}
  else
    GenServer.cast(todo_server, {:add_entry, new_entry})
  end
end

If the entries always have the same keys, there is a possibly better way to do this: you can use a struct for the entry, instead of a map, to enforce the “shape” of the entry:

defmodule Todo.Server do
  defmodule Entry do
    @enforce_keys [:date, :time, :title]
    defstruct [:date, :time, :title]
  end

  def add_entry(todo_server, %Entry{date: date, time: time, title: title})
  when is_nil(date) or is_nil(time) or is_nil(title) or title == "" do
    {:error, "input cannot be empty!"}
  end

  def add_entry(todo_server, new_entry = %Entry{}) do
    GenServer.cast(todo_server, {:add_entry, new_entry})
  end

  def add_entry(_server, _entry), do: {:error, "Invalid input"}
end

This way, the entry is now a struct that enforces that all of :date, :time, and :value are present. This also mean, though, that the caller of the add_entry function has to pass an Entry struct instead of a map, so it’s your choice whether this is desirable or not.

P.S.:
Unrelated to your question, but you might want to use GenServer.call/3 instead of GenServer.cast/2, even if you don’t need a result. The reason is explained here: https://elixir-lang.org/getting-started/mix-otp/genserver.html#call-cast-or-info

Also Liked

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Please always supply errors and code as text. The images are not readable on my screen, and it makes it very hard to suggest edits because I have to retype everything.

lucaong

lucaong

Yes, now the struct enforces the presence of all the keys. That’s good, because it enforces that an %Entry{} struct without the necessary options simply cannot be created.

That said, if you don’t want that, you can change the struct definition to:

defmodule Entry do
  # remove @enforce_keys
  defstruct date: nil, time: nil, title: nil
end

Make sure you understand the implications first though:

  • If you use a struct enforcing the keys, you enforce the presence of the keys whenever that struct gets created. That’s generally better, because it’s the developer’s job to make sure that the struct is created with the correct keys. In other words, it’s not a runtime concern. You still validate that the supplied values are not nil, because those values might come from user input, so that is a runtime concern, and you might need to give meaningful error messages to the user.

  • If you do not enforce the keys, when those keys are not set they will default to nil, and your code will return an error tuple like {:error, "input cannot be empty!"}. This might sound useful, but if it’s the code that builds the struct wrong, an error message to the user won’t be useful.

Where Next?

Popular in Questions Top

shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
sacepums
Hey guys. I'm new to elixir and im really stocked about it. But I ran into a bit of problem - I need to convert a date sting, for examp...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
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
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
mathew4509
I have a list say x = ["23gh", "56kh", "97mh"] I would like to pass each element to Val in each iteration. Say, in iteration 1 -------...
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
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New

Other popular topics Top

chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30048 115
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
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
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
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
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
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
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
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

We're in Beta

About us Mission Statement