top | item 8687485

Imperative vs. Declarative (2013)

72 points| actraub | 11 years ago |latentflip.com

41 comments

order
[+] sytelus|11 years ago|reply
I'd been enough in to these battles so my 2 cents. I'm not saying that declarative mode is bad, in fact I love it, but the problem is that people tend to over do it in undesirable way. I've seen "architects" designing declarative language on top XML and asking programmers to code in it. There are also examples in likes of WPF which is perhaps the ugliest fattiest hairiest thing out there that lot of people have to fight with to get their job done.

1. Declarative languages or constructs are much harder to debug when things are not working as expected. There are no breakpoints to put or no debug statements to write or no watch to put. It was supposed to do that and you just can't tell why it's doing this.

2. Performance issues are much harder to resolve with declarative constructs. When you get in hotspot, there is no way to run. You would be fortunate if your language/platform allows you to fall back to imperative mode but there are platforms/languages out there which insist in 100% declarative styles.

3. There is lot of bad declarative syntax that is not designed to be composable. Lot of time, it's just is not extensible or allows to take advantage of modern programming language constructs such as inheritance, functional patterns, etc.

[+] wellpast|11 years ago|reply
All good points. However...

1. Declarative expressions are much easier to spot for defects (and much easier to not introduce defects). So do you want easier interaction w/ your debugger or do you want less bugs?

2. "There is no way to run" is an overstatement, I think. You have to run toward understanding the abstractions you're using. (E.g., if I have GC issues in the JVM, it's not that I have no where to run, it's just that now I have to go understand the GC abstraction.)

3. There is a lot of bad imperative code out there that is just as inflexible to work with.

[+] collyw|11 years ago|reply
Thinking about SQL which I use quite a lot (and the only real declarative programming I do):

1. I would not say that SQL is harder to debug than imperative code. I have also noticed that I get less bugs and they take less time to solve when I push as much as possible to SQL. Usually something either works properly or it doesn't. I personally find SQL is one of the few languages where reading the code is easier than writing it.

2: Database optimizations must be some of the most well known ways to improve performance in the tech field.

3: SQL syntax isn't great (I wouldn't say it is terrible either).

[+] guscost|11 years ago|reply
Good points.

To someone not familiar with the practice, I'd say that imperative programming is like manufacturing a car step by step, attaching parts to the engine, building the frame and so on. There are a plethora of tasks involved but it's usually clear how to finish them if you know the principles.

Declarative programming is like finding a magic incantation that makes a car pop into existence. It feels great when the default incantation works and you deliver a finished car in five minutes, but things tend to get confusing quickly if you decide that the car needs a customized transmission, a new row of seats, or (heaven forbid) a different number of wheels. Soon you're poring over arcane texts on GearChangeCommands and CabinPresenters and WheelLocators and potentially spending longer than you would have by just building the car in the slow, predictable way.

That said, I can't help but like the declarative style too, and would still prefer it much of the time to build user interfaces.

[+] jmatthews|11 years ago|reply
Isn't the hallmark of good API design essentially moving from the imperative to the declarative?

We abstract the "how" into declarative statements of "what" and "how many".

[+] tagrun|11 years ago|reply
Can't say it's surprising. The von-Neumann architecture computers and their assembly languages are imperative. Functional programming language structs are just unnatural. Being computationally universal, one can simulate one using the other. But to me, it feels like an unwanted abstraction layer.

Analogy #1: if I were going to write a game for PC, I would directly write a game for PC, not a GBA ROM + GBA emulator for PC and make-believe that it's a PC game.

Analogy #2: if I want to write a novel in Spanish, it will not be possible to achieve the quality of a text written in Spanish from the beginning, by say, writing it in Japanese and using a translator (no matter how much you may like Japanese). Some idioms and culture-dependent things will be lost in translation. (Italian or Portuguese might be better, however)

[+] pekk|11 years ago|reply
Exercise: are the type systems of functional languages in the vein of Haskell declarative in the sense that is associated with the disadvantages you mention?
[+] Animats|11 years ago|reply
Yes, way too imperative. "map" and "reduce" are imperative; they order something done.

With true declarative forms, you can treat them as data and do something other than execute them. It's hard to do much with an imperative form other than execute it. A scene graph or a game level file is a declarative form; you can view it from different angles and positions. The programs that plan actions for NPCs look at a game level and decide what to do. CAD files are declarative. Spreadsheets are mostly declarative.

The usual problem with declarative forms is lack of expressive power. If you need to express something the declarative form can't handle, it's tempting to bolt on some kind of imperative gimmick. This is how we ended up with Javascript.

[+] craigching|11 years ago|reply
> "map" and "reduce" are imperative; they order something done.

So maybe it's my age showing, but I was taught that imperative was using explicit variables to control the "looping" (e.g. for with an index a la C style programming) whereas using "higher order functions" was not imperative. And I tend to agree with that. So I disagree that map and reduce are imperative because they don't explicitly control how the looping is done.

