2

Reading a couple of questions about Post-Increment and Pre-Increment I am in need of trying to explain a new programmer in what cases I would actually need one or the other. In what type of scenarios one would apply a Post-Increment Operator and in what it is better to apply a Pre-Increment one.

This is to teach case studies where, in a particular code, one would need to apply one or the other in order to obtain specific values for certain tasks.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
Luis Alvarado
  • 8,837
  • 12
  • 46
  • 60
  • 3
    Are you asking exclusively about functional programming? I see you added the FP tag, but in your text, FP is never mentioned. This is quite confusing to me, because the difference Pre-I vs Post-I seems much larger to me in languages with mutable variables. – Uli Köhler Mar 02 '14 at 04:12
  • No. Not exclusively for functional but it was the only tag that appeared. I was looking for a more general tag actually. – Luis Alvarado Mar 02 '14 at 05:03
  • You can use tags other than the auto-suggested ones. – user2357112 Mar 02 '14 at 09:52
  • I've updated the tags a bit. – Ingo Mar 02 '14 at 10:00
  • 2
    @Ingo: I removed the "pdp-11" and "vax" tags because they're not really relevant. See [this web page](http://cm.bell-labs.com/who/dmr/chist.html); search for "PDP-11". "People often guess that they were created to use the auto-increment and auto-decrement address modes provided by the DEC PDP-11 on which C and Unix first became popular. This is historically impossible, since there was no PDP-11 when B was developed." – Keith Thompson Mar 02 '14 at 10:46
  • Thank you, @KeithThompson. Still, they did fit better than the original "functional programming". – Ingo Mar 02 '14 at 16:26

4 Answers4

6

The short answer is: You never need them!

The long answer is that the instruction sets of early micro-computers had features like that. Upon reading of a memory cell, you could post-increment or pre-decrement that cell when reading it. Such machine level features inspired the predecessors of C, from whence it found its way even into more recent languages.

To understand this, one must remember that RAM was extremely scarce in those days. When you have 64k addressable RAM for your program, you'll find it worth it to write very compact code. The machine architectures of those days reflected this need by providing extremely powerful instructions. Hence you could express code like:

s = s + a[j]
j = j + 1

with just one instruction, given that s and j were in a register.

Thus we have language features in C that allowed the compiler without much effort to generate efficient code line:

register int s = 0;           // clr r5
s += a[j++];                  // mov j+, r6   move j to r6 and increment j after
                              // add r5,a[r6]

The same goes for the short-cut operations like +=, -=, *= etc.

They are

  1. A way to save typing
  2. A help for a compiler that had to fit in small RAM, and couldn't afford much optimizations

For example,

a[i] *= 5

which is short for

a[i] = a[i] * 5

in effect saves the compiler some form of common subexpression analysis.

And yet, all that language features, can always be replaced by equivalent, maybe a bit longer code that doesn't use them. Modern compilers should translate them to efficient code, just like the shorter forms.

So the bottom line and answer to your question: you don't need to look for cases where one needs to apply those operators. Such cases simply do not exits.

Ingo
  • 36,037
  • 5
  • 53
  • 100
  • 2
    No, `++` and `--` were not inspired by the PDP-11. The PDP-11 had predecrement and postincrement addressing modes, but not postdecrement and preincrement -- and it didn't exist when the `++` and `--` operators were added to C's predecessor language B. – Keith Thompson Mar 02 '14 at 10:48
  • @KeithThompson I have rewritten a bit, I hope it is now more accurate. – Ingo Mar 02 '14 at 16:24
  • 1
    This is an elaborate answer, but isn't the question about when to use pre and when to use post-operators and not about when to use the operators at all? – Excelcius Mar 02 '14 at 17:08
  • @Excelcius not quite, the question is actually when you *need* to use them. I am explaining that we don't need to - that we merely have syntactic sugar to write more compact programs. – Ingo Mar 02 '14 at 17:56
  • @Ingo Yes but the last sentence of the first paragraph says: "In what type of scenarios one would apply a Post-Increment Operator and in what it is better to apply a Pre-Increment one." That's why I think he is more interested in the difference between post and pre operators. But who am I to decide what the OP wants ;) – Excelcius Mar 02 '14 at 17:59
  • @Excelcius Well, yes, but then this question is like "When to use + or better -" - it stems from a misunderstanding of what these operators are and do. I am just telling - don't care about them. It's nothing magical about them. Once you find yourself writing: `counter = counter - 1; return array[counter]` and wish there was a way to write this shorter, *then* the time has come to learn that pre-decrement does what you want. – Ingo Mar 02 '14 at 18:14
