Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a Elixir equivalent of Rails `try` function?

Tags:

ruby

elixir

In Rails you can do something like:

@user.try(:contact_info).try(:phone_number)

Which will return the phone_number if the @user and contact_info are both not nil. If one of those are nil, the expression will return nil.

I want to know what is the most idiomatic way to do this in Elixir, knowing that @user and contact_info are structs.

like image 620
Martinos Avatar asked Mar 14 '16 03:03

Martinos


3 Answers

I think one way to do that is to go with pattern matching so it would be something like this:

case user do
  %{contact_info: %{phone_number: phone_number}} when phone_number != nil -> 
    #do something when the phone number is present
  _ -> 
    #do something when the phone number is absent
end
like image 98
NoDisplayName Avatar answered Nov 15 '22 17:11

NoDisplayName


Edit: Testing my suggestion to use with, I realize it won't work as it short circuits on match error, but you'll have UndefinedFunctionError on nil. So I removed that part. I'd go with pattern matching, as @JustMichael suggested.

If you control the definition of the structs, a default value in the struct may help.

defmodule ContactInfo do
  defstruct phone_number: nil
end

defmodule User do
  defstruct contact_info: %ContactInfo{}
end

iex> user = %User{}
%User{contact_info: %ContactInfo{phone_number: nil}}
iex> user.contact_info.phone_number
nil

Someone could still purposely set :contact_info to nil, but consider just letting it crash… :)

like image 2
Martin Svalin Avatar answered Nov 15 '22 17:11

Martin Svalin


You can use get_in from Kernel:

iex(2)> user = %{contact_info: %{name: "Bob"}}
%{contact_info: %{name: "Bob"}}
iex(3)> get_in(user, [:contact_info, :name])
"Bob"
iex(4)> user2 = %{}
%{}
iex(5)> get_in(user2, [:contact_info, :name])
nil
iex(6)> user3 = %{contact_info: %{}}
%{contact_info: %{}}
iex(7)> get_in(user3, [:contact_info, :name])
nil

Note that this will won't work with Ecto models/structs, but plain maps are fine.

like image 1
chrismcg Avatar answered Nov 15 '22 17:11

chrismcg