Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Go | Automatic (implicit) pointer dereferencing for pointer receivers #85

Open
atc0005 opened this issue Jul 9, 2020 · 3 comments
Open
Labels

Comments

@atc0005
Copy link
Owner

atc0005 commented Jul 9, 2020

This is the example code from the https://www.udemy.com/course/go-the-complete-developers-guide/ course:

func (pointerToPerson *person) updateName(newFirstName string) {
    (*pointerToPerson).firstName = newFirstName
}

Here it looks like they're explicitly dereferencing the pointer receiver in order to get at the firstName field. I vaguely recall reading about Go automatically dereferencing for you with pointer receivers, so for the programmer's perspective this would be functionally equivalent (though less explicit perhaps?):

func (pointerToPerson *person) updateName(newFirstName string) {
    pointerToPerson.firstName = newFirstName
}

Need to do some additional research to confirm that my memory is correct and if possible, figure out what the best practice is for this.

@atc0005 atc0005 added the golang label Jul 9, 2020
@atc0005
Copy link
Owner Author

atc0005 commented Jul 9, 2020

From https://www.digitalocean.com/community/tutorials/defining-methods-in-go:

package main

import "fmt"

type Boat struct {
    Name string

    occupants []string
}

func (b *Boat) AddOccupant(name string) *Boat {
    b.occupants = append(b.occupants, name)
    return b
}

func (b Boat) Manifest() {
    fmt.Println("The", b.Name, "has the following occupants:")
    for _, n := range b.occupants {
        fmt.Println("\t", n)
    }
}

func main() {
    b := &Boat{
        Name: "S.S. DigitalOcean",
    }

    b.AddOccupant("Sammy the Shark")
    b.AddOccupant("Larry the Lobster")

    b.Manifest()
}

Snippet from description:

Within main, we define a new variable, b, which will hold a pointer to a Boat (*Boat). We invoke the AddOccupant method twice on this instance to add two passengers. The Manifest method is defined on the Boat value, because in its definition, the receiver is specified as (b Boat). In main, we are still able to call Manifest because Go is able to automatically dereference the pointer to obtain the Boat value. b.Manifest() here is equivalent to (*b).Manifest().

Worth stressing:

  • Go is able to automatically dereference the pointer to obtain the Boat value.
  • b.Manifest() here is equivalent to (*b).Manifest()

@atc0005
Copy link
Owner Author

atc0005 commented Jul 9, 2020

From The Go Programming Language:

The (*Point).ScaleBy method can be called by providing a *Point receiver, like this:

r := &Point{1, 2} 
r.ScaleBy(2) 
fmt.Println(*r) // "{2, 4}" 

or this:

p := Point{1, 2} 
pptr := &p 
pptr.ScaleBy(2) 
fmt.Println(p) // "{2, 4}" 

or this:

p := Point{1, 2} 
(&p).ScaleBy(2) 
fmt.Println(p) // "{2, 4}" 

But the last two cases are ungainly. Fortunately, the language helps us here. If the receiver p is a variable of type Point but the method requires a *Point receiver, we can use this shorthand:

p.ScaleBy(2) 

and the compiler will perform an implicit &p on the variable. This works only for variables, including struct fields like p.X and array or slice elements like perim[0].

A little further down:

But we can call a Point method like Point.Distance with a *Point receiver, because there is a way to obtain the value from the address: just load the value pointed to by the receiver. The compiler inserts an implicit * operation for us. These two function calls are equivalent:

pptr.Distance(q)
(*pptr).Distance(q)

and further:

Or the receiver argument has type *T and the receiver parameter has type T . The compiler implicitly dereferences the receiver, in other words, loads the value:

pptr.Distance(q) // implicit (*pptr)

I obviously need to spend more time with this book (very detailed).

@atc0005 atc0005 changed the title Go | Automatic pointer dereferencing for pointer receivers Go | Automatic (implicit) pointer dereferencing for pointer receivers Jul 9, 2020
@atc0005
Copy link
Owner Author

atc0005 commented Jul 9, 2020

From Get Programming with Go:

type person struct { 
    name, superpower string
    age int 
} 

timmy := &person{ 
    name: "Timothy", 
    age: 10, 

}

Furthermore, it isn’t necessary to dereference structures to access their fields. The following listing is preferable to writing (*timmy).superpower.

timmy.superpower = "flying" 

fmt.Printf("%+v\n", timmy)

What’s the difference between timmy.superpower and (*timmy).superpower ?

There’s no functional difference because Go automatically dereferences pointers for fields, but timmy.superpower is easier to read and is therefore preferable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant