kostonstyle

kostonstyle

I wrote a a function that delete the content of database.
Consider following code snipped:

defmodule Seeds do

  def delete_db(values) when is_list(values) do
    cond do
      length(values) > 0  ->
        Repo.delete_all(values)
      true ->
        {:ok}
    end
  end

end

When I call the delete_db function, it will happen a side effect, the data on db will be deleted.
My question is, do I follow functional specification?

Thanks

Showing Posts 17 to 8

peerreynders

peerreynders

This topic made me realize that I need to work more on retraining my mind to see multiple function clauses not as overloaded functions but as distinct parts of one single function.

Edit: Sorry meant to be a general remark, not a specific reply.

hazardfn

hazardfn

Was hoping somebody had posted this method - too often the beauty of pattern matching in function heads is forgotten! :stuck_out_tongue:

NobbZ

NobbZ

Enum.any?/2 might gain you a bit, but only a little. For an empty list it returns always false, so you could do Enum.any?(list, &(&1)), which will return true for any non-empty list that does not consists of only nils and falses. But if you expect to have a list that might consit only of those, you can extend the filter: Enum.any?(list, &(&1 or (&1 == false) or (&1 == nil))) (untested).

But to be honest, I’d prefer to use Enum.empty?/1, but only if you can’t use a pattern match.

orestis

orestis

Is really Enum.any? a replacement of length?

The documentation says:

Invokes the given fun for each item in the enumerable. It stops the iteration at the first invocation that returns a truthy value. Returns true if at least one invocation returns a truthy value. Otherwise returns false.

When I read this, I would expect that values would contain true/false values and as long as one of them is true… delete from the repo? I would flag this as a code smell, no?

josevalim

josevalim

Creator of Elixir

Here is my take:

def delete_db([]) do
  :ok
end
def delete_db(values) do
  Repo.delete_all(values)
end
gon782

gon782

In this case it might be redundant, yeah, but in the general case you’ll get better error messages if you force structural matching when appropriate, because you’ll get errors about no function clause matching, which is generally super easy to debug. It’ll force the error earlier and be less messy.

I would add that I don’t think there is any downside to being as assertive as possible anywhere.

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

I prefer code to be as assertive as possible about structure and constants if possible. If something in the function itself makes the assumption that lists are passed in

Well the thing is there’s no value in doing this redundantly. Repo.delete_all already checks that the inputs make sense. In fact the whole function is pretty redundant because Repo.delete_all is smart enough to no-op an empty list.

gon782

gon782

The possible issue is that you’re not necessarily asserting that it should be a list if you ended up using only values, yeah. I prefer code to be as assertive as possible about structure and constants if possible. If something in the function itself makes the assumption that lists are passed in, we should try to make things that don’t follow that crash horribly, IMO.

On a related note: I vastly prefer the structural form to is_list().

gon782

gon782

Think of it this way:

If something needs updating, let’s say a map of some keys and values, you could conceivably have a process that guards that state and the way you interact with it is to send messages to that process in order to modify the data.

When you use this model you run the risk of having the process crash on you, possibly losing state while doing so, and also having the data modified at any point because other processes can also change the state. What you’ve effectively created is something like a reference to the state you want to work with. Sure, when you have it in your hand you can trust that it’s the same state you got from the KV process, but you can never trust that you have the “correct” data in the sense that it’s the updated one.

The BEAM is great in that your particular piece of memory that holds the data you have can’t be changed by anything else, so that’s great, but putting too many things in processes and calling stateful functions with them will still invite harder debugging.

If you had a function that modified the map and then passed that map to the function as an argument everything that that function relies on is inside that function. It doesn’t make any assumptions about the world; for example that a KV store is running somewhere.

It’s trivial to emulate stateful constructs in Elixir, but we generally never set out to do so unless it’s really needed. The point is to make the least amount of assumptions possible about what exists when you run something. The ideal is for everything that a function touches to be something it’s given up-front.

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

As a final tweak, you can have the second clause just be def delete_db(values) because the only way it gets there is if it isn’t an empty list. You could add when is_list(values) if you really wanted to as well

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
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
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
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New

Other Trending Topics Top

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
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
Aludel - LLM Evaluation Workbench Aludel is an embeddable Phoenix LiveView dashboard for evaluating and comparing LLM prompts across mult...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews