This question already has an answer here:
Go generics: invalid composite literal type T
(1 answer)
Closed last month.
The following code results in the error "invalid composite literal type T".
package main
import "fmt"
func main() {
fmt.Println(createThing[foo]())
}
type thing interface {
foo | bar
}
type foo struct {
id int
a string
}
type bar struct {
id int
b int
}
func createThing[T thing, P *T]() P {
return &T{}
}
If I only include foo in interface thing, or remove a string and b int so foo and bar are exactly the same, the code will run without error. However, doesn't this defeat the purpose of generics? Why can't I instantiate a generic type like this, especially when I'm not even accessing any fields?
Possibly related to https://github.com/golang/go/issues/48522
Most generic types are not valid types for composite literals. This isn't a problem though, as there are other ways to create values of generic types.
To create a pointer to a new zero value:
func createThing[T thing]() *T {
return new(T)
}
Or to create a non-pointer zero value:
func createThing[T thing]() T {
var value T
return value
}
As for why the error occurs in this way, here's the explanation from the spec, revised to address your specific question.
For composite literals:
The LiteralType's core type T must be a struct, array, slice, or map type
What is the core type?
An interface T has a core type if [...] there is a single type U which is the underlying type of all types in the type set of T
No other interfaces have a core type.
What is the underlying type?
Each type T has an underlying type: If T is one of the predeclared boolean, numeric, or string types, or a type literal, the corresponding underlying type is T itself. Otherwise, T's underlying type is the underlying type of the type to which T refers in its declaration.
A "type literal" can refer to a literal struct type, like struct{int id}. So, when foo and bar both have an underlying type of struct{int id}, then thing has a core type of struct{int id}, and so composite literals are possible. When foo and bar don't have the same underlying type, then thing has no core type, and composite literals are not possible, hence your error.
The formal definition may seem complicated, but the result and practical takeaway is simple: generic code is only capable of expressing common behaviour across the possible types. Besides in the special case where all underlying types are the same, literal values are not a common behaviour.
Related
I'm trying to figure out how go handles type conversion between structs. Everything I have read tells me that types with the same underlying type are considered compatible and type conversion happens implicitly. If that is the case, why does the code below not work? Both Foo and Bar implement the FooI interface, and they both add an x property of type string. Yet, when I pass a struct of type Bar to AcceptBarOrFoo that expects a struct of type Foo, I get a type mismatch compile error.
Go Playground
package main
import (
"play.ground/bar"
"play.ground/foo"
)
func main() {
AcceptBarOrFoo(bar.Bar{})
}
func AcceptBarOrFoo(foo.Foo) interface{} {
return nil
}
// -- iface/iface.go --
package iface
type FooI interface {
a() string
b(int) int
}
// -- foo/foo.go --
package foo
import (
"play.ground/iface"
)
type Foo struct {
iface.FooI
x string
}
// -- bar/bar.go --
package bar
import (
"play.ground/iface"
)
type Bar struct {
iface.FooI
x string
}
Foo's x is different from Bar's x because non-exported identifiers are never equal across package boundaries. Fix by exporting the fields in foo.Foo and bar.Bar:
type Foo struct {
iface.FooI
X string // <-- start with capital letter to export
}
To use a foo.Foo or bar.Bar as an argument value, a foo.Foo and bar.Bar must be assignable to the argument's type. It does not work to use foo.Foo as the argument type because named types are not assignable to each other. However, named types are assignable to unnamed types when the two types share the same underlying type. Declare the argument as an unnamed type:
func AcceptBarOrFoo(struct {
iface.FooI
X string
}) interface{} {
return nil
}
With these changes, the following code compiles:
AcceptBarOrFoo(bar.Bar{})
AcceptBarOrFoo(foo.Foo{})
Run the example on the Go playground
Another option is to use a conversion to a common type. In the following code, foo.Foo is the common type and bar.Bar is converted to a foo.Foo.
func Accept(foo.Foo) interface{} {
return nil
}
...
Accept(foo.Foo{})
Accept(foo.Foo(bar.Bar{}))
Run the example on the Go playground.
Note: foo.Foo and bar.Bar must have the same fields for the above to work (field names are exported, fields in same order, fields have same types).
Some notes about Go:
There are conversions from one concrete type to another.
Go is famous for having no implicit conversions in expressions, but there are implicit conversions in some assignment scenarios.
You cannot convert one concrete type to another concrete type, ever. They are not the same. There is no way to define this type of automatic casting in Go. At best, you could define a function that accepts a Bar and builds and returns a new Foo with its fields set to the same values as the input Bar.
Everything I have read tells me that if the underlying types are the same, the higher order types are considered compatible and type conversion happens implicitly
It's unclear what your source for this is, but nothing would have ever stated or implied this, it's simply not true. Go does no implicit conversion, of anything. That's a big, loudly advertised feature of Go. Given type Foo struct { a int } and type Bar struct { a int }, you can never assign an object of type Bar to a variable of type Foo.
You can convert from either concrete type to an interface type, when the type satisfies the interface. Your AcceptBarOrFoo method should accept an interface type (which both Foo and Bar satisfy), not a concrete type. Given that interfaces only define methods (not members), and given neither Foo or Bar have any methods, your interface would be the empty interface, interface{}. The value passed in would serve no purpose, except for you to later convert it back to a concrete type to access its members, but that's not really what interfaces are for.
I just want to confirm if my understanding is correct about interface{}{}
Does interface{}{} mean a composite literal of interface type?
So, if I wanted to pass a composite type, lets say []byte as a interface{}, I should assign it to a variable of type interface{}{} and pass in that variable, whereas if I wanted to pass a non composite type, such as a int as a interface{}, I should assign it to a variable of type interface{} and pass in that variable.
Is my understanding correct on this?
interface{}{} is invalid syntax.
It is not an empty interface composite literal — there's no such thing. The following don't compile:
var a interface{}{} = "foo" // not a type
b := interface{}{} // not a value
From the specs Composite Literals:
Composite literals construct values for structs, arrays, slices, and maps and create a new value each time they are evaluated.
The valid syntax is interface{}, which is the empty interface, i.e. an interface with no name and empty method set.
If you compare it to a named interface, you will see that the extra set of curly braces at the end makes no sense:
type Fooer interface {
Foo() error
}{} // ???
You can instantiate an empty interface{} by converting nil:
a := (interface{})(nil)
Or you can declare a var of unnamed interface type:
type A struct {}
func (a A) Foo() string {
return "foo"
}
var a interface{ Foo() string } = A{}
To answer your question:
So, if I wanted to pass a composite type [...]
you can assign any value to a variable of type interface{}, that's about it. Whether the value is composite or not is irrelevant because all types satisfy the empty interface:
var a interface{} = []byte{0x01, 0x02}
var b interface{} = "string_literal"
Playground: https://play.golang.org/p/w-l1dU-6Hb5
The empty interface interface{} essentially says "I don't care". Anything can be passed as an empty interface. So for your examples they all could be stored as the empty interface.
Possibly a more interesting question is why you want to avoid types in the first place, and what you're trying to achieve. But for the purposes of using interface{} you can pass anything to it, even a "nil".
interface{} type of empty interface.
you assign []byte or int to any empty variable of empty interface (interface{} type) or you can pass it directly to function that exepts interface values.
In Go, because of it's static type language we can see lot of type conversion for example,
var x float64
var y =32
x=float64(32)
Even though Go supports type casting, as far as I know it's very rarely used in. Can someone explain why and usecases that type casting can be used. Following is a one example that use type casting.
type Common struct {
Gender int
From string
To string
}
type Foo struct {
Id string
Name string
Extra Common
}
type Bar struct {
Id string
Name string
Extra Common
}
foo:=Foo{
Id:"123",
Name:"damitha",
Extra: struct {
Gender int
From string
To string
}{Gender:1 , From:"xx", To:"yy" },
}
bar:=*(*Bar)(unsafe.Pointer(&foo))
fmt.Printf("%+v\n",bar)
Even this mapping also possible to achieve in more safer ways.
The unsafe shenanigans in the question are similar to type casting. These shenanigans are not needed. Use a conversion:
bar := *(*Bar)(&foo)
or more simply:
bar := Bar(foo)
The relevant quote from the specification is:
A non-constant value x can be converted to type T in any of these cases:
...
ignoring struct tags (see below), x's type and T have identical underlying types.
ignoring struct tags (see below), x's type and T are pointer types that are not defined types, and their pointer base types have identical underlying types.
The first point in the quote applies to Bar(foo) because Foo and Bar have identical underlying types.
The second point in the quote applies to the conversion (*Bar)(&foo) because:
*Foo and *Bar are pointer types
*Foo and *Bar are not defined types.
The base types Foo and Bar have the same underlying type.
Go supports neither type casting nor implicit type conversion while lot of static support languages like Java C/C++ supporting both. Go only supports for type conversion.
This is a Go grammar question and seems a stupid question but I've been checking the Go language specification to find some official words or definitions to define what type is a xxx type, say, what type is an interface type?
For example, I see words like these:
The method set of an interface type is its interface.
Or
An embedded field must be specified as a type name T or as a pointer to a non-interface type name *T, and T itself may not be a pointer type.
Or
Consider a struct type T with two methods ...
type T struct {
a int
}
....
A type literal like struct {...} is a struct type, what about A in
type A struct {...} and B in type B interface{...}? Is A a struct type and B an interface type?
Yes, from the above sample for the struct type T, I can tell that a defined type (by the "type" declaration) whose given type is a struct type or interface type is also a struct or interface type. So A is a struct type and B is an interface type also. But where are the official definitions of this rule?
For defined types I can only find the following relating to type categories:
A type definition creates a new, distinct type with the same underlying type and operations as the given type, and binds an identifier to it.
So my understanding is that the defined type is a new, distinct type with the given type, but they are in the same type category, say, interface types or struct types. Still, there are no such definitions.
TLDR;
The kind of type T is interface if its underlying type is an interface type.
The kind of type T is struct if its underlying type is a struct type.
Spec: Struct types and Spec: Interface types specifies exactly what are the struct and interface types:
StructType = "struct" "{" { FieldDecl ";" } "}" .
FieldDecl = (IdentifierList Type | EmbeddedField) [ Tag ] .
EmbeddedField = [ "*" ] TypeName .
Tag = string_lit .
InterfaceType = "interface" "{" { MethodSpec ";" } "}" .
MethodSpec = MethodName Signature | InterfaceTypeName .
MethodName = identifier .
InterfaceTypeName = TypeName .
So for example these are struct types:
struct { A int }
struct {}
struct { _ int }
and these are interface types:
interface { String() string }
interface {}
We may use a type declaration to create a new type, such as:
type Point struct { X, Y int }
The above type definition creates a new, distinct type with the same underlying type and operations as the given type, and binds an identifier to it. The definition of underlying type is recursive:
Each type T has an underlying type: If T is one of the predeclared boolean, numeric, or string types, or a type literal, the corresponding underlying type is T itself. Otherwise, T's underlying type is the underlying type of the type to which T refers in its type declaration.
When we talk about arbitrary types being structs or interfaces, we're talking about their kind.
In the light of this, basically your question is equivalent to this:
"When is the kind of an arbitrary type interface or struct?"
The answer to this question is not in the spec, but this is how we could define it:
The kind of a type T is interface if its underlying type is an interface type.
Similarly:
The kind of a type T is struct if its underlying type is a struct type.
So for example:
type Point struct { X, Y int }
type PP Point
Is the type struct { X, Y int } of kind struct? Yes, because since it's a type literal, its underlying type is itself, and it's by definition a struct type.
Is Point a struct? Since the underlying type of Point is the underlying type of the type to which it refers in its type declaration, which is a type literal (see above), it is of struct type (its kind is struct).
Is PP a struct? Since its underlying type is the underlying type of the type to which it refers in its type declaration (which is Point), whose underlying type is a struct type literal, yes, it is also a struct type.
This kind we're talking about is represented by the reflect.Kind type. There are reflect.Interface and reflect.Struct constants (of type reflect.Kind) to represent the struct and interface kinds. And the reflect.Type type descriptor has a Type.Kind() method to access this kind.
This is how you can check if the type (kind) of some value is a struct for example:
func isStruct(i interface{}) bool {
return reflect.TypeOf(i).Kind() == reflect.Struct
}
Testing it (try it on the Go Playground):
fmt.Println(isStruct(Point{})) // true
fmt.Println(isStruct(PP{})) // true
fmt.Println(isStruct(struct{}{})) // true
fmt.Println(isStruct("text")) // false
Checking for interface type is a little more complicated because passing an interface value to a function that expects interface{} will not pass the interface value as-is but the concrete value "stored" in it, and as an interface{} value. We would have to pass a pointer to interface (which otherwise rarely makes sense in Go), access the element type and check its kind. For details, see this answer: What is the difference between reflect.ValueOf() and Value.Elem() in go?
An interface type is a type introduced by the interface keyword, or a name for such a type as defined by type name interface (plus of course the actual requirements for that interface).
Any type, whether it is an interface type or not, implements an interface type if it has the appropriate set of named methods. That is, a struct type may be sufficient to be used with some interface type. Even a non-struct type may be sufficient:
type foo int
func (receiver_arg foo) method1() { ... }
Type-name foo now implements any interface that requires a method named method1 (provided of course that it implements the rest of any required methods).
... the defined type [via the type keyword] is a new, distinct type with the given type, but they are in the same type category ...
Yes, just so. Using reflect, you'll find that they have the same Kind. The word kind isn't in the spec like this but it's quite useful, and the link here enumerates all the fundamental type-kinds in Go.
I was wondering why you can't do:
type Foo struct { A int }
type Bar Foo
foos := []Foo{Foo{1}, Foo{2}}
bars := []Bar(foos)
//cannot convert foos (type []Foo) to type []Bar
and I found out that this would require the runtime to perform a loop over the slice to convert each of the elements, which would be non-idiomatic Go. This makes sense.
However, could this not be solved by the compiler just aliasing Bar as Foo, so internally they're the same and they use the same type header underneath? I'm guessing the answer is no though I'm curious as to why.
This:
[]Bar(foos)
is a type conversion. Conversions have specific rules according to the spec:
A non-constant value x can be converted to type T in any of these cases:
x is assignable to T.
x's type and T have identical underlying types.
x's type and T are unnamed pointer types and their pointer base types have identical underlying types.
x's type and T are both integer or floating point types.
x's type and T are both complex types.
x is an integer or a slice of bytes or runes and T is a string type.
x is a string and T is a slice of bytes or runes.
None applies here. Why?
Because the underlying type of []Foo is not the same as the underlying type of []Bar. And a value of type []Foo is not assignable to a variable of type []Bar, see Assignability rules here.
The underlying type of Foo is the same as the underlying type of Bar, but the same does not apply to slices where the element type is Foo and Bar.
So the following works:
type Foo struct{ A int }
type Foos []Foo
type Bars Foos
func main() {
foos := []Foo{Foo{1}, Foo{2}}
bars := Bars(foos)
fmt.Println(bars)
}
Output (try it on the Go Playground):
[{1} {2}]
Note that since the actual memory representation of Foo and Bar is the same (because the underlying type of Bar is Foo), in this case using the package unsafe you can "view" a value of []Foo as a value of []Bar:
type Foo struct{ A int }
type Bar Foo
func main() {
foos := []Foo{Foo{1}, Foo{2}}
bars := *(*[]Bar)(unsafe.Pointer(&foos))
fmt.Println(bars)
fmt.Printf("%T", bars)
}
This: *(*[]Bar)(unsafe.Pointer(&foos)) means that take the address of foos, convert it to unsafe.Pointer (according to spec all pointers can be converted to unsafe.Pointer), then this Pointer is converted to *[]Bar (again according to the spec Pointer can be converted to any other pointer type), and then this pointer is dereferenced (* operator), so the result is a value of type []Bar as can be seen in the output.
Output (try it on the Go Playground):
[{1} {2}]
[]main.Bar
Notes:
Quoting the package doc of unsafe:
Package unsafe contains operations that step around the type safety of Go programs.
Packages that import unsafe may be non-portable and are not protected by the Go 1 compatibility guidelines.
What does this mean? It means that you shouldn't revert to using package usafe every time it makes your life easier. You should only use it in exceptional cases, when not using it would make your program really slow and complicated.
In your program this is not the case as I proposed a working example with just a little refactoring (Foos and Bars being slices).
unsafe steps around the type safety of Go. What does this mean? If you would change the type of foos (e.g. drastically like foos := "trap!"), your program would still compile and run, but most likely runtime panic would occur. Using usafe you lose type checks of the compiler.
While if you use my other proposal (Foos and Bars), such changes/typos are detected at compile time.
As mentioned in "Why can I type alias functions and use them without casting?"
In Go, there is no such thing as a type alias.
The type keyword introduces new named types. They are not aliases
If you compare two named types, the names must match in order for them to be interchangeable
This is what the spec mentions:
A type declaration binds an identifier, the type name, to a new type that has the same underlying type as an existing type, and operations defined for the existing type are also defined for the new type.
The new type is different from the existing type.