Are typedefs for primitive values equivalent in golang? - go

Given this code:
type Philosopher int
const (
Epictetus Philosopher = iota
Seneca
)
func Quote(who Philosopher) string {
fmt.Println("t: ", reflect.TypeOf(who))
switch who {
case Epictetus:
return "First say to yourself what you would be;
and do what you have to do"
case Seneca:
return "If a man knows not to which port he sails,
No wind is favorable"
}
return "nothing"
}
Calling Quote(5) will print Foo.Philosopher as the type for 5.
Why didn't the type checker complain since that is what a type safe enums are supposed to do i.e. limit the scope of values ?

These are not enums as you think of them. Type Philosopher is more or less an alias of an int. More or less, because it is a fundamentally distinct type, which can define its own methods.
The point of it is to provide semantic grouping of constants in a way that is clear to the programmer. Additionally, one gets the benefit of Go's type checker during compile time. But only to the degree that a value passed into a func(Philosopher) can not be implicitly interpreted as such. Passing a literal 5 as the parameter works, because constants like that in Go are inherently untyped. This will not work;
n := 5
Quote(n) // Compile error -> int is not Philosopher
Reason being that n is defined as int. There exists no implicit conversion between type int and Philosopher. However, this will work:
n := 5
Quote(Philosopher(n))
Because the type cast is valid. Go does not care whether or not 5 is a valid and pre-defined Philosopher constant.

Go doesn’t make any guarantees about valid values, except for those implied by int. The use of iota is just a convenience for defining a series of constants; it doesn’t say anything about valid values.
5 is a valid int, and therefore a valid Philosopher. You could also create const Plato = Philosopher(5).

Shorter answer should be like :
An untyped constant takes the type needed by its context.

Related

Is type casting structs in Go a no-op?

Consider the following code in Go
type A struct {
f int
}
type B struct {
f int `somepkg:"somevalue"`
}
func f() {
var b *B = (*B)(&A{1}) // <-- THIS
fmt.Printf("%#v\n", b)
}
Will the marked line result in a memory copy (which I would like to avoid as A has many fields attached to it) or will it be just a reinterpretation, similar to casting an int to an uint?
EDIT: I was concerned, whether the whole struct would have to be copied, similarly to converting a byte slice to a string. A pointer copy is therefore a no-op for me
It is called a conversion. The expression (&A{}) creates a pointer to an instance of type A, and (*B) converts that pointer to a *B. What's copied there is the pointer, not the struct. You can validate this using the following code:
a:=A{}
var b *B = (*B)(&a)
b.f=2
fmt.Printf("%#v\n", a)
Prints 2.
The crucial points to understand is that
First, unlike C, C++ and some other languages of their ilk, Go does not have type casting, it has type conversions.
In most, but not all, cases, type conversion changes the type but not the internal representation of a value.
Second, as to whether a type conversion "is a no-op", depends on how you define the fact of being a no-op.
If you are concerned with a memory copy being made, there are two cases:
Some type conversions are defined to drastically change the value's representation or to copy memory; for example:
Type-converting a value of type string to []rune would interpret the value as a UTF-8-encoded byte stream, decode each encoded Unicode code point and produce a freshly-allocated slice of decoded Unicode runes.
Type-converting a value of type string to []byte, and vice-versa, will clone the backing array underlying the value.
Other type-conversions are no-op in this sense but in order for them to be useful you'd need to either assign a type-converted value to some variable or to pass it as an argument to a function call or send to a channel etc — in other words, you have to store the result or otherwise make use of it.
All of such operations do copy the value, even though it does not "look" like this; consider:
package main
import (
"fmt"
)
type A struct {
X int
}
type B struct {
X int
}
func (b B) Whatever() {
fmt.Println(b.X)
}
func main() {
a := A{X: 42}
B(a).Whatever()
b := B(a)
b.Whatever()
}
Here, the first type conversion in main does not look like a memory copy, but the resulting value will serve as a receiver in the call to B.Whatever and will be physically copied there.
The second type conversion stores the result in a variable (and then copies it again when a method is called).
Reasonong about such things is easy in Go as there everything, always, is passed by value (and pointers are values, too).
It may worth adding that variables in Go does not store the type of the value they hold, so a type conversion cannot mutate the type of a variable "in place". Values do not have type information stored in them, either. This basically means that type conversions is what compiler is concerned with: it knows the types of all the participating values and variables and performs type checking.

Implicit type conversion constant vs variables

I have faced a situation where I have some integer value in a constant and multiplying it with math.Pi constant as below:
func main() {
const a = 5
fmt.Printf("%v", a*math.Pi)
}
On execution it gives following result:
15.707963267948966
But, when I change the constant to variable (variable a) as below:
func main() {
a := 5
fmt.Printf("%v", a*math.Pi)
}
On compilation it gives the following error:
constant 3.14159 truncated to integer
As far as I understand implicit numeric type conversion is working when all operands of expression are constants, but not working when any of these a variable.
But why is this happening?
It's happening because of Go's untyped constants. In both cases, you are not explicitly specifying a type.
In the first case, you are defining an untyped constant (you could also define a typed constant by using const a float64 = 5). For an untyped constant, a type will only be inferred when it’s used in a context that requires a type – i.e. when you are multiplying it with math.Pi, the compiler will "guess" that you want to have a float there, and everything works fine.
In the second case, a variable of course has to have a type, so the type inference takes place when declaring the variable, and since you used "5", the compiler will "infer" int, and multiplying an int and a float is not possible in Go. You could use e.g. a:=5.0 or var a float64 = 5 to declare a as a float64, then this code would work as well.
See this blog post for more details.

Why to use "redundant" keyword "struct" for types in Go?

I am a big fan of Golang, and very pleased to how the syntax of Go is designed. As a part of syntax philosophy, we have a rule as following: omit the things (keywords, characters etc.) if they are not needed actually.
For that reason instead of writing redundant colons:
for ; sum < 1000; {
sum += sum
}
You allowed to simply put:
for sum < 1000 {
sum += sum
}
notice how we omitted redundant semicolons
And there are lots of other cases where syntax is gratefully simplified.
But what about struct when we define type?
type Person struct {
name string
}
Why do we need to put struct keyword here?
Keywords are to determine intention, to clarify the exact choice of available options so a compiler knows how to do his job properly.
Will it be unclear and ambiguous if we simply put:
type Person {
name string
}
??
I believe there is a meaning for struct in the examples above
because compiler fails when type defined without struct keyword.
Please, explain me (and provide links) what else we can use instead of struct when we define some type.
Please, list available options from which we want to clarify to a compiler that things in curly brackets after type name are exactly parts of a struct and not something else (what else?).
Thanks.
It's not redundant. You can make types from existing types:
type MyType int
type MyType string
Or interfaces:
type Stringer interface {
String() string
}
This is covered in the Go tour and in the spec.
Types (may) not only appear in type declarations, but in countless other places, for example in function declarations.
Structs may be "used" anonymously, without creating a named type for them. For example, the following declaration is valid:
func GetPoint() struct{ x, y int } {
return struct{ x, y int }{1, 2}
}
Without having to use the struct keyword, a parsing ambiguity would arise in multiple uses. Let's say we want to create a function which returns an empty struct:
func GetEmpty() struct{} {
return struct{}{}
}
How would this look like without the struct keyword?
func GetEmpty2() {} {
return {}{}
}
Now if you're the compiler, what would you make out of this? Is this a function with the same signature as GetEmpty()? Or is this a function without a return value and an empty body (func GetEmpty2() {}) followed by a block which contains a return statement? The return statement would be another ambiguity, as it may return nothing which is followed by 2 empty blocks, or it may return an empty struct value which is followed by an empty block...
Now to avoid parsing ambiguity, we have to use the struct keyword when specifying struct types elsewhere (outside of type declarations), then why make it optional or disallow it in type declarations?
I think a consistent syntax is more important than grabbing all chances to reduce the language (syntax) to the minimum possible. That hurts readability big time. The for loop example you mentioned is not really a simplification, but rather the usage of different forms of the for loop.

Object instantiation by reference

