jeroenbourgois

jeroenbourgois

How to extend kernel module without aliasing/importing it?

I would like to add a function to my project that is available throughout all modules without aliasing/importing it. How should I go about it? I know I can include it in my *_web.ex file so it becomes available in controllers, views, … but I want to use it in business logic as well. Like the title op my topic suggest, I would like it to be available next to all other default Kernel module functions.

The function itself is very simple:

def is_empty(""), do: true
def is_empty(nil), do: true
def is_empty([]), do: true
def is_empty(_), do: false

Thank you for your input!

PS: I opted for is_empy/1 vs empty?/1 to relate to the existing is_nil/1 function.
PS2: our codebase has various occurences of x in ["", nil] checks, which I would like to simplify.

Marked As Solved

jeroenbourgois

jeroenbourgois

Thank you (both) for the responses!

As for the data, most checks are if a in ["", nil] (without the list), because for those fields in the database we can have nil or the empty string. In the database we want the difference, since nil is the default (aka: never set) and the empty string can be ‘set to empty’, but was set none the less.

We find it valuable to have that distinction in the db, but in the application it doesn’t matter most of the time.

Thanks again for the input, I’ll take this feedack to our team!

Also Liked

christhekeele

christhekeele

Yup. Elixir is explicit about imports by design, with Kernel being the single exception. You will need to define some sort of MyProject.Kernel and import it wherever you want to use its functions.


Just BTW, the is_nil/1 function does not choose is_nil over nil? half-hazardly, this is in line with a particular Elixir naming convention:

Type checks and other boolean checks that are allowed in guard clauses are named with an is_ prefix.

Note that type checks that are not valid in guard clauses do not follow this convention. For example: Keyword.keyword?/1.

To follow this convention that other developers in your project may rely upon, you would either want to name this function empty?/1, or implement it as a guard.

That implementation will be different than the functional version, but can be used anywhere guards or allowed! To translate your example is_empty/1, it would look something like:

defmodule MyProject.Kernel do
  defguard is_empty(thing) when thing in ["", nil, []]
end

Finally, as a design note, outside of extenuating circumstances, I would treat it as a code smell that you are often checking if thing in ["", nil, []]. The implication is that you are regularly uncertain if your data is a string, list, or null value; all throughout your program.

It would be hard with no context to diagnose why this is happening or propose a better pattern, but I would keep :eyes: on this part of your code! You may find an opportunity to coerce the variable type of an input into your program into a known single type close to where it is received, then confidently refactor a lot of less-confident, unassertive code. Then theoretically you could handle “empty cases” throughout just by matching against one of "", [], or nil.

LostKobrakai

LostKobrakai

There’s nothing automatically imported besides Kernel in elixir. You either need to import explicitly or have a macro doing the import.

D4no0

D4no0

I’ve dealt with this a few times also in some legacy codebases and the best solution I found is to use custom Ecto types that know how to deal with these values, you skip the step where you have to deal manually with these kind of checks.

christhekeele

christhekeele

That’s a very common situation, makes perfect sense!

Generally, rather than scattering these checks across my codebase, I’d try to exert them within modules singly responsible for interacting with ecto structs that have these quirks—for example, perhaps inside the schema modules themselves with changesets, or a context module that validates and navigates all of this conditional logic in one place.


Specific to this common empty-string data-model case however, I’d propose a simpler way to handle this—at least, if your team is willing to make a schema change, and using postgres—other dbs may have similar solutions but I’m not sure:

ALTER TABLE thing ADD CHECK (field <> '');

This simply ensures that a given field can not be an empty string.

Whether or not my text fields are NOT NULL these days, I simply do not allow empty strings in my data model. It never makes sense in the domain layer, causes semantic confusion in nullable columns, and as you experience, pushes a whole bevy of edge case handling to application logic.

Empty strings are the opposite of data, moreso than NULLs! Get’em out of your database! Make invalid states unrepresentable! Have your nullable changesets cast "" to nil once, your non-nullable ones error, and never think about it again.

The one exception is maybe if I have a user-entered free-form text area like a description and I want to discern between “never interacted with” and “had a value manually deleted”. But that’s really something that should be modeled differently, with change tracking or an enum-type state machine.


:memo: Edit: I just noticed your mention that

:sweat_smile: Feel free to ignore my rant against empty strings, then! If your team finds signal in them, by all means normalize in the application layer rather than the data model! @D4no0 's suggestion is a great one.

dimitarvp

dimitarvp

You’re a missing a guard here.

Where Next?

Popular in Questions Top

lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
gonzofish
I’m currently trying to understand how to join three tables using Ecto. All the examples I’ve seen use 2, so maybe I’m just missing somet...
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
Exadra37
Sometimes I want to check if the input into a function is not a blank string. My first approach: defmodule Example do def do_stuff(s...
New
wernerlaude
In AR this is so simple @articles = current_user.articles How to do in Ecto? def index(conn, _params) do current_user = conn.assig...
New

Other popular topics Top

TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
273 38985 115
New
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
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
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 49522 488
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? https://hexdocs.pm/ecto/Ecto.Repo.h...
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New

We're in Beta

About us Mission Statement