kostonstyle
Is this code idiomatic Elixir/functional?
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
Most Liked
gon782
Well, with refactoring in mind it might be better to simply do this:
def delete_db([]) do
:ok
end
def delete_db([_h | _t] = values) do
Repo.delete_all(values)
end
It’s short, splits the procedure up into cases neatly and asserts structure at the same time.
josevalim
Here is my take:
def delete_db([]) do
:ok
end
def delete_db(values) do
Repo.delete_all(values)
end
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().
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.
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.







