Why to use "redundant" keyword "struct" for types in Go? - 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.

Related

go generics: how to declare a type parameter compatible with another type parameter

I'm looking for a way to declare type compatibility between type parameters in Go generics constraints.
More specifically, I need to say some type T is compatible with another type U. For instance, T is a pointer to a struct that implements the interface U.
Below is a concrete example of what I want to accomplish:
NOTE: Please, do not answer with alternative ways to implement "array prepend". I've only used it as a concrete application of the problem I'm looking to solve. Focusing on the specific example digresses the conversation.
func Prepend[T any](array []T, values ...T) []T {
if len(values) < 1 { return array }
result := make([]T, len(values) + len(array))
copy(result, values)
copy(result[len(values):], array)
return result
}
The above function can be called to append elements of a given type T to an array of the same type, so the code below works just fine:
type Foo struct{ x int }
func (self *Foo) String() string { return fmt.Sprintf("foo#%d", self.x) }
func grow(array []*Foo) []*Foo {
return Prepend(array, &Foo{x: len(array)})
}
If the array type is different than the elements being added (say, an interface implemented by the elements' type), the code fails to compile (as expected) with type *Foo of &Foo{…} does not match inferred type Base for T:
type Base interface { fmt.Stringer }
type Foo struct{ x int }
func (self *Foo) String() string { return fmt.Sprintf("foo#%d", self.x) }
func grow(array []Base) []Base {
return Prepend(array, &Foo{x: len(array)})
}
The intuitive solution to that is to change the type parameters for Prepend so that array and values have different, but compatible types. That's the part I don't know how to express in Go.
For instance, the code below doesn't work (as expected) because the types of array and values are independent of each other. Similar code would work with C++ templates since the compatibility is validated after template instantiation (similar to duck typing). The Go compiler gives out the error invalid argument: arguments to copy result (variable of type []A) and values (variable of type []T) have different element types A and T:
func Prepend[A any, T any](array []A, values ...T) []A {
if len(values) < 1 { return array }
result := make([]A, len(values) + len(array))
copy(result, values)
copy(result[len(values):], array)
return result
}
I've tried making the type T compatible with A with the constraint ~A, but Go doesn't like a type parameter used as type of a constraint, giving out the error type in term ~A cannot be a type parameter:
func Prepend[A any, T ~A](array []A, values ...T) []A {
What's the proper way to declare this type compatibility as generics constraints without resorting to reflection?
This is a limitation of Go's type parameter inference, which is the system that tries to automatically insert type parameters in cases where you don't define them explicitly. Try adding in the type parameter explicitly, and you'll see that it works. For example:
// This works.
func grow(array []Base) []Base {
return Prepend[Base](array, &Foo{x: len(array)})
}
You can also try explicitly converting the *Foo value to a Base interface. For example:
// This works too.
func grow(array []Base) []Base {
return Prepend(array, Base(&Foo{x: len(array)}))
}
Explanation
First, you should bear in mind that the "proper" use of type parameters is to always include them explicitly. The option to omit the type parameter list is considered a "nice to have", but not intended to cover all use cases.
From the blog post An Introduction To Generics:
Type inference in practice
The exact details of how type inference works are complicated, but using it is not: type inference either succeeds or fails. If it succeeds, type arguments can be omitted, and calling generic functions looks no different than calling ordinary functions. If type inference fails, the compiler will give an error message, and in those cases we can just provide the necessary type arguments.
In adding type inference to the language we’ve tried to strike a balance between inference power and complexity. We want to ensure that when the compiler infers types, those types are never surprising. We’ve tried to be careful to err on the side of failing to infer a type rather than on the side of inferring the wrong type. We probably have not gotten it entirely right, and we may continue to refine it in future releases. The effect will be that more programs can be written without explicit type arguments. Programs that don’t need type arguments today won’t need them tomorrow either.
In other words, type inference may improve over time, but you should expect it to be limited.
In this case:
// This works.
func grow(array []*Foo) []*Foo {
return Prepend(array, &Foo{x: len(array)})
}
It is relatively simple for the compiler to match that the argument types of []*Foo and *Foo match the pattern []T and ...T by substitutingT = *Foo.
So why does the plain solution you gave first not work?
// Why does this not work?
func grow(array []Base) []Base {
return Prepend(array, &Foo{x: len(array)})
}
To make []Base and *Foo match the pattern []T and ...T, just substituting T = *Foo or T = Base provides no apparent match. You have to apply the rule that *Foo is assignable to the type Base to see that T = Base works. Apparently the inference system doesn't go the extra mile to try to figure that out, so it fails here.

When is the tilde not necessary in Go generics?

With Golangs new generics we have the tilde operator ~ which will match the underlying type. In what case is it valid to NOT match the underlying type? I'm trying to understand why the current behavior with the tilde is not the default behavior. It seems unnecessary to support both.
For example, why would you write
interface { int }
and not
interface { ~int }
What benefit to you would it be to write a method that is so strict that it could not accept something like
type MyInt int
Why is the tilde behavior not the default, and thus the language would not require another operator?
Not using the ~ operator means you only accept the listed exact types. Why should this matter?
You may want to use the values of the exact types to set to other variables and else type conversion would be required. And because the saying goes "new type, new method set". New types having the same underlying type have their own method sets.
You may want the "original" behavior of the value, which may change if it has a different method set.
For example, let's say you want to print the number like this:
type Num interface{ ~int }
func foo[T Num](v T) {
fmt.Println(v)
}
If MyInt has a String() string method:
type MyInt int
func (m MyInt) String() string { return "bar" }
The output might not be what foo() would want, because the fmt package checks if a printed value has a String() string method, and if so, it is called to acquire its string representation:
foo(1)
foo(MyInt(1))
This will output (try it on the Go Playground):
1
bar
If you only allow int:
type Num interface{ int }
You can still call foo() with a value of type MyInt, using a type conversion:
foo(1)
x := MyInt(1)
foo(int(x))
And output will be what foo() wants, not what MyInt would want (try this one on the Go Playground):
1
1
Yes, this would also be possible if foo() itself would do the conversion, but this clearly documents you want a pure int, with int's behavior, and not something that is an int with a different, custom behavior.
Why is the tilde behavior not the default
Because it would be confusing and semantically unsound to write a function like func Foo[T int](v T) that accepts type parameters that are not int. Then the meaning of int in interface constraints would not be the same as everywhere else. (More on this discussion)
What benefit to you would it be to write a method that is so strict [...]
Indeed if the constraint includes only one exact type, using type parameters is moot. If the type set of the constraint has cardinality 1, you should just remove the type parameter.
A function like:
func Foo[T int](v T)
can only ever be instantiated with exactly int, so it can (and should!) be simply written with regular arguments:
func Foo(v int)
When the type set cardinality is N, which includes single tilde types, but also unions, makes it basically impossible to write exhaustive type switch, since using ~ in case statements is not allowed (yet?):
func Foo[T ~int | ~string](v T) {
switch t := any(v).(type) {
case int: // ok
case string: // ok
// how to match other possible types then?
}
}
In this particular case, an exhaustive type switch can be written only if the constraint includes exact types:
func Foo[T int | string](v T) {
switch t := any(v).(type) {
case int: // ok
case string: // ok
default:
panic("should not occur")
}
}
This should not arise frequently in practice: if you find yourself switching on the type parameter, you should ask yourself if the function really needs to be generic. However the use case is relevant when designing your code.
Why is the tilde behavior not the default, and thus the language would not require another operator?
Because if the approximation would be the default unconditionally you could not express the fact that your polymorphic function requires an int and not a MyInt. You would then have to introduce an operator like strict and write %int. Nothing gained.

Can I get a variable of a type based on reflect.Type [duplicate]

I have a function which takes an interface, like this:
func method(data interface{})
.. because I need to process different structs which have common fields/methods. In this function I use data tens or hundreds of times, in different places. It's really unpleasant to add switch a.(type) { case .. case .. all the time.
Is there a way to create a variable with just one switch with needed type and then just use this variable everywhere later? Something like:
var a .... // something here
switch data.(type) {
case *Struct1:
a = data.(*Struct1)
case *Struct2:
a = data.(*Struct2)
}
// Continue with 'a' only
a.Param = 15
fmt.Println(a.String())
Go is a statically typed language, the type of a must be known at compile time. And since Go does not support generics yet, you can't do what you want.
Try to come up with some other solution, e.g. abstract away the things you want to do with a into an interface, and have the concrete types implement that interface. Then a can be a variable of this interface type, and you can call methods of it.
If you can achieve this, actually you can even change the parameter of the data type to this interface, and no type assertion or type switch is needed.
Alternatively you could use reflection to access common fields (either for get or set) identified by their name, but reflection provides no compile-time guarantee, and it's usually less efficient. For an example how to do that, see this question: Assert interface to its type
You can't do what you ask for in your question directly, go is statically typed, so you can't have one variable that can hold different types, and still access that variable as if it is typed.
If you're only working on the common struct fields in your method, you are perhaps better off gathering all the common variables in its own struct, illustrated below as the commons struct and have your method take that type as an argument
package main
import (
"fmt"
)
type commons struct {
name string
age int
}
type structA struct {
commons
other_stuff int
}
type structB struct {
commons
foo string
}
func method(c* commons) {
fmt.Println(c)
c.age +=1
}
func main() {
a := structA{commons{"foo", 44}, 1}
b := structB{commons{"bar", 33}, "test"}
method(&a.commons)
method(&b.commons)
fmt.Println(a)
}
Go playground
I can't figure out what is your real goal but if the "method" you want to write handles common fields from similar structures, and you cannot fix original structures using Type Embedding, as #nos said above, then you can try to make another structure for method-internal use:
var v Vehicle // with common fields
switch data.(type) {
case *Car:
v.Handle = data.(*Car).Handle // or CircleHandle
case *Motorcycle:
v.Handle = data.(*Motorcycle).Handle // or BarHandle
}
v.Degree = 15
v.Speed = 50
v.Direction = "left"
v.Style = "rough"
/// so many things on `v`...
steering(v)
I think it is not a good approach but sometimes... :-)

How to create a variable with needed type instead of type assertion

I have a function which takes an interface, like this:
func method(data interface{})
.. because I need to process different structs which have common fields/methods. In this function I use data tens or hundreds of times, in different places. It's really unpleasant to add switch a.(type) { case .. case .. all the time.
Is there a way to create a variable with just one switch with needed type and then just use this variable everywhere later? Something like:
var a .... // something here
switch data.(type) {
case *Struct1:
a = data.(*Struct1)
case *Struct2:
a = data.(*Struct2)
}
// Continue with 'a' only
a.Param = 15
fmt.Println(a.String())
Go is a statically typed language, the type of a must be known at compile time. And since Go does not support generics yet, you can't do what you want.
Try to come up with some other solution, e.g. abstract away the things you want to do with a into an interface, and have the concrete types implement that interface. Then a can be a variable of this interface type, and you can call methods of it.
If you can achieve this, actually you can even change the parameter of the data type to this interface, and no type assertion or type switch is needed.
Alternatively you could use reflection to access common fields (either for get or set) identified by their name, but reflection provides no compile-time guarantee, and it's usually less efficient. For an example how to do that, see this question: Assert interface to its type
You can't do what you ask for in your question directly, go is statically typed, so you can't have one variable that can hold different types, and still access that variable as if it is typed.
If you're only working on the common struct fields in your method, you are perhaps better off gathering all the common variables in its own struct, illustrated below as the commons struct and have your method take that type as an argument
package main
import (
"fmt"
)
type commons struct {
name string
age int
}
type structA struct {
commons
other_stuff int
}
type structB struct {
commons
foo string
}
func method(c* commons) {
fmt.Println(c)
c.age +=1
}
func main() {
a := structA{commons{"foo", 44}, 1}
b := structB{commons{"bar", 33}, "test"}
method(&a.commons)
method(&b.commons)
fmt.Println(a)
}
Go playground
I can't figure out what is your real goal but if the "method" you want to write handles common fields from similar structures, and you cannot fix original structures using Type Embedding, as #nos said above, then you can try to make another structure for method-internal use:
var v Vehicle // with common fields
switch data.(type) {
case *Car:
v.Handle = data.(*Car).Handle // or CircleHandle
case *Motorcycle:
v.Handle = data.(*Motorcycle).Handle // or BarHandle
}
v.Degree = 15
v.Speed = 50
v.Direction = "left"
v.Style = "rough"
/// so many things on `v`...
steering(v)
I think it is not a good approach but sometimes... :-)

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