4

What are the main differences, if any, of Python's argument passing rules vs C#'s argument passing rules?

I'm very familiar with Python and only starting to learn C#. I was wondering if I could think of the rule set as to when an object is passed by reference or by value the same for C# as it is in Python, or if there are some key differences I need to keep in mind.

Max
  • 261
  • 1
  • 4
  • 9
  • passed by reference in python, from when???? – user1655481 Sep 15 '12 at 14:23
  • Python passes reference to objects by value: [link](http://stackoverflow.com/questions/534375/passing-values-in-python) – Max Sep 15 '12 at 14:40
  • I know you must be talking about some list appending, I haven't seen the link but I guess it must be.... – user1655481 Sep 15 '12 at 14:43
  • @Max: Right. But passing the reference value simply means passing by reference. Simply said, 4 bytes are passed, and the bytes are the address of the object that is passed by reference. – pepr Sep 15 '12 at 15:00
  • @pepr **No**, that is not pass by reference. The "reference" in "pass by reference" refers to a different concept, namely to something which allows you to manipulate storage locations (variables, object attributes, slots in collections, etc.) and does not exist in Python. Pass by reference permits `def f(x): x = whatever` to have an effect. –  Sep 15 '12 at 16:01
  • @delnan: Passing by value means that you copy the value. This is not Python case. The value of the object is not copied. Passing by value also means that you cannot modify the outer object from inside the function. Technically, passing by reference means copying the address of the target object. This is the Python case. The problem is hidden in question *What is a variable in Python, and say in C, and in mathematics*. And **yes**, the passed arguments allows you to manipulate outer object in Python. The problem is that **the assignment operator does something else than you expect**. – pepr Sep 15 '12 at 17:08
  • Visual explanation added at http://stackoverflow.com/a/12438316/1346705 – pepr Sep 15 '12 at 18:18

5 Answers5

7

C# passes parameters by value unless you specify that you want it differently. If the parameter type is a struct, its value is copied, otherwise the reference to the object is copied. The same goes for return values.

You can modify this behavior using the ref or out modifier, which must be specified both in the method declaration and in the method call. Both change the behavior for that parameter to pass-by-reference. That means you can no longer pass in more complex expressions. The difference between ref and out is that when passing a variable to a ref parameter, it must have been initialized already, while a variable passed to an out parameter doesn't have to be initialized. In the method, the out parameter is treated as uninitialized variable and must be assigned a value before returning.

Wormbo
  • 4,978
  • 2
  • 21
  • 41
  • 1
    About ref, OP may find [this question](http://stackoverflow.com/q/4656184/704144) interesting. – Şafak Gür Sep 15 '12 at 14:55
  • Selected as the answer since it's the only one that's telling me about how passing parameters in C# works. – Max Sep 15 '12 at 16:20
4

Python always uses pass by reference values. There is no exception. Any variable assignment means assigning the reference value. No exception. Any variable is the name bound to the reference value. Always.

You can think about reference as about the address of the target object that is automatically dereferenced when used. This way it seems you work directly with the target object. But there always is a reference in between, one step more to jump to the target.

Updated -- here is a wanted example that proves passing by reference:

Illustrated example of passing the argument

If the argument were passed by value, the outer lst could not be modified. The green are the target objects (the black is the value stored inside, the red is the object type), the yellow is the memory with the reference value inside -- drawn as the arrow. The blue solid arrow is the reference value that was passed to the function (via the dashed blue arrow path). The uggly dark yellow is the internal dictionary. (It actually could be drawn also as a green elipse. The colour and the shape only says it is internal.)

Updated -- related to fgb's comment on passing by reference example swap(a, b) and the delnan's comment on imposibility to write the swap.

In compiled languages, variable is a memory space that is capable to capture the value of the type. In Python, variable is a name (captured internally as a string) bound to the reference variable that holds the reference value to the target object. The name of the variable is the key in the internal dictionary, the value part of that dictionary item stores the reference value to the target.

The purpose of the swap in other languages is to swap the content of the passed variables, i.e. swap the content of the memory spaces. This can be done also for Python, but only for variables that can be modified--meaning the content of their memory space can be modified. This holds only for modifiable container types. A simple variable in that sense is always constant, even though its name can be reused for another purpose.

If the function should create some new object, the only way to get it outside is or via a container type argument, or via the Python return command. However, the Python return syntactically look as if it was able to pass outside more than one argument. Actually, the multiple values passed outside form a tuple, but the tuple can be syntactically assigned to more outer Python variables.

Update related to the simulation of variables as they are perceived in other languages. The memory space is simulated by a single-element lists -- i.e. one more level of indirection. Then the swap(a, b) can be written as in other languages. The only strange thing is that we have to use the element of the list as the reference to the value of the simulated variable. The reason for neccessity to simulate the other-languate variables this way is that only containers (a subset of them) are the only objects in Python that can be modified:

>>> def swap(a, b):
...   x = a[0]
...   a[0] = b[0]
...   b[0] = x
...
>>> var1 = ['content1']
>>> var2 = ['content2']
>>> var1
['content1']
>>> var2
['content2']
>>> id(var1)
35956296L
>>> id(var2)
35957064L
>>> swap(var1, var2)
>>> var1
['content2']
>>> var2
['content1']
>>> id(var1)
35956296L
>>> id(var2)
35957064L

Notice that the now the var1 and var2 simulate the look of "normal" variables in classic languages. The swap changes their content, but the addresses remain the same.

For modifiable object--as the lists are for example--you can write exactly the same swap(a, b) as in other languages:

>>> def swap(a, b):
...   x = a[:]
...   a[:] = b[:]
...   b[:] = x[:]
...
>>> lst1 = ['a1', 'b1', 'c1']
>>> lst2 = ['a2', 'b2', 'c2']
>>> lst1
['a1', 'b1', 'c1']
>>> lst2
['a2', 'b2', 'c2']
>>> id(lst1)
35957320L
>>> id(lst2)
35873160L
>>> swap(lst1, lst2)
>>> lst1
['a2', 'b2', 'c2']
>>> lst2
['a1', 'b1', 'c1']
>>> id(lst1)
35957320L
>>> id(lst2)
35873160L

Notice that the multiple assignment like a[:] = b[:] must be used to express copying of the content of the lists.

pepr
  • 20,112
  • 15
  • 76
  • 139
  • 1
    The one that downvoted is malevolent or mistaken or he/she does not know Python. It can be proven by examples that what I say is true. However, you cannot prove that Python passes by value. – pepr Sep 15 '12 at 14:54
  • I'm not the downvoter, but "assigning the reference value" isn't the same as pass-by-reference. Looking at this question: http://stackoverflow.com/questions/986006/python-how-do-i-pass-a-variable-by-reference it sounds like Python *does* use pass by value, where (like C#) the value of a variable is never an actual object, only a reference. – Jon Skeet Sep 15 '12 at 15:00
  • 1
    @JonSkeet: Even though the referenced question says otherwise, it is very cofusing. It is a play on the words whether passing by reference means passing the reference value. Of course. But the reference value is just the address of the object. Passing by reference means passing the address of the object. This way is used also in Python. Passing the argument to the function actually means assigning the local variable of the function the thing from outside. This is the same kind of assignment as any other assignment in Python. – pepr Sep 15 '12 at 15:12
  • @pepr: You said: "It can be proven by examples that what I say is true." Okay, then prove it! You also said: "However, you cannot prove that Python passes by value." I *did* provide an example of pass-by-value in Python. Granted, a single example is not a proof, you would have to consult the Python Language Specification for that. On the other hand, neither you nor someone else has been able to come up with an example of pass-by-reference in Python, so I view that as a strong indication that I am right. – Jörg W Mittag Sep 15 '12 at 15:12
  • 1
    If it's the same kind of assignment as any other, then it's pass-by-value. Pass-by-reference means that the passed/local variables are references to each other. Any change to the variables (including assignment) has the same effect no matter which variable is used. – fgb Sep 15 '12 at 15:19
  • This example does *not* demonstrate pass-by-reference. It demonstrates that lists are mutable. But that is not the question. Nobody ever claimed Python was a purely functional language. This is completely orthogonal to pass-by-reference vs. pass-by-value. That's just how shared mutable state works. – Jörg W Mittag Sep 15 '12 at 15:24
  • @fgb: While I understand your confusion... Any assignment in Python means copying a reference to the target object. This is how Python variables are implemented. – pepr Sep 15 '12 at 15:25
  • 3
    @pepr: You wrote: "Any assignment in Python means copying a reference to the target object." Well, that's the *definition* of pass-by-value. – Jörg W Mittag Sep 15 '12 at 15:26
  • 1
    @JörgWMittag: When passing by value in any programming language, the rule is that you cannot modify the outer object. This is one of the reasons why passing by value is used. The pass-by-value means that you copy the value, not the reference. If you have integer on 4 bytes, you just copy the four bytes with the content. If you have array with 1000 element, then passing by value means you copy the content of all the 1000 elements. – pepr Sep 15 '12 at 15:26
  • @pepr I'm not confused. I know how variables and references work. You're just repeating things we all know that have nothing to do with the argument. – fgb Sep 15 '12 at 15:30
  • 1
    @fgb: In Python, you never copy the 1000 elements unless you explicitly say that. You never copy the elements only because you pass it as argument to the function. – pepr Sep 15 '12 at 15:36
  • @pepr: No, passing by value means that modification to the parameter doesn't modify the argument. That's not the same thing as saying that modifying *the object the parameter refers to* isn't seen via the argument. Itdoes sound like Python is like C# in this respect. Please read http://pobox.com/~skeet/csharp/parameters.html for the C# version. Pass by reference really is different. – Jon Skeet Sep 15 '12 at 16:13
  • @pepr: In the code that you've given, what would happen if you wrote: `x = ['modified']` instead of `x.append('modified')`? Would the caller see that change to the value of `x`? If so, that's a good example of pass by reference. If not, then it's using pass by value - the value of the argument (`lst`) *is* a reference, which is then passed by value. – Jon Skeet Sep 15 '12 at 16:16
  • @JonSkeet: Good point. The problem is that when you do `x = ['aaaa']` you reuse the name `x` for binding with the reference to another object `['aaaa']`. You are not using the reference that was passed as the argument. In other word, you forget the binding between the *local variable `x`* and you use the `x` for another purpose. In Python, `x` is simply a string that is bound to a reference variable. You rebind the string to another reference variable in your example. – pepr Sep 15 '12 at 16:24
  • @pepr: Well, I can't speak for Python, but that sounds ever so much like the way pass by value works in both Java and C#... except there you'd say there's just one `x` variable, and you're giving it a different value. In every case, the value of `x` isn't an object, it's a reference. – Jon Skeet Sep 15 '12 at 16:40
  • @pepr: Reading the Python documentation, section 5.3.4 talks about: " Otherwise, the value of the argument is placed in the slot, filling it" which again sounds like pass by value to me. It's the *value* of the argument which is used. Likewise "A function call always assigns values to all parameters mentioned in the parameter list, either from position arguments, from keyword arguments, or from default values" in section 7.6. I've read nothing in the Python documentation so far suggesting pass by reference semantics - and your example definitely doesn't demonstrate it either. – Jon Skeet Sep 15 '12 at 16:47
  • 1
    @JonSkeet: Well, the slot is actually a reference variable. The value is the reference value. When working with reference values, you are pasing by references. There is one more moment that causes confusion. Any reference variable behaves (in any language) as if you worked directly with the target object (because of the automatic dereferencing). Anyway, the technical difference is that there is one level of indirection. For my example... How the outer object could be modified if it was not passed by reference? – pepr Sep 15 '12 at 16:58
  • 4
    @pepr: Because the reference would be passed by value - that's exactly the way that C# and Java works. To be honest, I'm coming to the conclusion that the traditional terminology of "pass by value" and "pass by reference" may simply be unhelpful for Python. It's easy to see how they work for C# and Java (as examples I'm familiar with) as the value of a variable is very clearly defined - whereas in Python there's the binding and the variable, which sound like they're different things, introducing confusion... – Jon Skeet Sep 15 '12 at 17:03
  • 1
    @JonSkeet I agree. Python should have its own name for how it passes variables. Its behavior is very familiar but the underlying logic has lead to much confusion. – Max Sep 15 '12 at 17:10
  • @Max: It was confusing also for me in the past. Actually, the source of confusion disappears when you focus on answering the questions: *What a variable in Python means?* and *What the assignment in Python means?*. A variable in classical languages means a memory space big enough to store the values of the type. Its name is typically lost during the compilation (converted to the address or the like). Creating a variable in Python means to store its name as a string plus copy 4 bytes -- the reference value. The assignment is the mean to do that. Nothing more, nothing less. – pepr Sep 15 '12 at 17:27
  • 1
    This answer is wrong, and this: `the arguments are actually the copied reference values. But this is excactly what is named passing by reference in all other languages.` is also wrong. What you are describing there is passing a reference by value, which is not the same as pass by reference. An argument passed by reference is an alias for the passed variable, and assignments in the function are visible in the caller. Your list example demonstrates mutability and the passing convention is not relevant. – Lee Sep 15 '12 at 19:08
  • @Lee: OK. What form takes *an alias for the passed variable* when passing by reference (in other languages)? In some sense, the reference value, the pointer value, and the address of the target object is the same. When passing by reference, you always have to pass the address (technically). How would you call the kind of passing the argument used in the example? Notice that assignment operator in Python just copies internally the reference value. It is not the same as in classical compiled languages where the assignment operator causes copying the memory of the right-side object. – pepr Sep 15 '12 at 19:37
  • 1
    @pepr - Your answer describes passing references by value. `lst` is a reference to a list, and it is copied (i.e. passed by value) into the local variable `x` in `func`. `func` can mutate the passed list through its reference, but it cannot change the list pointed to by `lst` in the caller. This is the also way reference types are passed by default in C#, however you can also pass them by reference using the `ref` or `out` keywords, and this is why it is important to make the distinction between pass by reference, and passing references by value. – Lee Sep 15 '12 at 20:34
  • Without reading all the comments: You are right that the common meaning of pass-by-value does not fit Python semantics, and that the data model is quite different from, say, C and C++. Nevertheless, I must object. As I have explained before, pass by reference implies (a) the presence of *storage locations* and (b) the ability to have a "reference" towards such a storage location. Python's data model can be stated in a way which involved storage locations, where all storage locations contain "references" to values/objects. But there simply is no equivalent to (b). You cannot write `swap`. –  Sep 15 '12 at 20:37
  • 1
    To contrast, let's define references for Python: You can, in addition to regular "names" which are references to objects, also have something-else-mumble-mumble (semm). Let's denote them as `x&` as opposed to `x`. Then, `ref& <- x` bind the semm to a variable, `ref& <- obj.attr` binds the semm to an object attribute, and `ref& <- arre[key]` binds the semm to a slot in a collection. `ref& = ...` now changes which object that name, object attribute, or collection slot refers to. `def swap(x&, y&): x&, y& = x&, y&` now has an effect and is called as `swap(x, a[i])` rather than `swap(1, ["foo"])`. –  Sep 15 '12 at 20:44
  • And none of this has anything to do with whether programs are compiled or interpreted. That assignment and argument passing doesn't copy objects is simply a matter of whether objects have *reference semantics* or *value semantics*. In Python, everything has reference semantics, that's why things are the way they are. But reference semantics also exists in compiled languages (RPython is a compiled language with reference semantics *exclusively*, and in C and C++ you have pointers). –  Sep 15 '12 at 20:48
  • @Lee: I see what you mean. But if we think in terms of single thread of activity, there is no way to make the target objects named as `lst` outside and `x` inside different. Whenever I modify the list, I modify the same list known inside and outside. When talking about *pass by reference*, I mean the way used in classical compiled languages. *The object is not copied, only the reference is passed, and the object can be modified from inside.* It works this way say in Pascal, modern C, C++. Passing the result out is done via `return` or via pointers in C or C++. – pepr Sep 15 '12 at 20:55
  • @pepr - Pass by reference in C++ is not the same as your description of how things work in Python - assignment to a ref parameter in C++ is visible in the caller. e.g. `void modify(int &i) { i = 10; }`. There is no way to write such a function in Python. C does not support pass by reference, only passing pointers, which themselves are passed by value. – Lee Sep 15 '12 at 21:12
  • @delnan: +1 I see. But the the reason for not being able to write `swap` in Python that looks syntactically the same way as in other languages only means that there is not pointer-type variable available (directly). If `out` in C# means I can use the uninitialized variable passed inside (correct me, I am not good in C#). It means you are creating the initialized variable in two phases: 1) memory allocation outside, 2) its content assigned inside the function/procedure. However, in Python only collection objects can be modified. This way, it is always closely related to the assignment. – pepr Sep 15 '12 at 21:21
  • That way, Python must use the *multiple assignment* for the output purpose (syntactically). The created simple objects must be created in a single phase. Then `a, b = b, a` is the way to swap the object. Anyway if `c = a` was done before, it will point to the same object as `b` after the swap. To simulate the *variables as filled memory space* in Python, you always have to do with one indirection as the simple values are always constant. And in C and C++ you have also references (beside the pointers). – pepr Sep 15 '12 at 21:26
  • (1) C#'s `out` indeed supports filling uninitialized variables, but there is nothing which prevents such a feature in Python -- there already are uninitialized local variables (try `print(x); x = 1` in a function). (2) I don't know what point you are trying to make with the latest comment. (3) The definition of pass by reference you cite in the 20:55 comment is wrong. Not copying the object and modifying it can be achieved with *any* indirection, and pass by reference references allow you to also replace the value/object wholesale (instead of just changing parts of it). –  Sep 15 '12 at 21:43
  • @Lee and @delnan: Of course, the constant object cannot be modified. But if you accept that there can be constant objects, the `swap(a, b)` can be written for the rest of the objects (i.e. those that can be modified) even in Python. You cannot write `swap(a, b)` for constant objects in other languages either. (The `print(x); x = 1` is errorneous. The error is only not discovered during compile time.) For the *indirection* I was speaking about it as about simulation of a variable as it is understood in the classical languages (say using a single-element list as the variable). – pepr Sep 15 '12 at 23:01
  • @pepr - How would you write a (void) function `swap(a, b)` in Python which swaps the values of its arguments? – Lee Sep 15 '12 at 23:31
  • @delnan: I have updated the anwer to show what I mean by the mentioned indirection. At Lee, frankly, I am using C++ too long. I thought that references were added to C later. I did not checked. Anyway, you can have references to constant objects also in C++. Then the assignment via the reference even does not compile. In Python, simple objects are constant, the most of the containers are not constant. – pepr Sep 15 '12 at 23:32
  • Your swap example does not swap its arguments, it merely swaps the first elements of two list arguments. In C# you could write it as `void Swap(ref T first, ref T second) { T temp = first; first = second; second = first; }`. You cannot write such a function in Python (except possibly using some low-level direct memory manipulation) since you can't pass parameters by reference. – Lee Sep 15 '12 at 23:39
  • @Lee: Of course you can never swap strings in Python, because you cannot modify strings. You can never swap constant objects. Anyway, you can swap lists. – pepr Sep 15 '12 at 23:52
  • @pepr You cannot swap lists. In fact, you cannot swap anything but references (in the Python sense, not the C++ sense). You can swap references stored in a sequence/mapping at a specific index/key, in local or global variables, and in object attributes, but you cannot swap objects themselves. Your example does that to work around the fact that you can't have a reference to a storage location, only a reference to an object (and then treat items or attributes of that object as storage locations via a convention). But pass by reference means that you **do have** references to storage locations. –  Sep 16 '12 at 00:01
  • In other words, you only show how to *emulate* pass by reference in Python. Nobody ever said you can't emulate it. But you *have* to emulate it, precisely because Python does not pass by reference. –  Sep 16 '12 at 00:06
  • @delnan: See the updated answer for exactly this. The last `swap` swaps the contents of the lists. What is the list and the content of the list in our opinion? The lists in Python are indeed the collection of references to the elements (technically). But from abstract point of view, the lists contain the values. Anyway, the values are the result of automatic dereferencing. The list is a dynamic array of references. The `swap` swaps the contents of the lists. Right? The first list then contains what the second list contained, and vice versa. – pepr Sep 16 '12 at 00:10
  • @pepr And about the `print(x); x = 1` example not being a compile time error: That's solely due to Python being dynamically typed and not requiring a *compile-time* error for *anything*. The variable is uninitialized; a C# implementation does static analysis to make sure it has a value, a Python implementation checks it dynamically. Neither allows reading an uninitialzed variable, and both could feature respectively do feature a variant of pass by reference which accepts uninitialized variables by not allowing the called function to read it either. –  Sep 16 '12 at 00:11
  • Well, but Python does not know the containers that really contain say the strings. Actually, Python documentation says nothing about references. It is related to technical implementation of variables. The same way you can discuss that Python does not support integer variables, and you would be right in the technical sense. – pepr Sep 16 '12 at 00:14
  • @pepr No, the lists are still distinct despite each now having the items the other one had before. `id` allows us to discriminate them. And this is not just theoretical or esoteric; identifying objects by their ID happens quite frequently. And apart from that, pass by reference also includes swapping variables, and as we all know that cannot happen. Just swapping object contents does not fall under pass by reference, as we already established any indirection allows this. –  Sep 16 '12 at 00:15
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/16736/discussion-between-delnan-and-pepr) –  Sep 16 '12 at 00:16
3

The problem with calling Python a "pass-by-value" or "pass-by-reference" language and comparing to C, C#, etc. is that Python has a different conception of how data is referred to. Python does not fit easily into a conventional by-value or by-reference dichotomy, leading to confusion and the "It's call-by-value!" "No, it's call-by-reference, and I can prove it!" "NO, YOU MAROON, it's obviously call-by-value!" endless loop witnessed above.

The truth is, it's neither. Python uses call-by-sharing (aka call-by-object). Sometimes this appears to be a by-value strategy (e.g. when dealing with scalar values like int, float, and str), and sometimes like a by-reference strategy (e.g. when dealing with structured values like list, dict, set, and object). David Goodger's Code like a Pythonista sums this up beautifully as "other languages have variables; Python has names." As a bonus, he provides clear graphics illustrating the difference.

Under the covers, call-by-sharing is implemented more like call-by-reference (as the mutate a float example mentioned by Noctis Skytower demonstrates.) But if you think of it as call-by-reference, you will go off the tracks rapidly, because while references are the implementation, they're not the exposed semantics.

C#, in contrast, uses either call-by-value or call-by-reference--though one might argue that the out option represents a tweak above-and-beyond pure call-by-reference as seen in C, Pascal, etc.

So Python and C# are very different indeed--at an architectural level, at any rate. In practice, the combination of by-value and by-reference would allow you to create programs that operate very similarly to call-by-sharing--albeit with a tricky little Devil living in the details and corner-cases.

