I'm not sure what the title has to do with the article at all. It's just pointing out a language gotcha/subtlety. The title might as well have been "Go is Not Javascript", "Go is not QBasic", etc.
This is the kind of "gotcha" that you learn pretty quickly when working with go. The problem is that Go has created a new variable called "student" that is assigned as its value each item in students as it ranges through. Go is not going to allocate a brand new "student" variable for each iteration of the loop. That would be a waste of time and memory both during the loop, and later during GC. So your "fredPtr" given this syntax, would be more accurately named "studentPtr."
Go won't hold your hands because it's more efficient if you are explicit. If you want a "reference" to the real original, your array needs to be an array of pointers.
It's pretty simple to understand when you have worked with pointers before and understand how the memory is allocated and eventually collected (and why you don't want to reallocate every loop iteration).
Finally, nil is the default value of anything with type (star)Student, and almost nobody uses arrays in Go ([2]Student is an array, []Student is a much-more-useful slice). In general, I don't think this author has written much Go code. It's probably a good idea to get a little more experience with whatever you're complaining about before writing a blog post about it, and likely misinforming your readers.
It's pretty straightforward code when you write what you explicitly want:
package main
import (
"fmt"
)
type Student struct {
name string
}
func main() {
students := []*Student{{"fred"}, {"karen"}}
var fredPtr *Student
for _, student := range students {
if student.name == "fred" {
fredPtr = student
}
}
fmt.Println(fredPtr.name)
}
Ironically, your code looks much more like Python than the author's. "Simple is better than complex" at play, I suppose. If I were to sit down and start writing Go, the idea to use equality would come long before I bothered with pointer notation, especially for such a simple task.
I believe he's talking about what he should teach to students, and his point is that Python is more intuitive than Go for newcomers.
I personally don't really care how easy it is to write a "hello world" in Go, nor Python. My day job involves big projects, so I'm pretty fine with "hello world" taking 10k lines as long as it will scale slower with complexity than other language. The same argument about learning curve -- I would be happy with a language that requires couple of years of learning to even start, as long as it takes less time in the following 20 years I'm going to be using it.
I don't get that impression at all from the article. I think he's just trying to warn others coming to Go from Python about a particular language quirk. Nothing about the intuitiveness of Go or Python at all
While C has no for-in loop, the natural translation of that to a C style for loop and the C address-of operator would work the same way; the key thing is that student is a variable defined outside the loop whose value is modified each iteration, not a fresh variable allocated with each loop iteration.
I love Python. But honestly speaking, the point raised in this article is fairly trivial. I would not, not learn Go just because there are small differences in the way reference / pointers work. I do not see this as an inherent shortcoming of Go.
Both languages have their strengths. When you pick a language for an application, it is your responsibility to use it properly. Otherwise you will make mistakes and it won't be the fault of the language.
> But honestly speaking, the point raised in this article is fairly trivial. I would not, not learn Go just because there are small differences in the way reference / pointers work.
Nothing in the article suggests not learning Go because of this behavior; the article is warning about a behavior developers coming to Go from Python are, in the author's experience, often bitten by, so that other people taking the same path can avoid making the same mistake.
> When you pick a language for an application, it is your responsibility to use it properly.
Yes, and this article aims to help people coming to Go from Python to do that by pointing out a common pitfall.
I think you can put this more generally as "syntax is not semantics." Go takes some syntactic cues from python (but who doesn't these days?) but its semantics can be pretty different. I think it's pretty common for new programmers especially to get caught up in the syntax of languages without giving enough attention to their semantics, which causes the sort of problems the author highlights here.
> I think you can put this more generally as "syntax is not semantics." Go takes some syntactic cues from python (but who doesn't these days?) but its semantics can be pretty different.
Except the difference is not in similar syntax with different semantics; since it's the application of the & operator, which has no close parallel in Python, that is the source of the surprise.
Yes. A copy into type `Student` will copy each field, whereas `*Student` only takes the address. (Which would not be a problem if the loop didn't reuse the memory slot for the loop variable.)
Also, indent with two spaces to get code formatting. HN formatting is (sadly) not Markdown.
Alternative options of solving this issue include `break`ing when the right option is found (so the loop variable doesn't get overwritten again) or moving everything into a function:
func findByName(students []*Student, name string) *Student {
for _, s := range students {
if s.name == name {
return s
}
}
return nil
}
Both options have the added advantage of stopping iteration as soon as the result is found.
30 comments
[ 2363 ms ] story [ 963 ms ] threadThe title has to do with a common use case of Go, referred to in the opening example, where it is a common choice to move to from Python for speed.
> It's just pointing out a language gotcha/subtlety.
The implied motivation for posting this (see the closing line) is that the author has see this bite people coming to Go from Python.
Go won't hold your hands because it's more efficient if you are explicit. If you want a "reference" to the real original, your array needs to be an array of pointers.
It's pretty simple to understand when you have worked with pointers before and understand how the memory is allocated and eventually collected (and why you don't want to reallocate every loop iteration).
Finally, nil is the default value of anything with type (star)Student, and almost nobody uses arrays in Go ([2]Student is an array, []Student is a much-more-useful slice). In general, I don't think this author has written much Go code. It's probably a good idea to get a little more experience with whatever you're complaining about before writing a blog post about it, and likely misinforming your readers.
It's pretty straightforward code when you write what you explicitly want:
I personally don't really care how easy it is to write a "hello world" in Go, nor Python. My day job involves big projects, so I'm pretty fine with "hello world" taking 10k lines as long as it will scale slower with complexity than other language. The same argument about learning curve -- I would be happy with a language that requires couple of years of learning to even start, as long as it takes less time in the following 20 years I'm going to be using it.
What gives you that impression?
— Go is basically a better (more evolved?) C.
Both languages have their strengths. When you pick a language for an application, it is your responsibility to use it properly. Otherwise you will make mistakes and it won't be the fault of the language.
Nothing in the article suggests not learning Go because of this behavior; the article is warning about a behavior developers coming to Go from Python are, in the author's experience, often bitten by, so that other people taking the same path can avoid making the same mistake.
> When you pick a language for an application, it is your responsibility to use it properly.
Yes, and this article aims to help people coming to Go from Python to do that by pointing out a common pitfall.
https://play.golang.org/p/rpqvVDR9v8
Although technically he was trying to get a pointer/reference to the student in the array, not a copy of its value
eg:
https://play.golang.org/p/kFjXSlf5fw
Python: How is `Fred` available to be printed in the Python example, is not it out of scope?
Go: Why use `var fredPtr *Student`? What's the point? Can not use `var fredPtr Student` and the set `fredPtr = student` in the loop?
(Perhaps worthy of a follow up article: "Go is Not C/C++"? ;)
Except the difference is not in similar syntax with different semantics; since it's the application of the & operator, which has no close parallel in Python, that is the source of the surprise.
Also, indent with two spaces to get code formatting. HN formatting is (sadly) not Markdown.