Qqwy

Qqwy

TypeCheck Core Team

On 'Explicit is better than Implicit'

Hello there, everyone,

I just listened to the ‘break it down like a fraction’ episode of Elixir Outlaws on my way back home. It is mostly about the subject ‘explicit vs implicit’. I found it very interesting, since I thought it had a very clear and simple meaning, to find out that in actuality, people have given very different interpretations to what ‘explicit is better than implicit’ actually means.

So that’s why I think it might be worth talking more about this, because I agree with show-hosts Chris Keathley (@keathley) Amos King (@adkron) and Anna Neyzberg that applying a guideline without thinking about the context it was conceived in is a dangerous thing.


Personally, I’ve always thought that the main idea of ‘explicit is better than implicit’, which I believe has its origins in the Zen of Python is not about how (if at all) complexity should be abstracted away (which is an interpretation that a lot of the podcast episode focuses on), but rather the (mostly) orthogonal concept of (a) clear naming and (b) making it as clear as possible how the data/state flows through the program.

So the idea that “a user should understand with as little cognitive effort as possible what a call to a function does”. Importantly, not how it does it! (this is what is hopefully abstracted away).
This has been used as an argument in many aspects of the design of the language itself, as well as the standard library:

  • The use of defining new infix operators is often discouraged, and José has made the choice to only allow a handful of operators to be (re)defined, rather than allowing arbitrary new ones to be used.
  • Pipelines prefix module names (for non-local functions), which make it more clear what the subject is (expected to be) w.r.t. a chain of member methods that work on ‘whatever the last member method returned’ in Ruby.
  • The separation of functions that create/transform datastructures from functions that perform an effect. A prime example here would be creating an Ecto query or changeset vs. running it on a particular Repo.

So I am very eager to hear what other people think about this:

  1. Have you seen ‘explicit is better than implicit’ been used in the wild as justification for something where you think it is not applicable?
  2. What is your interpretation of ‘explicit is better than implicit’? Do you try to apply it to your code in one way or another, or not?

First Post!

JEG2

JEG2

Author of Designing Elixir Systems with OTP

Most Liked

josevalim

josevalim

Creator of Elixir

My take on the “explicit better than implicit” is that we want to make the complexity explicit. This makes its interpretation a bit more personal, because what is complex for some is not necessarily complex for others, but I believe it aligns well with FP. Mutability is troublesome? So let’s make it explicitly opt-in. Communication is hard? Let’s be explicit with messages! Oh, you have side-effects? Let’s keep them in their own corner.

In particular, explicit does not mean dropping things like “convention over configuration”. In fact, I would argue that making everything verbose makes it less explicit, because you don’t know what to focus on (i.e. if everything is explicit, then nothing is explicit).

PS: I didn’t listen to the episode yet.

25
Post #3
keathley

keathley

Oh that’s fine lots of people don’t listen to podcasts. No big deal.

Hey wait a minute!

13
Post #9
keathley

keathley

Since a few people haven’t listened to the podcast I thought I would try to explain some of the main points. I’m not sure I can enumerate everything here with as much nuance as we had on the show so I’d still recommend listening. But hopefully I can capture the main points.

I made the case on the show that a lot of the apis that people like in elixir tend to be highly implicit apis. I also made the case that explicit apis tend to be worse apis then implicit apis. That was my contrarian opinion. So now I’ll try to justify it.

When I’m talking about implicit apis what I’m really talking about is encapsulation. A key part of good api design is about hiding large amounts of complexity behind a small interface. If this is done well then the end user doesn’t ever notice the underlying complexity which is really as good as removing complexity altogether. The interface should be small for similar reasons. If you need to chain together multiple api calls in order to use a module then this is a more complicated api then an api that accomplishes the same goal through a single api call. A good example of this would be if every time you wanted to execute a query through ecto you also needed to check out the database connection yourself, parse and compile the query yourself, send the query to Postgres yourself, etc. I refer to APIs like this as “maximally explicit APIs”. They tend to be cumbersome to use and more error prone. But ftmp ecto hides all of this complexity and it’s a better api because of that.

But all of those details are “implicit” to us, the end users of Ecto. We don’t see how any of that stuff is managed from an api perspective. Sure there are escape hatches into that level of the system. But generally you don’t have to wander down there. At our layer of the stack the call to Repo is explicit, the query is explicit, and everything else is encapsulated.

Obviously those details are handled somewhere. If you work on a database pooling solution then you might have to care about them. But at our layer we’re able to ignore them and instead be more explicit about our domain logic.

The trend I see is that people have taken advice like “explicit is greater than implicit” and are carrying it a little too far. If you build a “maximally explicit” api then you quickly start to limit your ability to encapsulate complexity. If you take explicitness to it’s limit then encapsulation becomes impossible.

I think when people say they want explicit APIs over implicit APIs what they really are saying is “don’t surprise me”. If you say to ecto “run this query” you expect it to run the query. You don’t expect it to run the query and also buy you a toaster. The rails example you mention @PragTob is a great example of a surprising api. It’s almost like it was designed to create surprise through indirection.

I think what we ought to be heading for are APIs that encapsulate large amounts of complexity - which means APIs that hide implicit details - and have few if any surprises. It’s a tricky balance. But I think that’s the correct strategy.

Last Post!

venkatd

venkatd

Disclosure: I have not listened to this podcast episode yet.

But I feel like the distinction explicit vs. implicit is not helpful. When I run into a distinction that does not help, I like to ask “so what?” until I get to the root of things.

For example…

Question: why make things explicit?
Example answer: so that when you are making modifications to a codebase, you can easily understand the parts of the system needed to make the change

So really we don’t want to be explicit for the sake of being explicit - being “explicit” is just a means to a deeper goal of making a codebase easy to understand.

I would rather ask “If me or someone is coming back to this code and needs to make a change, will it be easy to understand the parts of the code needed to make the change?”

Where Next?

Popular in Discussions Top

sergio
There’s a new TIOBE index report that came out that shows Elixir is still not in the top 50 used languages. It also goes on to call Elix...
New
PragTob
Hey everyone, this has been brewing in my head some time and it came up again while reading Adopting Elixir. GenServers, supervisors et...
New
chulkilee
Here are the list of HTTP client libraries/wrappers, and some thoughts on HTTP client in general. I’d like to hear from others how they w...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
nburkley
AWS re:Invent is on at the moment with some interesting announcements. One new feature in particular is the Lambda Runtime API for AWS La...
New
Fl4m3Ph03n1x
Background A few days ago I was listening to The future of Elixir from Elixir Talks, with Dave Thomas (@pragdave ) and Brian Mitchell. I...
New
marciol
Please, let me know if this kind of discussion already took place in another topic . Hi all, how do you consider if is better to build ...
New

Other popular topics Top

hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 49266 226
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 44265 214
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New

We're in Beta

About us Mission Statement