If you're interested in understanding different languages' parameter passing strategies in a comparative context, Wikipedia's page on expression evaluation strategy is worth a read. While it's not exhaustive (there are many ways to skin this particular cat!), it ably covers a range of the most important ones, plus some interesting uncommon variations.

Community
  • 1
  • 1
Jonathan Eunice
  • 21,653
  • 6
  • 75
  • 77
  • 1
    call-by-sharing is simply the name given by Barbara Liskov for the specific kind of pass-by-value (where the value being passed is *always* implicitly a pointer) implemented in CLU and later in languages like Smalltalk, Objective-C, Java, C#, Python, Ruby, Self, Newspeak, Io, Ioke, Seph and so forth. Call-by-sharing *is* pass-by-value. And it is what Java and by default C# use as well, at least for reference types. – Jörg W Mittag Sep 15 '12 at 21:32
  • 2
    My +1 @JörgWMittag: The problem with that is that you think about the variable and name it after the passing the address. But the address is not the argument value. Also, when passing arguments that occupy a lot of memory, the *pass-by-value* means copying that big amount of memory. Historically, pass by reference as the opposite was or used to avoid copying, or to allow the output through modification of the passed variable. – pepr Sep 15 '12 at 22:52
  • 2
    Sure, Python is call-by-value. In exactly the same way that *all* call-by-reference is really call-by-value. At the CPU register level, everything is a value. Even references. "Ha! Call-by-value! Call-by-value! QED!" Next, let's have the debate where objects are nothing more than a little sugar-coating on Turing Machines. On second thought--no. Let's be serious. When we organize things for different intent and effect, we give them different names to signify the different semantics and outcomes. Call-by-{reference,sharing,copy-back,etc.} are NOT usefully reducible to call-by-value. – Jonathan Eunice Sep 16 '12 at 03:28
  • 1
    Python and C# (without using `ref` or `out`) exhibit the exact same semantics. So, why is C# pass-by-value and Python isn't? – Jörg W Mittag Sep 16 '12 at 08:05
  • @JonathanEunice: Thank you for adding your explanation on how Python really works. It is a great insight to realize that pass-by-reference is actually a form of pass-by-value. As you pointed out, it is "NOT usefully reducible to call-by-value." – Noctis Skytower Sep 18 '12 at 16:50
  • @pepr: Good job at pointing out that pass-by-value creates copies of data in memory whereas pass-by-reference just creates a pointer to what is already in memory! – Noctis Skytower Sep 18 '12 at 16:50
  • @JörgWMittag: When you pass a structure composed of 20 bytes to a function in C# (without `ref` and `out`), how many bytes are copied? – pepr Sep 19 '12 at 20:38
  • @pepr: When you pass a value type as an argument to a subroutine in C#, the entire value gets copied into the parameter, *just like in Python*. When you pass a reference type as an argument to a subroutine in C#, only the reference gets copied into the parameter, *just like in Python*. – Jörg W Mittag Sep 19 '12 at 23:45
  • @JörgWMittag: When you pass a value type as an argument, the value is *not copied* in Python. Only the reference value to the argument object is passed. You can check `id()` of the argument outside the call and inside the function -- you will get the same identification. – pepr Sep 21 '12 at 10:37
  • Another way to express this idea would be to say that if all objects in Python were mutable, and if the assignment operator always mutated objects instead of re-binding variable names, then Python would be (unambiguously) a call-by-reference language. This shows how the by-reference/by-value distinction is inadequate for Python: it's supposed to be a distinction between _evaluation_ styles, but the semantics of _assignment_ (statements) are what actually make the difference. – senderle Nov 08 '12 at 14:44
