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.

Last Post!

sodapopcan

sodapopcan

Me neither but I’ve dealt with people who are resistant.

Where Next?

Popular in Questions Top

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
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 131117 1222
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 44778 311
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New

We're in Beta

About us Mission Statement