Can anyone cite where map and reduce are imperative? Must be some new-fangled text book that I'm not aware of ;)

And I get that someone could impose on me to cite references that map and reduce are not imperative. Point taken and I'm thinking that I got this from SICP in the first place so I'm looking it up now. Will report back if I find anything.

EDIT: First quote from SICP:

"In contrast to functional programming, programming that makes extensive use of assignment is known as imperative programming. In addition to raising complications about computational models, programs written in imperative style are susceptible to bugs that cannot occur in functionalprograms."

[+] AnimalMuppet|11 years ago|reply
I think (perhaps unknowingly) you're just playing a semantic game. By your definition everything is imperative, even if it is also totally declarative. All programs are imperative in your sense. Even if you could tell the computer "Do what I want" and expect it to be psychic, that would still be imperative by your definition.

But the difference between imperative programming and declarative programming is not drawn by "ordering something done" (even if the article didn't define things precisely enough to prevent confusion on this point). It's basically a level-of-abstraction/level-of-detail thing. Saying "double each number in this list" is significantly different than saying "follow this step-by-step algorithm to double each number in the list".

The boundaries can get fuzzy; arguments can be made about where to draw the lines. But your approach lumps everything on one side of the line, and therefore becomes incapable of saying anything very useful.

[+] icebraining|11 years ago|reply
"map" and "reduce" are imperative; they order something done.

Well, in JS, sure, but what about if you could do:

  a = 13
  b = map(function(x){ return x; }, [1, 2, 8, a])
  print b
  >  [1, 2, 8, 13]
  a = 26
  print b
  > [1, 2, 8, 26]
(While I'm representing it as a sequential program, the idea would be to plug "a" and "b" to some IO channels.)

What I'm trying to say is that the concept of map is not necessarily imperative, just JS's version.

[+] aikah|11 years ago|reply
> Yes, way too imperative. "map" and "reduce" are imperative; they order something done.

Well how would you write these snippets the right way then?with the language of your choice, so it fits the declaritive way a 100% ?

[+] taeric|11 years ago|reply
Hasn't it been fairly well established that imperative and declarative are not necessarily duals? That is, !imperative is not the same as declarative. And vice versa.

That is, the base generalization here is invalid.

Further, there are plenty of things where imperative just makes sense. It is why we have plenty of imperatives in every day usage. I mean, sure, you could tell your kids "I want a clean room." Likely, they will look at you and wonder, if that is what you want, why don't you clean it. :)

So, sure, if there is a nice clean concise declarative way to specify something, do so. However, I think it is a fool's errand to think that can be the universal case. Even in an ideal sense. It is why you don't hear people trying to drop imperatives from daily life. (Or... do you?)

[+] _random_|11 years ago|reply
Still waaay too imperative, how about this:

func [1,2,3,4,5] => [2,4,6,8,10] //Calculation inferred by compiler.

console.log (func [6,7,8,9,10]) //=> [12,14,16,18,20]

[+] evincarofautumn|11 years ago|reply
One practical way to implement this would be a “...” operator which would look at the syntax of the surrounding expression and attempt to infer an inductive definition from that, based on some assumptions about e.g. the structure of lists or the values of integers.

    double xs => [xs[0] * 2, ..., xs[xs.length - 1] * 2]

    map f xs => [f(xs[0]), ..., f(xs[xs.length - 1])]

    sum xs => xs[0] + ... + xs[xs.length - 1]

    foldl f z xs => f(f(..., f(z, xs[0])), xs[xs.length - 1])

    foldr f z xs => f(xs[0], f(..., f(xs[xs.length - 1], z)))
[+] i_am_ralpht|11 years ago|reply
What algorithms are there for inferring the calculation?

I'm playing around with a tool for building touch gestures visually, and I have some problems that look a bit like that (want to infer a function from some examples) but I don't yet know how.

[+] segmondy|11 years ago|reply
Not practical, there are infinitely many functions that could produce such result

here is such psuedo code foo(x) { if (x <= 5) { x * 2 } else { x } } foo1(x) { if (x <= 6) { x * 2 } else { x+1 } } foo1(x) { if (x <= 7) { x * 2 } else { x+2 } }

[+] segmondy|11 years ago|reply
Awwww, all that an no mention of Prolog or Mecury? Prolog is a declarative language that is being used in the real world and being used often to solve interesting problems too. There is always a joke about how folks tend to reinvent lisp while trying to extend their language. Same can be said for any program that has rules, there is always a half ass prolog engine poorly implemented.
[+] sanketbajoria|11 years ago|reply
Good Explanation
[+] renox|11 years ago|reply
I disagree, it could be improved: imperative|declarative is not a binary state but a continuous line. For example, you could use foreach instead of for in the imperative solution and the loop would become closer to the declarative one.