2

Python is always pass-by-value:

def is_python_pass_by_value(foo):
    foo[0] = 'More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.'
    foo = ['Python is not pass-by-reference.']

quux = ['Yes, of course, Python *is* pass-by-value!']

is_python_pass_by_value(quux)

print(quux[0])
# More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.

C# is pass-by-value by default, but also supports pass-by-reference if both at the method declaration site and at the call site the ref keyword is used:

struct MutableCell
{
    public string value;
}

class Program
{
    static void IsCSharpPassByValue(string[] foo, MutableCell bar, ref string baz, ref MutableCell qux)
    {
        foo[0] = "More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.";
        foo = new string[] { "C# is not pass-by-reference." };

        bar.value = "For value types, it is *not* call-by-sharing.";
        bar = new MutableCell { value = "And also not pass-by-reference." };

        baz = "It also supports pass-by-reference if explicitly requested.";

        qux = new MutableCell { value = "Pass-by-reference is supported for value types as well." };
    }

    static void Main(string[] args)
    {
        var quux = new string[] { "Yes, of course, C# *is* pass-by-value!" };

        var corge = new MutableCell { value = "For value types it is pure pass-by-value." };

        var grault = "This string will vanish because of pass-by-reference.";

        var garply = new MutableCell { value = "This string will vanish because of pass-by-reference." };

        IsCSharpPassByValue(quux, corge, ref grault, ref garply);

        Console.WriteLine(quux[0]);
        // More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.

        Console.WriteLine(corge.value);
        // For value types it is pure pass-by-value.

        Console.WriteLine(grault);
        // It also supports pass-by-reference if explicitly requested.

        Console.WriteLine(garply.value);
        // Pass-by-reference is supported for value types as well.
    }
}

