Live data from Hacker News

There is no pass by reference in Go

dave.cheney.net

51–60 of 70 posts

Re: There is no pass by reference in Go

#51
post #21
post #11

Earlier quoted context omitted.

I'm still confused and I've been working in various languages for 15 years. If I pass a java object to a function, I'm passing a (probably) 8-byte pointer to some memory with a class tag, fields, whatever. It goes on the stack just like an 8 byte long. In languages that support pointers more directly, I'm doing the same thing, maybe minus the class tag in the pointed-to memory. Address is in an 8 byte type, put it on…

In all of those cases, you're probably passing a reference by value, semantically. ("Probably", because you didn't specify which languages, so I'm making an educated guess.) The usual litmus test is having two objects (or ints or whatever), write a fn `swap(a, b)` where the two are swapped after the call is over. Can't do that in Java or Go or Python or C; but you can in e.g. C++ and you sorta-can in Lisp. In C++, yo…

Just to be clear, the rules of your swap challenge are that the arguments of the function have to be ints, not allowed to be int *, right?

Also you say "two objects", but if the objects were compound, e.g. arrays, then I could write swap in C.

Re: There is no pass by reference in Go

#52

Earlier quoted context omitted.

The difference between pass-as-reference and pass-by-reference is more than trivia - if you were ignorant of it in a language, you might find trouble in the future when a function decides to alter its argument values in a way that negatively affects the caller. Part of the reason we should work to clarify the language is to avoid misconceptions about behaviour based on what kind of "reference" is meant.

A language with pointers also allows a function to alter its logical (not syntactical) argument values in a way that negatively affects the caller. There isn't much practical difference between using // void c_func_alters_deref_pfoo(Foo * pfoo) Foo foo = { ... }; c_func_alters_deref_pfoo(&foo); and // void cpp_func_alters_foo(Foo & foo) Foo foo = { ... }; cpp_func_alters_foo(foo); besides the ability to pass null or…

>A language with pointers also allows a function to alter its logical (not syntactical) argument values

What's the difference between a logical and syntactical argument?

Re: There is no pass by reference in Go

#53
Go lacks the C++ reference operator. You can't write:

    func fn(m &map[int]int) {
        m = make(map[int]int)
    }
    ...
    fn(m)
You have to write:

    func fn(m *map[int]int) {
        *m = make(map[int]int)
    }
    ...
    fn(&m)
It's very C. The caller is forced to use different syntax to pass something as a pointer/reference. In C++ and Rust, you can't see from the call whether you're passing a pointer or a reference.

Re: There is no pass by reference in Go

#54
post #48

Earlier quoted context omitted.

And Java just added to the problem. For PR reasons, they didn't want to have "pointers" (arithmetic, etc. ew). So Java has "references". But what happens when you call a method on a null reference? Not NullReferenceException, but NullPointerException.

They also insists Java is pass-by-value whereas technically it's pass-by-value for primitive unboxed types and call-by-sharing for others. The reason of which escapes me.

"Call-by-sharing" is just a different, and IMHO unnecessary and unhelpful, name for pass-by-value when the values happen to be pointers.

To put it another way, the inconsistency in Java isn't that primitives and objects are passed differently, it's that they're stored differently. Given how they're stored, they're passed the same way.

Re: There is no pass by reference in Go

#55
post #48

Earlier quoted context omitted.

And Java just added to the problem. For PR reasons, they didn't want to have "pointers" (arithmetic, etc. ew). So Java has "references". But what happens when you call a method on a null reference? Not NullReferenceException, but NullPointerException.

They also insists Java is pass-by-value whereas technically it's pass-by-value for primitive unboxed types and call-by-sharing for others. The reason of which escapes me.

Since primitives are immutable have value-equality, it doesn't matter.

If your cognitive model prefers to think of everything as pass pointer by value, you think that.

Re: There is no pass by reference in Go

#56
post #47

Earlier quoted context omitted.

And Java just added to the problem. For PR reasons, they didn't want to have "pointers" (arithmetic, etc. ew). So Java has "references". But what happens when you call a method on a null reference? Not NullReferenceException, but NullPointerException.

