Any difference in using an empty interface or an empty struct as a map's value? - go

I am using this construct to simulate a set
type MyType uint8
map[MyType]interface{}
I then add in all my keys and map them to nil.
I've learnt that it is also possible to use
map[MyType]struct{}
Any benefits of using the empty struct versus interface{}.

Memory usage. For example, types struct{}, interface{}, and bool,
package main
import (
"fmt"
"unsafe"
)
func main() {
var s struct{}
fmt.Println(unsafe.Sizeof(s))
var i interface{}
fmt.Println(unsafe.Sizeof(i))
var b bool
fmt.Println(unsafe.Sizeof(b))
}
Output (bytes for 32-bit architecture):
0
8
1
Output (bytes for 64-bit architecture):
0
16
1
References:
Go Data Structures: Interfaces

The empty struct and empty interface, though syntactically similar, are actually opposites. An empty struct holds no data; an empty interface can hold any type of value. If I see a map[MyType]struct{}, I know immediately that no values will be stored, only keys. If I see a map[MyType]interface{}, my first impression will be that it is a heterogenous collection of values. Even if I see code storing nil in it, I won't know for sure that some other piece of code doesn't store something else in it.
In other words, using struct{} makes your code much more readable. It also saves a little memory, as described in the other answer, but that is just a fringe benefit of using the right tool for the job.

I would like to add additional detail about empty struct , as differences are already covered by andybalholm and peterSO .
Below is the example which shows usability of empty struct .
Creates an instance of rectangle struct by using a pointer address
operator is denoted by & symbol.
package main
import "fmt"
type rectangle struct {
length int
breadth int
color string
}
func main() {
var rect1 = &rectangle{10, 20, "Green"} // Can't skip any value
fmt.Println(rect1)
var rect2 = &rectangle{}
rect2.length = 10
rect2.color = "Red"
fmt.Println(rect2) // breadth skipped
var rect3 = &rectangle{}
(*rect3).breadth = 10
(*rect3).color = "Blue"
fmt.Println(rect3) // length skipped
}
Reference : https://www.golangprograms.com/go-language/struct.html
For a thorough read you can refer : https://dave.cheney.net/2014/03/25/the-empty-struct

Related

Creating type from slices

I want to create a data type which acts like a stack. I want to add and remove entries at the "top", as well as being able to print it out. In this example an XPath type for traversing an xml document and keeping track of the current path.
So I created a type xPath []string, and write the appropriate functions, ie: push() pop() and String().
My problem here is that the type loses its state, which baffles me a bit since I thought slices were reference types. Also if I try changing my functions into pointer receivers I run into several compile errors. At this point just to get by the problem, I simply changed []string into a struct with a single []string field. Though it still bathers me that I can't make it work with just a slice as the underlying type.
What is the correct way to do this?
package main
import (
"fmt"
"strings"
)
type xPath []string
func (xp xPath) push(entry string) {
xp = append(xp, entry)
}
func (xp xPath) String() string {
sb := strings.Builder{}
sb.WriteString("/")
sb.WriteString(strings.Join(xp, "/"))
return sb.String()
}
func main() {
xp := xPath{}
xp.push("rss")
xp.push("channel")
xp.push("items")
fmt.Println(xp)
// Output: /
// Wanted: /rss/channel/items
}
Your push function is doing nothing.
Correct push function:
func (xp *xPath) push(entry string) {
*xp = append(*xp, entry)
}
Slices are reference types in cases where you want to change their values (e.g. using indexes).
On the other hand, if you want to reassign them and replace the whole slice, you should use pointers.
Also about the stack, the are some better approaches:
have a look at this question.

When to store pointers to structs in variables instead of the struct itself

I'm currently learning Go and am following a tutorial about how to use Go with Stripe. There is this example code:
package main
import (
"fmt"
"github.com/stripe/stripe-go"
"github.com/stripe-go/customer"
)
func main() {
sc := &client.API{}
sc.Init("somekey")
c, _ := sc.Customers.Get("customerid", nil)
// ...
}
What is/could be the reason that sc stores the pointer to the struct and not the struct itself?
[To supplement the comment you received]
While in this case with the small code sample it's hard to say, in most scenarios you'll see non-trivial types passed around by pointer to enable modification. As an anti-example, consider this code which uses a variable of a struct type by value:
type S struct {
ID int
}
func (s S) UpdateID(i int) {
s.ID = i
}
func main() {
s := S{}
s.UpdateID(99)
fmt.Println(s.ID)
}
What do you think this will print? It will print 0, because methods with value receivers cannot modify the underlying type.
There's much information about this in Go - read about pointers, and about how methods should be written. This is a good reference: https://golang.org/doc/faq#methods_on_values_or_pointers, and also https://golang.org/doc/effective_go#pointers_vs_values
Back to your example: typically non-trivial types such as those representing a "client" for some services will be using pointers because method calls on such types should be able to modify the types themselves.

How builtin function "append" works: appending to a slice whose elements are of type interface

