
Go is Not Python - blacksmythe
http://www.seanhelvey.com/go-is-not-python
======
optimusclimb
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.

~~~
andrewstuart2
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)
        }

~~~
hasbroslasher
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.

------
betterwaytodoit
Here's a more idiomatic translation of the Python code to Go, and there's no
surprise to how the code behaves:

[https://play.golang.org/p/rpqvVDR9v8](https://play.golang.org/p/rpqvVDR9v8)

~~~
sfilargi
Nope, that's not what the OP is trying to do.

eg:

[https://play.golang.org/p/kFjXSlf5fw](https://play.golang.org/p/kFjXSlf5fw)

------
jimsmart

      fredPtr = nil // This line is superfluous.
    

In Go, declarations always initialise variables to their zero value, which for
all pointers is nil.

(Perhaps worthy of a follow up article: "Go is Not C/C++"? ;)

------
majewsky
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.

------
grasleya
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.

~~~
dragonwriter
> 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.

------
abhinai
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.

~~~
dragonwriter
> 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.

------
questhrowaway
I don't know Python or Go, but both examples seem _wrong_.

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?

------
sabujp
been a while since i've done pointer stuff, isn't that how it works in c? go
seems de-evolved to me.

~~~
0xffff2
C has no concept of the kind of for loop used in the article, so there is no
"how it works" in C.

~~~
dragonwriter
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.

------
urda
This has nothing to do with Python. It's just a "gotcha" of Go.

~~~
deepsun
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.

~~~
pvg
_I believe he 's talking about what he should teach to students_

What gives you that impression?

~~~
deepsun
Huh, I was reading it fast, and didn't realize that word "students" in the
text meant a variable name, not his students. My bad :)

~~~
pvg
Heh yeah and I ended up re-reading it looking for some indication the writer
was an instructor that I'd missed and didn't notice 'students' at all.

------
singularity2001
for a no-goer: will this copy by value? ``` var fred Student for _, student :=
range students { if student.name == "fred" { fred = student } } ```

~~~
majewsky
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.

