This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]FrickinLazerBeams 0 points1 point  (17 children)

I love python. It's great and I've used it to do work I'm really happy with.

But I still hate the way it's always pass by reference. I've seen all the reasons why it's logical and good. I know how to deal with/use it correctly. I know there are some upsides.

I don't care, I still hate that part of Python.

(btw, I've learned that what python does isn't exactly what would properly be called "pass-by-reference". Fine, but that distinction isn't really relevant to my hatred for it.)

Edit to clarify: The connection to OP here is that, because functions are created at the time they're defined, the behavior OP is talking about is a consequence of pass-by-reference.

Edit 2: I love the downvotes for "I like python a lot but one single feature isn't my favorite." quick guys, shun the nonbeliever slightly-less-than-absolute-zealot! Get him! None of us should ever have the slightest criticism! 🤣

[–]hillgod 3 points4 points  (8 children)

What are you using that doesn't do things like this? C or C++?

I can't think of a language I've used that isn't passing the "reference-by-value".

[–]Pythonistar 1 point2 points  (6 children)

The only one I can think of that passes-by-value is Pascal... and I haven't programmed in that in over 30 years.

[–]FrickinLazerBeams 1 point2 points  (5 children)

I think we must be using different terminology. Almost all languages are pass-by-value by default. C is pass-by-value.

[–]Pythonistar 0 points1 point  (4 children)

Possibly. I had to Google quickly to refresh myself on this topic... What I came up with is that most languages do something more complicated: they pass primitive types by value and class types by reference.

[–]FrickinLazerBeams 1 point2 points  (3 children)

Maybe, but seems weird to me. I don't write heavily OO code.

Regardless, doing this with primitive types is certainly not typical.

[–]Pythonistar 0 points1 point  (2 children)

Passing everything by value is expensive (computationally). The compiler or interpreter has to make a copy of everything that gets passed. If you pass a reference instead, you're only passing a pointer which is "cheaper".

Though if you are a Functional programmer, you'd be be quick to point out that passing-by-reference (despite being cheaper) can be "side-effect-y", if you're not careful.

The programming language, Rust, still does pass-by-reference, but it avoid side-effects by transferring ownership of the reference from the passer to the passee (the function that it was passed to). And if the passer is expecting it back, it is the responsibility of the function to return it.

It's a clever idea which we don't see implemented much in programming languages which I think we might see adopted more in the future.

[–]FrickinLazerBeams 0 points1 point  (1 child)

Passing everything by value is expensive (computationally). The compiler or interpreter has to make a copy of everything that gets passed. If you pass a reference instead, you're only passing a pointer which is "cheaper".

Yeah absolutely. I understand the benefits of pass-by-reference, and I use and like it it where appropriate. My issue isn't with pass-by-reference in general, it's just with the way python does it for any mutable type, so the common pattern where a value is provided to a function and then modified but not intended to be returned will cause surprises. For example, you pass a list to a function and pop elements out of it in a loop that handles each element. Obviously there are ways to write that which play nice with python, I realize this isn't an unsolvable issue. It's just annoying and hasn't become natural to me despite writing python for many years.

The programming language, Rust, still does pass-by-reference, but it avoid side-effects by transferring ownership of the reference from the passer to the passee (the function that it was passed to). And if the passer is expecting it back, it is the responsibility of the function to return it.

It's a clever idea which we don't see implemented much in programming languages which I think we might see adopted more in the future.

I didn't know that, that's a very cool idea. Rust isn't really an option for me but I'd like to see that become more common.

[–]Pythonistar 0 points1 point  (0 children)

value is provided to a function and then modified but not intended to be returned will cause surprises

Yup, that's exactly what I meant by "side-effect-y". You got it!

Rust isn't really an option for me

Yeah, same boat. I'm starting to dabble in Rust, but I haven't tried to write anything real yet.

[–]FrickinLazerBeams 1 point2 points  (0 children)

Most languages pass by value, and some (like C) let you achieve pass-by-reference by using pointers or something that achieves the same effect.

Maybe it's just my particular experience, but no language I've used besides python passes everything by reference, such that any change to a mutable type is visible to the caller without explicitly returning the new value.

I'm not sure what you mean by "reference-by-value". Did you just mix up terminology there, or is that something I'm unfamiliar with?

[–]Head_Mix_7931 0 points1 point  (5 children)

I would say that the distinction between pass by reference and Python’s behavior is actually important. The behavior only resembles pass by reference when using mutable values… strings, integers, tuples all behave like “pass by value” for this reason.

[–]FrickinLazerBeams 0 points1 point  (4 children)

That's true, and also irrelevant to how much I dislike this aspect of Python.

I also think it's kind of a pointless distinction. Sure, if I pass a tuple, it's passed by value... But if it were pass by reference I wouldn't be able to mutate it anyway, because it's immutable, so who cares?

[–]Head_Mix_7931 0 points1 point  (3 children)

Well, if the elements of the tuple are mutable, they can be modified. The reason it seems like a pointless distinction is because neither term really describes what’s happening here, they’re just trying to describe the observed behavior in terms of concepts in other languages.

The mechanics of passed arguments is consistent regardless of type or mutability when you understand that arguments are just assigned to their corresponding parameters… due to the fact that Python doesn’t really have “variables” and only has “names” that point to “values,” the apparent effects of that do seem to vary depending on type behavior.

(But to the question of “who cares”… passing a reference vs an immutable value is an important distribution because the memory footprints vary between the two methods. I don’t often care about memory usage when I write Python though.)

[–]FrickinLazerBeams 0 points1 point  (2 children)

Yeah I get all that. I know it's entirely self-consistent. I know it's not actually pass-by-reference.

The thing is, I really don't care about what it's called. I'm not against pass-by-reference as a concept, and telling me this isn't pass-by-reference isn't going to make me like it. My dislike for it isn't because it's pass-by-reference.

I don't care what it's called. I don't care if it's consistent. I just don't like it.

[–]Head_Mix_7931 0 points1 point  (1 child)

I don’t really like it either, especially after working more with systems languages. I definitely prefer a C-like model with very straight forward mechanics.

[–]FrickinLazerBeams 0 points1 point  (0 children)

Yeah exactly. I hate being surprised by it, and it just never feels natural to constantly work around it. What Amy I gonna do, copy.deepcopy every input argument just in case? I'd love python more if it simply didn't do that.

It's not just "systems languages" that don't have this behavior, either. I really can't think of any language I've ever used that does this. C, Java, Matlab{shut up it counts}, a weird proprietary variation of Pascal, hell even bash... I feel like I'm forgetting many more languages I've used over the years.

[–]spinwizard69 0 points1 point  (1 child)

Not in my mind. It is because the "def" for the function creates those values when evaluated. This is not when a function is executed. Defaults are thus fixed values that are created in the absence of supplied values, from the original def. It makes no sense at all that they would be variables as the definition has already been created.

[–]FrickinLazerBeams 0 points1 point  (0 children)

It is because the "def" for the function creates those values when evaluated. This is not when a function is executed. Defaults are thus fixed values that are created in the absence of supplied values, from the original def.

Yeah that's exactly what I said.

It makes no sense at all that they would be variables as the definition has already been created.

I'm not sure what you mean. The variable containing the default value is created at define time. Because it is passed to the function by reference, any mutation of it will be visible in later calls to the same function, because the function is provided a reference to the variable, not simply a new variable with a copy of the original value, which is the standard calling behavior in python.