The section of appending to slices on the specification, mentions the following example:
var t []interface{}
t = append(t, 42, 3.1415, "foo") // t == []interface{}{42, 3.1415, "foo"}
I'm confused here, why can we append values of int, float and string to a slice whose elements are of interface type? And why is the result of the append like that? I tried hard/long, but I don't get it.
Because:
all types implement the empty interface
For details read over the ref spec for interfaces.
interface is similar to Object in java where all types/classes/etc are also an Object.
You can see this effect by using reflect:
package main
import (
"fmt"
"reflect"
)
func main() {
var t []interface{}
z := append(t, "asdf", 1, 2.0)
fmt.Println(z)
for i := range z {
fmt.Println(reflect.TypeOf(z[i]))
}
}
Output:
[asdf 1 2]
string
int
float64
Why is it like this? Well, think about serialization especially of JSON objects; the types can be string, int, object, etc. This allows for deserialization without specifying a fully mapped struct (maybe you don't care and want only some of the data, etc). Basically, it allows you to have a form of "weak typing" in Go; while still being able to have strong typing.
As mentioned below, reflect identifies the type for you. When programming though, you may have to do it manually.

why two pointer of same struct which only used new function for creating compares equal in go

I want to compare 2 instance of the same struct to find out if it is equal, and got two different result.
comment the code // fmt.Println("%#v\n", a), the program output is "Equal"
Use the fmt to print variable "a", then I got the output "Not Equal"
Please help me to find out Why???
I use golang 1.2.1
package main
import (
"fmt"
)
type example struct {
}
func init() {
_ = fmt.Printf
}
func main() {
a := new(example)
b := new(example)
// fmt.Println("%#v\n", a)
if a == b {
println("Equals")
} else {
println("Not Equals")
}
}
There are several aspects involved here:
You generally cannot compare the value of a struct by comparing the pointers: a and b are pointers to example not instances of example. a==b compares the pointers (i.e. the memory address) not the values.
Unfortunately your example is the empty struct struct{} and everything is different for the one and only empty struct in the sense that it does not really exist as it occupies no space and thus all different struct {} may (or may not) have the same address.
All this has nothing to do with calling fmt.Println. The special behavior of the empty struct just manifests itself through the reflection done by fmt.Println.
Just do not use struct {} to test how any real struct would behave.

what exactly is interface(struc) and interface(struc).function

Trying to do go koan, i got stuck in understanding the interface(struct) syntax, what exactly
does it do ?
I came up with following fun program, which has further confused me on how is interface casting working :
package main
import "fmt"
type foo interface{ fn() }
type t struct { }
type q struct { }
func (_i t ) fn() { fmt.Print("t","\n") }
func (_i q ) fn() { fmt.Print("q","\n")}
func main() {
_j := t{}
_q := q{}
// This is alright ..
fmt.Print( _j.fn,"\n") //0x4015e0
fmt.Print( _q.fn,"\n") //0x401610
_j.fn() //t
_q.fn() //q
// both pointers same .. why ?
fmt.Print( foo(_j).fn,"\n") //0x401640
fmt.Print( foo(_q).fn,"\n") //0x401640
// but correct fns called .. how ?
foo(_j).fn() //t
foo(_q).fn() //q
// same thing again ...
_fj := foo(_j).fn
_fq := foo(_q).fn
// both pointers same .. as above
fmt.Print( _fj,"\n") //0x401640
fmt.Print( _fq,"\n") //0x401640
// correct fns called .. HOW !
_fj() //t
_fq() //q
}
The pointer are what i'm getting my machin, YMMV.
My question is .. what exactly does interface(struct) returns ?
and how does interface(struct).func , finds the original struct ...
is there some thunk/stub magic going on here?
From here: http://research.swtch.com/interfaces
what exactly does interface(struct) return?
It creates a new interface value (like the one you see on top in the graphic), wrapping a concrete struct value.
how does interface(struct).func find the original struct?
See the data field in the graphic. Most of the time this will be a pointer to an existing value. Sometimes it will contain the value itself if it fits, though.
In the itable you'll see a function table (where fun[0] is).
I assume that on your machine 0x401640 is the address of the respective pointers to fn, which is in that table for foo. Although this is best verified by someone working on the GC compiler suite.
Note that the behaviour you discovered is not strictly defined to be so. Compiler builders can take other approaches to implementing Go interfaces if they like to, as long as the language semantics are preserved.
Edit to answer questions in the comments:
package main
import "fmt"
type foo interface {
fn()
}
type t struct{}
type q struct{}
func (_i t) fn() { fmt.Print("t", "\n") }
func (_i q) fn() { fmt.Print("q", "\n") }
func main() {
_j := t{}
_j1 := t{}
fmt.Println(foo(_j) == foo(_j)) // true
fmt.Println(foo(_j) == foo(_j1)) // true
}
On the diagram you see 3 blocks:
The one on the left side labeled Binary is a concrete type instance, like your struct instances _j and _j1.
The one on the top center is an interface value, this one wraps (read: points to) a concrete value.
The block on the right lower side is the interface definition for Binary underlyings. This is where the jump table / call forwarding table is (itable).
_j and _j1 are two instances of the concrete type t. So there are two of the lower-left blocks somewhere in memory.
Now you decide to wrap both _j and _j1 in interfaces values of type foo; now you have 2 of the top-center blocks somewhere in memory, pointing back at _j and _j1.
In order for the interface value to remember what its underlying type is and where the methods of those types are it keeps a single instance of the lower-right block in memory, to which both interface values for _j and _j1 respectively point to.
In that block you have a jump table to forward method calls made on the interface values to the concrete underlying type's implementation. That's why both are the same.
It's worth mentioning that unlike Java and C++ (not sure about Python), all Go methods are static and the dot-call notation is only syntactic sugar. So _j and _j1 don't have different fn methods, it's the same exact method called with another implicit first parameter which is the receiver on which the method is called.

Resources