Cxx-mlr

Cxx-mlr

I’m working on a small exercise involving update_in/3, and I came up with this solution:

data = %{
  name: "Periodic Table",
  category: "Chemistry",
  elements: %{
    hydrogen: ["H", "Nonmetal"],
    helium: ["He", "Noble gas"],
    lithium: ["Li"],
    oxygen: ["O", "Nonmetal"]
  },
  version: 1
}

remove_attribute = fn data, element, attribute ->
  try do
    update_in(
      data,
      [:elements, element],
      fn
        nil -> throw(:element_not_found)
        [^attribute] -> throw(:remove_element)
        [_|_] = attributes -> List.delete(attributes, attribute)
      end
    )
  catch
    :element_not_found -> data
    :remove_element -> %{data | elements: Map.delete(data.elements, element)}
  end
end

The behavior I want is:

  • If the element has several attributes, remove the given attribute from the list.

  • If the attribute being removed is the element’s last attribute, remove the element itself from the :elements map.

  • If the element or attribute doesn’t exist, leave the data unchanged.

Is this a valid use of try/catch and throw? How would you approach this?

Showing Posts 1 to 9

DaAnalyst

DaAnalyst

Have you consider using get_and_update_in/3 instead (returning :pop when element removal is required)?

derek-zhou

derek-zhou

No. See Design-related anti-patterns — Elixir v1.20.4

i-n-g-m-a-r

i-n-g-m-a-r

Something like this?

  def remove_attribute(%{elements: elements} = data, element, attribute) do
    elements = elements
               |> update_in([element], &(List.wrap(&1) -- [attribute]))
               |> Enum.reject(fn {_ , value} -> match?([], value) end)
               |> Map.new

    %{data | elements: elements}
  end
LostKobrakai

LostKobrakai

get_and_update_in is the solution here with :pop, but also using Access.key with a default of [] removes the need to special case the non existing key path:

{_, result} =
  get_and_update_in(data, [:elements, Access.key(:dragon, [])], fn attributes ->
    case List.delete(attributes, attribute) do
      [] -> :pop
      attributes -> {nil, attributes}
    end
  end)
Cxx-mlr

Cxx-mlr OP

The attributes case should return {nil, attributes}.

Cxx-mlr

Cxx-mlr OP

I think that anti-pattern refers to try/rescue, not try/catch.
I agree that try/catch is ugly and I try to avoid it as much as I can.

derek-zhou

derek-zhou

If I were you, I will just implement the algorithm as closely as possible to your 3 bullet points. I believe someone said: “Don’t try to be as smart as possible in writing the code, because then you’d need to be smarter still the debug it”

new_elements = 
    data.elements
    |> Enum.map(fn {name, attributes} -> {name, List.delete(attributes, attribute)} end)
    |> Enum.filter(fn {name, attributes} -> attributes != [] end)
    |> Map.new()

data = %{data | elements: new_elements} 

PS: The source of the quote is Kernighan’s law

LostKobrakai

LostKobrakai

That one would remove the attribute from any element not just the specified one.

derek-zhou

derek-zhou

Oops, that’ll be:

case Map.fetch(data.elements, element) do
    {:ok, attributes} ->
        case List.delete(attributes, attribute) do
            [] -> pop_in(data, [:elements, element])
            attributes -> put_in(data, [:elements, element], attributes)
        end

    :error ->
        data
end
— All posts loaded —

Where Next? Top

Trending in Questions Top

katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
apz
I’m new to elixir and just tried to install the elixirLS extension for VScode(ium) and it is throwing some errors that I would like help ...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews