views:

708

answers:

13

I often hear people praise languages, frameworks, constructs, etc. for being "explicit". I'm trying to understand this logic. The purpose of a language, framework, etc. is to hide complexity. If it makes you specify all kinds of details explicitly, then it's not hiding much complexity, only moving it around. What's so great about explicitness and how do you make a language/framework/API "explicit" while still making it serve its purpose of hiding complexity?

+4  A: 

Relying on default behaviour hides important details from people who aren't intimately familiar with the language/framework/whatever.

Consider how Perl code which relies extensively on shorthands is difficult to understand for people who don't know Perl.

Anon.
+15  A: 

I believe that explicit refers to knowing exactly what it is doing when you use it. That is different from knowing exactly how it's done, which is the complex part.

Juan
Exactly... explicit != complex
Mayo
+1  A: 

In some cases the opposite is "magic" - as in "then a miracle occurs".

When a developer's reading code trying to understand or debug what's going on, explicitness can be a virtue.

TrueWill
+6  A: 

Code is harder to read than to write. In nontrivial applications, a given piece of code will also be read more often than it is written. Therefore, we should write our code to make it as easy on the reader as possible. Code that does a lot of stuff that isn't obvious is not easy to read (or rather, it's hard to understand when you read it). Ergo, explicitness is considered a good thing.

Chuck
+27  A: 

Whether you should be explicit or implicit depends on the situation. You are correct in that often you are trying to hide complexity, and certain things being done behind the scenes for you automatically is good. encapsulation, etc.

Sometimes though frameworks or constructs hide things from us that they should not, and this makes things less clear. Sometimes certain information or settings are hidden from us and hence we don't know what's happening. Assumptions are made that we don't understand and can't determine. Behaviors happen that we can't predict.

Encapsulation: good. Hiding: bad. Making the right call takes experience. Where logic belongs, it should be explicit.

Example: I once removed about 90 lines of code from a series of a dozen code behind pages; data access code, business logic, etc., that did not belong there. I moved them to base pages and the key business object. This was good (encapsulation, separation of concerns, code organization, decoupling, etc.).

I then excitedly realized that I could remove the last line of code from many of these pages, moving it to the base page. It was a line that took a parameter from url and passed it to the business object. Good, right? Well, no, this was bad (I was hiding). This logic belonged here, even though it was almost the same line on every page. It linked the UI intention with the business object. It need to be explicit. Otherwise I was hiding, not encapsulating. With that line, someone looking at that page would know what that page did and why; without it, it would be a pain to determine what was going on.

Patrick Karcher
I think a lot of Microsofts frameworks suffer from the problem of hiding too much, and making it too difficult to plug in pieces to figure out what's going on.
Andy White
@Andy: The ASP.NET Web forms frameworks suffer from that, ASP.NET MVC tries to reduce that abstraction. :)
Mayo
A: 

The purpose of frameworks moving things around is to remove duplication in code and allow easier editing of chunks without breaking the whole thing. When you have only one way of doing something, like say SUM(x,y); We know exactly what this is going to do, no reason to ever need to rewrite it, and if you must you can, but its highly unlikely. The opposite of that is programming languages like .NET that provide very complex functions that you often will need to rewrite if your doing anything but the obvious simple example.

MindStalker
+7  A: 

It is about expressing intentions. The reader can't tell if the default was left by mistake or by design. Being explicit removes that doubt.

Brian Rasmussen
A good way of looking at it. However, including additional details that the user doesn't care about (and doesn't actually need to know) will muddy intent, not clarify it.
kyoryu
Of course. I am not advocating maximum verbosity. Be explicit when it expresses the intentions behind the code.
Brian Rasmussen
+3  A: 

Frameworks, etc., can be both explicit and hide complexity by offering the right abstractions for the job to be done.

Being explicit allows others to inspect and understand what is meant by the original developer.

Hiding complexity is not equivalent with being implicit. Implicitness would result in code that is only understandable by the person who wrote it as trying to understand what goes on under the hood is akin to reverse engineering in this case.

Explicit code has a theoretical chance of being proved correct. Implicit code never stands a chance in this respect.

Explicit code is maintainable, implicit code is not - this links to providing correct comments and choosing your identifiers with care.

rsp
+2  A: 

An "explicit" language allows the computer to find bugs in software that a less-explicit language does not.

For example, C++ has the const keyword for variables whose values should never change. If a program tries to change these variables, the compiler can state that the code is likely wrong.

Chip Uni
+2  A: 

Explicitness is desirable in the context of making it clear to the reader of your code what you intended to do.

There are many examples, but it's all about leaving no doubt about your intent.

e.g. These are not very explicit:

while (condition);

int MyFunction()

bool isActive;         // In C# we know this is initialised to 0 (false)

a = b??c;

double a = 5;

double angle = 1.57;

but these are:

while (condition)
    /* this loop does nothing but wait */ ;

private int MyFunction()

int isActive = false;  // Now you know I really meant this to default to false

if (b != null) a = b; else a = c;

double a = 5.0;

double angleDegrees = 1.57;

The latter cases leave no room for misinterpretation. The former might lead to bugs when someone fails to read them carefully, or doesn't clearly understand a less readable syntax for doing something, or mixes up integer and float types.

Jason Williams
I don't think a = b ?? c is any less explicit than your alternative
Lee
True, it *means* the same thing, hence it is "explicit". But the point I was making with that example is that if you don't know C# (or indeed if you do, but don't use ?? much), which syntax is more readable? Using the more readable form makes your intention clear to a wider audience, hence it is (in a sense) a more explicit way of stating it.
Jason Williams
Shouldn't code be written with the assumption that the person reading it **does** know the language reasonably well?
dsimcha
Not if you want random junior programmer X (who you haven't even hired yet) to successfully maintain your code. I work with a mathematician who writes dynamics code - he programs all day, but he is not a career programmer and I doubt he'd know what ?? means. I've been programming for 28 years and I understand ?? but I use it so infrequently (never, in fact) that I have to *think* what it means whenever I read it.
Jason Williams
Well, if random junior programmer X doesn't know what ??, or any other useful but "non-explicit/advanced" construct is, he can easily look it up, with the added benefit that he'll be able to grok it and use it in his code from that point forward. If he's too lazy or ignorant to do so, then you probably shouldn't have hired him.
dsimcha
My point, which you seem to be missing, is that "if...else" is easier in general for people to read. I'm not saying you shouldn't use ??, I'm just using it as a clear example where you have the *option* of a fairly universal syntax (making it readable by anyone, even most non-programmers) or a cryptic one (meaning that it requires the reader to have a greater level of knowledge of this specific language).
Jason Williams
+2  A: 

Good abstraction doesn't hide complexities, it takes decisions that are best left to the compiler off of your plate.

Consider garbage collection: The complexities of releasing resources are delegated to a garbage collector which is (presumably) better qualified to make a decision than you, the programmer. Not only does it take the decision off your hands, but it makes a better decision than you would have yourself.

Explicitness is (sometimes) good because it makes it so that certain decisions that in some cases are better left to the programmer are not automatically made by a less qualified agent. A good example is when you're declaring a floating point data type in a c-type language and initializing it to an integer:

double i = 5.0;

if instead you were to declare it as

var i = 5;

the compiler would rightfully assume you want an int and operations later on would be truncated.

brian
This is a silly example, but what's wrong with:`double i = 5;`or `var i = 5.0;`
dsimcha
+6  A: 

It's not so much that explicit is good (certainly the closely-related verbose is bad) as that when implicit goes wrong, it's so hard to tell WTF is going on.

Hack C++ for a decade or two and you'll understand exactly what I mean.

Jason Orendorff
+4  A: 

Being explicit vs. implicit is all about what you hide, and what you show.

Ideally, you expose concepts that either the user cares about, or has to care about (whether they want to or not).

The advantage of being explicit is that it's easier to track down and find out what's going on, especially in case of failure. For instance, if I want to do logging, I can have an API that requires explicit initialization with a directory for the log. Or, I can use a default.

If I give an explicit directory, and it fails, I'll know why. If I use an implicit path, and it fails, I will have no idea of what has gone wrong, why, or where to look to fix it.

Implicit behavior is almost always a result of hiding information from the consumer. Sometimes that's the right thing to do, such as when you know in your environment there's only one "answer". However, it's best to know when you're hiding information and why, and ensure that you're letting your consumers work closer to their level of intent, and without trying to hide items of essential complexity.

Frequently implicit behavior is a result of "self-configuring" objects that look at their environment and try to guess the correct behavior. I'd avoid this pattern in general.

One rule I'd probably follow overall is that, for a given API, any operation should either be explicit, or implicit, but never a combination. Either make the operation something the user has to do, or make it something they don't have to think about. It's when you mix those two that you will run into the biggest problems.

kyoryu