3

Well, some people like Douglas Crockford are against using those operators because they can lead to unexpected behaviors by hiding the final result from the untrained eye.

But, since I'm using JSHint, let's share an example here:

http://jsfiddle.net/coma/EB72c/

var List = function(values) {

    this.index = 0;
    this.values = values;
};

List.prototype.next = function() {

    return this.values[++this.index];
};

List.prototype.prev = function() {

    return this.values[--this.index];
};

List.prototype.current = function() {

    return this.values[this.index];
};

List.prototype.prefix = function(prefixes) {

    var i;

    for (i = 0; i < this.values.length; i++) {

        this.values[i] = prefixes[i] + this.values[i];
    }
};

var animals = new List(['dog', 'cat', 'parrot']);

console.log('current', animals.current());
console.log('next', animals.next());
console.log('next', animals.next());
console.log('current', animals.current());
console.log('prev', animals.prev());
console.log('prev', animals.prev());

animals.prefix(['Snoopy the ', 'Gartfield the ', 'A ']);

console.log('current', animals.current());
Community
  • 1
  • 1
coma
  • 16,429
  • 4
  • 51
  • 76
2

As others have said, you never "need" either flavor of the ++ and -- operators. Then again, there are a lot of features of languages that you never "need" but that are useful in clearly expressing the intent of the code. You don't need an assignment that returns a value either, or unary negation since you can always write (0-x)... heck, if you push that to the limit you don't need C at all since you can always write in assembler, and you don't need assembler since you can always just set the bits to construct the instructions by hand...

(Cue Frank Hayes' song, When I Was A Boy. And get off my lawn, you kids!)

So the real answer here is to use the increment and decrement operators where they make sense stylistically -- where the value being manipulated is in some sense a counter and where it makes sense to advance the count "in passing". Loop control is one obvious place where people expect to see increment/decrement and where it reads more clearly than the alternatives. And there are many C idioms which have almost become meta-statements in the language as it is actually used -- the classic one-liner version of strcpy(), for example -- and which an experienced C programmer will recognize at a glance and be able to recreate at need; many of those do take advantage of increment/decrement as side effect.

Unfortunately, "where it makes sense stylistically" is not a simple rule to teach. As with any other aspect of coding style, it really needs to come from exposure to other folks' code and from an understanding of how "native speakers" of the programming language think about the code.

That isn't a very satisfying answer, I know. But I don't think a better one exists.

keshlam
  • 7,931
  • 2
  • 19
  • 33
  • A pedagical approach would be to not teach the shorthands in the first place, but later, when the studenst find themselves writing code like `int temp = counter; counter = counter + 1; return a[temp]` you can tell them that they can write `return a[counter++]:` – Ingo Mar 02 '14 at 18:02
  • 1
    I think you need to teach folks that the shorthands exist, because they're certainly going to see them in sample code and come to you with questions. But I agree that it makes sense to teach them _as_ shorthand rather than as primary solution... and to focus on using them only in "counters" rather than as a general operation, and to remind folks that any operation with side effects raises precedence and order of execution questions which it's usually better to avoid than to understand deeply. "Real writers rewrite to avoid the problem." – keshlam Mar 02 '14 at 19:24
0

Usually, it just depends on what you need in your specific case. If you need the result of the operation, it's just a question of whether you need the value of the variable before or after incrementing / decrementing. So use the one which makes the code more clear to understand.

In some languages like C++ it is considered good practice to use the pre-increment / pre-decrement operators if you don't need the value, since the post operators need to store the previous value in a temporary during the operation, therefore they require more instructions (additional copy) and can cause performance issues for complex types.

I'm no C expert but I don't think it really matters which you use in C, since there are no increment / decrement operators for large structs.

Excelcius
  • 1,680
  • 1
  • 14
  • 31