> For PR reasons, they didn't want to have "pointers" (arithmetic, etc. ew). So Java has "references" Well, it's just a rename for PR reasons. They actually don't have pointers. > But what happens when you call a method on a null reference? Not NullReferenceException, but NullPointerException. That's because it's the underlying pointer access that causes the exception. Doesn't mean the reference is itself a pointer -…

> They actually don't have pointers.

They do. Everywhere.

Every Java variable of Object type is a pointer. (Also, they're all nullable....ugh.)

If Java had real references (see original comment by jasode) you'd be able to write something like C#'s int.TryParse ( https://msdn.microsoft.com/en-us/library/f02979c7(v=vs.110).... ).

Re: There is no pass by reference in Go

#57
post #53

Go lacks the C++ reference operator. You can't write: func fn(m &map[int]int) { m = make(map[int]int) } ... fn(m) You have to write: func fn(m *map[int]int) { *m = make(map[int]int) } ... fn(&m) It's very C. The caller is forced to use different syntax to pass something as a pointer/reference. In C++ and Rust, you can't see from the call whether you're passing a pointer or a reference.

The difference is in C++ rvalues coerce to const&, while in Rust they do not.

E.x. this works

    int square(const int & num) {
        return num * num;
    }
    
    int main() {
        square(5);
    }
this does not

    fn takes_ref(a: &i32) -> i32 {
        *a
    }

    fn main() {
        takes_ref(64);
    }
There are still cases where you won't be able to tell if you're using a ref or not, though:

    let x = returns_a_ref();
    takes_ref(x);

Re: There is no pass by reference in Go

#58
post #10

An extended explanation missing from Dave Cheney's answer is that the "reference" etymology has at least 2 meanings. This is why his explanation is virtually the same as the one 20 years ago in the C Language FAQ[1] compiled by Steve Summit. - "reference" definition 1: an alias that cannot be null which is what a "reference type" is in Pascal and C++. This might be thought of as a stricter "computer-science" definiti…

I've got a credit in a game by pointing out that the reason the teams tools kept segfaulting was because the authors believed that if they had a reference they didn't need to check it for null. Unfortunately, they'd assign these references from pointers that could totally be null, and didn't error check at that point. References in C++ can totally be null.

Re: There is no pass by reference in Go

#59
post #10

An extended explanation missing from Dave Cheney's answer is that the "reference" etymology has at least 2 meanings. This is why his explanation is virtually the same as the one 20 years ago in the C Language FAQ[1] compiled by Steve Summit. - "reference" definition 1: an alias that cannot be null which is what a "reference type" is in Pascal and C++. This might be thought of as a stricter "computer-science" definiti…

I've got a credit in a game by pointing out that the reason the teams tools kept segfaulting was because the authors believed that if they had a reference they didn't need to check it for null. Unfortunately, they'd assign these references from pointers that could totally be null, and didn't error check at that point. References in C++ can totally be null.

That's undefined behavior. References in valid C++ cannot be null.

Re: There is no pass by reference in Go

#60
post #47

Earlier quoted context omitted.

> For PR reasons, they didn't want to have "pointers" (arithmetic, etc. ew). So Java has "references" Well, it's just a rename for PR reasons. They actually don't have pointers. > But what happens when you call a method on a null reference? Not NullReferenceException, but NullPointerException. That's because it's the underlying pointer access that causes the exception. Doesn't mean the reference is itself a pointer -…

> They actually don't have pointers. They do. Everywhere. Every Java variable of Object type is a pointer. (Also, they're all nullable....ugh.) If Java had real references (see original comment by jasode) you'd be able to write something like C#'s int.TryParse ( https://msdn.microsoft.com/en-us/library/f02979c7(v=vs.110).... ).

>Every Java variable of Object type is a pointer.

No, it's a reference. It just has a pointer underneath.

>If Java had real references (see original comment by jasode) you'd be able to write something like C#'s int.TryParse

If Java had one specific type of references. The common use of the term though is still what Java has.

Post reply on HN