36

Even languages where you have explicit pointer manipulation like C it's always passed by value (you can pass them by reference but that's not the default behavior).

What is the benefit of this, why are so many languages passed by values and why are others passed by reference ? (I understand Haskell is passed by reference though I'm not sure).

  • 5
    void acceptEntireProgrammingLanguageByValue(C++); – Thomas Eding Jun 19 '12 at 23:24
  • 4
    It could be worse. Some old languages also allowed for call by name – hugomg Jun 19 '12 at 23:50
  • 25
    Actually, in C you can't pass by reference. You can pass a pointer by value, which is very similar to pass-by-reference, but not the same thing. In C++, though, you can pass by reference. – Mason Wheeler Jun 20 '12 at 0:27
  • @Mason Wheeler can you elaborate more or add some link, beacuase your statement is not clear to me as I'm not C/C++ guru, just a regular programmer, thanks – Betlista Nov 9 '12 at 11:38
  • 1
    @Betlista: With pass by reference, you can write a swap routine that looks like this: temp := a; a := b; b := temp; And when it returns, the values of a and b will be swapped. There's no way to do that in C; you have to pass pointers to a and b and the swap routine has to act on the values they point to. – Mason Wheeler Nov 9 '12 at 11:54
58

Pass by value is often safer than pass by reference, because you cannot accidentally modify the parameters to your method/function. This makes the language simpler to use, since you don't have to worry about the variables you give to a function. You know they won't be changed, and this is often what you expect.

However, if you want to modify the parameters, you need to have some explicit operation to make this clear (pass in a pointer). This will force all your callers to make the call slightly differently (&variable, in C) and this makes it explicit that the variable parameter may be changed.

So now you can assume that a function will not change your variable parameter, unless it is explicitly marked to do so (by requiring you to pass in a pointer). This is a safer and cleaner solution than the alternative: Assume everything can change your parameters, unless they specifically say they can't.

  • 4
    +1 Arrays decaying to pointers present a notable exception, but the overall explanation is good. – dasblinkenlight Jun 19 '12 at 21:29
  • 6
    @dasblinkenlight: arrays are a sore spot in C :( – Matthieu M. Jun 20 '12 at 7:11
55

Call-by-value and call-by-reference are implementation techniques that were mistaken for parameter-passing modes a long time ago.

In the beginning, there was FORTRAN. FORTRAN only had call-by-reference, since subroutines had to be able to modify their parameters, and computing cycles were too expensive to allow multiple parameter-passing modes, plus not enough was known about programming when FORTRAN was first defined.

ALGOL came up with call-by-name and call-by-value. Call-by-value was for things that were not supposed to be changed (input parameters). Call-by-name was for output parameters. Call-by-name turned out to be a major crock, and ALGOL 68 dropped it.

PASCAL provided call-by-value and call-by-reference. It did not provide any way for the programmer to tell the compiler that he was passing a large object (usually an array) by reference, to avoid blowing the parameter stack, but that the object should not be changed.

PASCAL added pointers to the language design lexicon.

C provided call-by-value, and simulated call-by-reference by defining a kludge operator to return a pointer to an arbitrary object in memory.

Later languages copied C, mostly because the designers had never seen anything else. This is probably why call-by-value is so popular.

C++ added a kludge on top of the C kludge to provide call-by-reference.

Now, as a direct result of call-by-value vs. call-by-reference vs. call-by-pointer-kludge, C and C++ (programmers) have horrible headaches with const pointers and pointers to const (read-only) objects.

Ada managed to avoid this whole nightmare.

Ada does not have explicit call-by-value vs. call-by-reference. Rather, Ada has in parameters (which may be read but not written), out parameters (which MUST be written before they can be read), and in out parameters, which may be read and written in any order. The compiler decides whether a particular parameter is passed by value or by reference: it is transparent to the programmer.

  • 1
    +1. This is the only answer I've seen on here so far that actually answers the question and makes sense and does not use it as a transparent excuse for a pro-FP rant. – Mason Wheeler Jun 20 '12 at 0:37
  • 11
    +1 for "Later languages copied C, mostly because the designers had never seen anything else." Every time I see a new language with 0-prefixed octal constants I die a little inside. – librik Jun 20 '12 at 11:58
  • 4
    This could be the first sentence of the Bible of programming: In the beginning, there was FORTRAN. – user39685 Jan 18 '13 at 15:06
  • 1
    With regard to ADA, if a global variable is passed to an in/out parameter, will the language prevent a nested call from examining or modifying it? If not, I would think there would be a clear difference between in/out and ref parameters. Personally, I'd like to see languages explicitly support all combinations of "in/out/in+out" and "by value/by ref/don't-care", so programmers could offer maximum clarity as to their intention but optimizers would have maximum flexibility in implementation [so long as it jibed with programmer intent]. – supercat Jun 12 '14 at 15:32
  • 2
    @Neikos There's also the fact that the 0 prefix is inconsistent with every other non-base ten prefix. That may be somewhat excusable in C (and mostly source-compatible languages, e.g. C++, Objective C), if octal was the only alternative base when introduced, but when more modern languages use both 0x and 0 from the start, it just makes them look poorly thought out. – 8bittree Oct 6 '16 at 14:00
13

Pass by reference allows for very subtle unintended side effects that are very difficult to next to impossible to trace down when they start causing the unintended behavior.

Pass by value, especially final, static or const input parameters makes this entire class of bugs disappear.

Immutable languages are even more deterministic and easier to reason about and understand what is going in and what is expected to be coming out of a function.

  • 7
    It's one of those things that you figure out after trying to debug 'ancient' VB code where everything is by reference as default. – jfrankcarr Jun 19 '12 at 19:59
  • Maybe it's just that my background is different, but I have no idea what sort of "very subtle unintended side effects that are very difficult to next to impossible to trace down" you're talking about. I'm used to Pascal, where by-value is the default but by-reference can be used by explicitly marking the parameter, (basically the same model as C#,) and I've never had that cause problems for me. I can see how it would be problematic in "ancient VB" where by-ref is the default, but when by-ref is opt-in, it makes you think about it while you're writing it. – Mason Wheeler Jun 20 '12 at 0:32
  • 4
    @MasonWheeler what about newbies that come along behind you and just copy what you did without understanding it and start manipulating that state all over the place indirectly, real world happens all the time. Less indirection is a good thing. Immutable is best. – user7519 Jun 20 '12 at 0:47
  • 1
    @MasonWheeler The simple alias examples, like the Swap hacks that don't use a temporary variable, though not likely to be a problem themselves, show how hard a more complex example might be to debug. – Mark Hurd Jun 28 '12 at 2:16
  • 1
    @MasonWheeler: The classic example in FORTRAN, which led to the saying "Variables won't; constants aren't", would be passing a floating-point constant like 3.0 to a function which modifies the passed-in parameter. For any floating-point constant that was passed to a function the system would create a "hidden" variable that was initialized with the proper value and could be passed to functions. If the function added 1.0 to its parameter, an arbitrary subset of 3.0's in the program could suddenly become 4.0's. – supercat Oct 5 '16 at 18:10
8

Why are so many languages passed by value?

The point of breaking up large programs into small subroutines is that you can reason about the subroutines independently. Pass-by-reference breaks this property. (As does shared mutable state.)

Even languages where you have explicit pointer manipulation like C it's always passed by value (you can pass them by reference but that's not the default behavior).

Actually, C is always pass-by-value, never pass-by-reference. You can take an address of something and pass that address, but the address will still be passed by value.

What is the benefit of this, why are so many languages passed by values and why are others passed by reference ?

There are two main reasons for using pass-by-reference:

  1. simulating multiple return values
  2. efficiency

Personally, I think #1 is bogus: it's almost always an excuse for bad API and/or language design:

  1. If you need multiple return values, don't simulate them, just use a language which supports them.
  2. You can just as well simulate multiple return values by packaging them into some lightweight data structure such as a tuple. This works particularly well if the language supports pattern matching or destructuring bind. E.g. Ruby:

    def foo
      # This is actually just a single return value, an array: [1, 2, 3]
      return 1, 2, 3
    end
    
    # Ruby supports destructuring bind for arrays: a, b, c = [1, 2, 3]
    one, two, three = foo
    
  3. Oftentimes, you don't even need multiple return values. For example, one popular pattern is that the subroutine returns an error code and the actual result is written back by reference. Instead, you should just throw an exception if the error is unexpected or return an Either<Exception, T> if the error is expected. Another pattern is to return a boolean which tells whether the operation was successful and return the actual result by reference. Again, if the failure is unexpected, you should throw an exception instead, if the failure is expected, e.g. when looking up a value in a dictionary, you should return a Maybe<T> instead.

Pass-by-reference may be more efficient than pass-by-value, because you don't have to copy the value.

(I understand Haskell is passed by reference though I'm not sure).

No, Haskell is not pass-by-reference. Nor is it pass-by-value. Pass-by-reference and pass-by-value are both strict evaluation strategies, but Haskell is non-strict.

In fact, the Haskell Specification doesn't specify any particular evaluation strategy. Most Hakell implementations use a mixture of call-by-name and call-by-need (a variant of call-by-name with memoization), but the standard doesn't mandate this.

Note that even for strict languages, it doesn't make sense to distinguish between pass-by-reference or pass-by-value for functional languages since the difference between them can only be observed if you mutate the reference. Therefore, the implementor is free to chose between the two, without breaking the semantics of the language.

  • 9
    "If you need multiple return values, don't simulate them, just use a language which supports them." This is a bit of a strange thing to say. It's basically saying "if your language can do everything you need, but one feature that you'll probably need in less than 1% of your code--but you still will need it for that 1%--can't be done in a particularly clean way, then your language isn't good enough for your project and you should rewrite the whole thing in another language." Sorry, but that's just plain ridiculous. – Mason Wheeler Jun 20 '12 at 0:35
  • +1 I totally agree with this point The point of breaking up large programs into small subroutines is that you can reason about the subroutines independently. Pass-by-reference breaks this property. (As does shared mutable state.) – Rémi May 1 '14 at 20:42
3

There is different behavior depending on the calling model of the language, the type of arguments and the memory models of the language.

With simple native types, passing by value allow you to pass the value by the registers. That can be very fast since the value aren't need to be loaded from memory neither save back. Similar optimization is also possible simply by reusing the memory used by the argument once the callee is done with it, without risking to mess with the caller copy of the object. If the argument was a temporary object, you would have probably save a full copy doing so (C++11 make this kind of optimization even more obvious with the new right-reference and its move semantic).

In a lot of OO languages (C++ is more an exception in this context), you cannot passed an object by value. You are force to pass it by reference. This make the code polymorphic by default and are more inline with the notion of instances proper to OO. Also, if you want to pass by value, you must make a copy yourself, acknowledging the cost of performance that generated such action. In this case, the language choose for you the approach that is more likely to give you the best performance.

In case of functional languages, I guess passing by value or reference is simply a question of optimization. Since the functions in such language are pure and so free of side effects, there is really no reason to copy the value except for speed. I'm even pretty sure that such language often shared the same copy of objects with the same values, a possibility available only if you used a pass by (const) reference semantic. Python also used this trick for integer and common strings (like methods and class names), explaining why integer and strings are constant objects in Python. This also help to optimize the code again, by allowing for example pointer comparaison instead of content comparaison, and doing lazy evaluation of some internal data.

2

You can pass an expression by value, it's natural. Passing expression by (temporary) reference is... weird.

  • 1
    Also, passing expression by temporary reference can lead to bad bugs (in stateful language), when you happily change it (since it's just temporary), but then it backfires when you actually pass a variable, and you must devise ugly workaround like passing foo+0 instead of foo. – herby Jun 19 '12 at 21:23
2

If you pass by reference, then you are effectively always working with global values, with all of the problems of globals (namely scope and unintended side effects).

References, just like globals, are sometimes beneficial, but they shouldn't be your first choice.

  • 3
    I assume you meant pass by reference in the first sentence? – jk. Jun 19 '12 at 20:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.