As you can see, without explicit annotation with the ref keyword, C# behaves exactly like Python. Value types are pass-by-value where the value being passed is the object itself, Reference types are pass-by-value where the value being passed is a pointer to the object (also known as call-by-object-sharing).

Python does not support mutable value types (probably a good thing), so it is impossible to observe the distinction between pass-value-by-value and pass-pointer-by-value, so you can just treat everything as pass-pointer-by-value and greatly simplify your mental model.

C# also supports out parameters. They are also pass-by-reference, but it is guaranteed that the callee will never read from them, only write, so the caller does not need to initialize them beforehand. They are used to simulate multiple return values, when you would use a tuple in Python. They are kind-of like one-way pass-by-reference.

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
  • 2
    But keep in mind, that even if Python uses pass-by-value, you can change input parameters if they are complex types like dict. Changing them inside your function will change the original value. – Gregor Sep 15 '12 at 14:27
  • 2
    @Gregor: Well, that's just mutable state. If you mutate a mutable object, it changes, there's nothing surprising there. Python is not a purely functional language, and neither is C#. – Jörg W Mittag Sep 15 '12 at 14:30
  • 1
    @JörgWMittag: Python never uses pass by value. The opposite is true. – pepr Sep 15 '12 at 14:47
  • @pepr: I added a code snippet demonstrating pass-by-value in Python. Note: I tested it in Python 2.7 only, but I would be very surprised to see a different result in Python 3. – Jörg W Mittag Sep 15 '12 at 14:58
  • @JörgWMittag are (class) objects in C# not passed by reference by default? – Max Sep 15 '12 at 14:58
  • @Max: No, C# *only* passes by reference if *both* the author of the called method *and* the author of the calling code *explicitly* request by adding the `ref` keyword both into the parameter list and the argument list. – Jörg W Mittag Sep 15 '12 at 15:01
  • @Max: No, objects aren't passed at all. References and value type values are passed - by default, they're passed by value, but can also be passed by reference. See http://pobox.com/~skeet/csharp/parameters.html – Jon Skeet Sep 15 '12 at 15:01
  • 1
    @JörgWMittag: This is not the proof. Strings in Python are immutable. This way, assigning `foo` inside the function body means that the `foo` name is bound to another reference. The original object passed by reference cannot be changed. Another object is created by the internal assignment. However, you have no access to the new value. Try to pass a list instead, and then modify it inside. – pepr Sep 15 '12 at 15:04
  • 3
    @Max: The difference between reference types (instances of classes) and value types (instances of structs) is not *how* they are passed but *what* is passed: for reference types the *value* being passed is (a copy of) a *pointer* to the object, for value types the value being passed is (a copy of) the object *itself*. This is completely orthogonal to pass-by-value vs. pass-by-reference: you can pass reference types by value (the default) or value types by reference. – Jörg W Mittag Sep 15 '12 at 15:04
  • 1
    @pepr: Mutability or immutability is completely irrelevant here. If I assign to a variable inside the callee, and that changes that same *variable* (*not* object!) inside the caller, then that is pass-by-reference, otherwise it isn't. In fact, that's pretty much the *definition* of pass-by-reference. – Jörg W Mittag Sep 15 '12 at 15:06
  • 3
    In python, values are sorta-kinda passed in by reference. Python *assignment* doesn't replace the referenced object, it creates a new reference and stores the latter. Python values (objects) themselves live on a heap. – Martijn Pieters Sep 15 '12 at 15:06
  • 1
    @JörgWMittag: Sorry, but you are wrong. The definition of a reference value is simple -- it is a value that gives you access to the target object using the automatical dereferencing when used. Reference value is kind of the same as a pointer value. In only must point to the valid object (so that it can be dereference automatically with no error). Implementation of the reference is say 4 byte address. The anti-argument is that you can never change the immutable object. – pepr Sep 15 '12 at 15:18
  • 1
    @pepr: You are, of course, free to define the term pass-by-reference in any way you like. However, if you choose to use a well-defined term in a way that is different (and in some sense the *exact opposite*) from the definition that every programmer, every teacher, every textbook, every course, every professor, every lecture, every computer scientist on the planet in the entire history of computing agree on, then you have to be prepared if people are confused by your statements. – Jörg W Mittag Sep 15 '12 at 15:21
  • 1
    @JörgWMittag: I do not like to use the following argument. I like the truth. But I have graduated in the Computer Science, and I have Ph.D. degree in it. I have taught students (as assistant) programming for 8 years at the University courses, CS. I am working as a programmer for 12 years. I can understand your confusion, but the things must be clarified in this case. Then show me what you mean by pass-by-reference. – pepr Sep 15 '12 at 15:34
  • @pepr The classic example is a function swap(a, b) that swaps the values of a and b. Note the lack of indirection via mutable objects. – fgb Sep 15 '12 at 15:44
  • 1
    Python always uses pass-by-reference. – Noctis Skytower Sep 15 '12 at 15:48
  • @fgb: Well, I understand what you mean. But Python is not a classical compiled language. Python variable means something slightly different than in compiled languages. I will update my answer in that sense. – pepr Sep 15 '12 at 15:56
  • @pepr: There is no such thing as a *compiled language*. Compilation and interpretation are traits of, well, the compiler and the interpreter, not the language. A language is a set of abstract mathematical rules. A language isn't compiled or interpreted. A language just *is*. Every language can be implemented by both a compiler and an interpreter. Most have both. All currently existing Python implementations in actual use (CPython, IronPython, Jython, PyPy) have compilers. – Jörg W Mittag Sep 15 '12 at 15:59
  • @JörgWMittag: The compilation/interpretation is not related to the question. Anyway, there is a way how we think about *variables* in classical compiled languages, and (say) in Python. This is what makes it different. Python works with variables on a higher abstraction level. I agree that technically, it is difficult to say what the compilation actually mean (more philosophical question). Anyway, it does not change the fact *what is passed as arguments when calling a Python function*. – pepr Sep 15 '12 at 16:19
  • @JörgWMittag: Your example only proves that you did not use the passed reference for modification of the passed object. The reason is that the string object passed by reference cannot be modified in any way. There is no mean to modify it. The assignment does not modify the passed object. It reuses the `foo` name for another purpose. Try `orig = foo` and call the `id(foo)` before and after the assignment. Then call `id(orig)` before and after assignment. The `id()` returns the identification of the target object (basically its address). – pepr Sep 15 '12 at 18:35
  • @pepr: Yes, and that is *exactly* the defining difference between pass-by-value and pass-by-reference. – Jörg W Mittag Oct 26 '14 at 21:33
0

Not so different

def func(a,b):
    a[0]=5 #Python
    b=30

public int func( ref int a,out int b,int d)
{
  a++;b--;  //C#
}

x=[10]
y=20
func(20,30) #python 
print x,y   #Outputs x=[5],y=20 Note:I have used mutable objects.Not possible with int.

int x=10,y=20;
func(ref x,out y,18); //C# 
Console.Writeline("x={0} y={1}",x,y);//Outputs x=11,y=19
user1655481
  • 376
  • 1
  • 10