Here is a sample of Go code which I do not really understand:
type MyClass struct {
field1 string
field2 string
}
...
objectinstance1 := MyClass{field1:"Hello", field2:"World"}
objectinstance2 := &MyClass{field1:"Hello", field2:"World"}
I can do exactly the same thing with objectinstance1 and objectinstance2 (method call for example) with the same syntax.
So I do not understand the role of the & operator. What I understand is that objectinstance1 contains an object whereas objectinstance2 contains a pointer.
It is for me the same thing in C than the difference between char and char*.
But in this case I should use -> instead of . (dot)?
The & operator gives you a pointer to a struct, while not using it gives you the struct value.
The biggest place this is relevant is when you pass this struct over to another function - if you pass the pointer that you made using the & operator, the other function has access to the same struct. If that function changes it, you've got the changed struct as well.
If you pass the variable that you made without the & operator, the function that you pass it to has a copy of the struct. There is nothing that that function or any other function can possibly do to change what you see in your variable.
This effectively makes the value variable safe for use across multiple go routines with no race conditions - everyone has their own copy of the struct.
If you pass the pointer made with & to other go routines, all have access to the same struct, so you really want that to be intentional and considered.
Difference is not visible because it’s hidden in 2 things:
Operator := which assigns value and type for a variable simultaneously. So it looks like objectinstance1 and objectinstance2 are the same. But in fact first is a MyClass instance and second is a pointer to it. It will be more palpable if use long-form operator:
var objectinstace1 MyClass = MyClass{}
var objectinstance2 *MyClass = &MyClass{}
If you omit * or & variable and type become incompatible and assignment fails.
Implicit pointer indirection. Go does it automatically in statements like ptr1.Field1 to access a specific field in struct by pointer to it.
Only on rare cases when there’s ambiguity you have to use full form:
*ptr1.Value1
or sometimes even:
(*ptr1).Value1
UPDATE:
Explicit pointer usage for disambiguation:
type M map[int]int
func (m *M) Add1() {
// this doesn't work - invalid operation: m[1] (type *M does not support indexing)
// m[1] = 1
// the same - invalid operation: m[1] (type *M does not support indexing)
// *m[1] = 1
// this works
(*m)[1] = 1
}
https://play.golang.org/p/JcXd_oNIAw
But in this case i should use -> instead of . (dot) ?
No. Golang is not C is not Golang. In Golang there is no ->. You use dot (.) for pointers aswell. Golang is meant to be simple, there is no point in introducing another operator if the intention is clear (what else would . on a pointer mean than calling a method?)
In go, the & operator takes the address of its argument and returns a pointer to the type of the argument.
Pointer indirection happens automatically so there is no -> operator, the dot operator handles all field (member) operations and accesses for all types, whether a pointer or a struct.
package main
import (
"fmt"
"reflect"
)
func main() {
type Foo struct{ name string }
foo1 := Foo{"Alpha"} // A plain struct instance.
foo2 := &Foo{"Bravo"} // A pointer to a struct instance.
fmt.Printf("foo1=%v, name=%v\n", reflect.TypeOf(foo1), foo1.name)
fmt.Printf("foo2=%v, name=%v\n", reflect.TypeOf(foo2), foo2.name)
// foo1=main.Foo, name=Alpha
// foo2=*main.Foo, name=Bravo
}

map[T]struct{} and map[T]bool in golang

What's the difference? Is map[T]bool optimized to map[T]struct{}? Which is the best practice in Go?
Perhaps the best reason to use map[T]struct{} is that you don't have to answer the question "what does it mean if the value is false"?
From "The Go Programming Language":
The struct type with no fields is called the empty struct, written
struct{}. It has size zero and carries no information but may be
useful nonetheless. Some Go programmers use it instead of bool as the
value type of a map that represents a set, to emphasize that only the
keys are significant, but the space saving is marginal and the syntax
more cumbersome, so we generally avoid it.
If you use bool testing for presence in the "set" is slightly nicer since you can just say:
if mySet["something"] {
/* .. */
}
Difference is in memory requirements. Under the bonnet empty struct is not a pointer but a special value to save memory.
An empty struct is a struct type like any other. All the properties you are used to with normal structs apply equally to the empty struct. You can declare an array of structs{}s, but they of course consume no storage.
var x [100]struct{}
fmt.Println(unsafe.Sizeof(x)) // prints 0
If empty structs hold no data, it is not possible to determine if two struct{} values are different.
Considering the above statements it means that we may use them as method receivers.
type S struct{}
func (s *S) addr() { fmt.Printf("%p\n", s) }
func main() {
var a, b S
a.addr() // 0x1beeb0
b.addr() // 0x1beeb0
}

Resources