In Golang spec:
type (
T0 []string
T1 []string
)
it says T0 and T1 are different because they are named types with distinct declarations.but there is a rule:
Two named types are identical if their type names originate in the same TypeSpec.
so why T0 and T1 are different?
EDIT:
in spec it also says:
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.
Given:
type (
T0 []string
T1 []string
)
The Go Programming Language Specification
Version of June 28, 2017
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.
TypeDef = identifier Type .
The new type is called a defined type. It is different from any other
type, including the type it is created from.
A defined type is always different from any other type. Otherwise, two
types are identical if their underlying type literals are structurally
equivalent; that is, they have the same literal structure and
corresponding components have identical types.
T0 and T1 are defined types and are, therefore, different.
References:
The Go Programming Language
Specification
Version of June 28, 2017
Types
A type determines a set of values together with operations and methods
specific to those values. A type may be denoted by a type name, if it
has one, or specified using a type literal, which composes a type from
existing types.
Named instances of the boolean, numeric, and string types are
predeclared. Other named types are introduced with type declarations.
Type declarations
A type declaration binds an identifier, the type name, to a type. Type
declarations come in two forms: alias declarations and type
definitions.
TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
TypeSpec = AliasDecl | TypeDef .
Alias declarations
An alias declaration binds an identifier to the given type.
AliasDecl = identifier "=" Type .
Within the scope of the identifier, it serves as an alias for the
type.
Type definitions
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.
TypeDef = identifier Type .
The new type is called a defined type. It is different from any other
type, including the type it is created from.
Type identity
Two types are either identical or different.
A defined type is always different from any other type. Otherwise, two
types are identical if their underlying type literals are structurally
equivalent; that is, they have the same literal structure and
corresponding components have identical types.
Related
If I define a type definition
type X int64
Why is it that I can then do
var x X = 123
x = x + 1
The x behaves as if it was the underlying int64, which I don't want. Or that it allows operations on the underlying type to be performed on this new type?
One of the reasons I'd define a new type is to hide the underlying type and define my own operations on it.
Creating a new defined type will dissociate any methods on the underlying type, but it does not dissociate functionality with operators such as + - / *.
A defined type may have methods associated with it. It does not inherit any methods bound to the given type
You should base your type on an underlying type with the desirable operators. For example, if you don't want to have arithmetic operators, you can derive from a struct.
If your type still needs the arithmetic capabilities of an int64 for internal reasons, you can hide it as an un-exported field in the struct. For example:
type X struct {
number int64
}
From the specs on conversion, I read
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 are not type parameters but have identical underlying types.
[..]
From the above specs, I would have expected the following code to compile
package main
import "github.com/fxtlabs/date"
type Date struct {
day int32
}
func main() {
_ = date.Date(Date{12345})
}
However, it does not compile with error message
cannot convert Date{…} (value of type Date) to type date.Date
Note that "github.com/fxtlabs/date".Date is defined here as
type Date struct {
// day gives the number of days elapsed since date zero.
day int32
}
Why does it fail to compile? Is it because the field day from "github.com/fxtlabs/date".Date is unexported? If yes, shouldn't this be specified in the specs?
Is it because the field day from "github.com/fxtlabs/date".Date is unexported?
Yes.
If yes, shouldn't this be specified in the specs?
It is in the spec under Type Identity.
Two struct types are identical if they have the same sequence of fields, and if corresponding fields have the same names, and identical types, and identical tags. Non-exported field names from different packages are always different.
In other words, the underlying types are NOT identical because their fields are unexported.
Example of identical types struct {Day int32} (packag a) and struct{Day int32} (package b).
Example of NOT identical types struct {day int32} (packag a) and struct{day int32} (package b).
I was reading this slideshow, which says:
var hits struct {
sync.Mutex
n int
}
hits.Lock()
hits.n++
hits.Unlock()
How does that work exactly? Seems like hits isn't composed of a mutex and integer, but is a mutex and integer?
It is composition. Using an anonymous field (embedded field), the containing struct will have a value of the embedded type, and you can refer to it: the unqualified type name acts as the field name.
So you could just as easily write:
hits.Mutex.Lock()
hits.n++
hits.Mutex.Unlock()
When you embed a type, fields and methods of the embedded type get promoted, so you can refer to them without specifying the field name (which is the embedded type name), but this is just syntactic sugar. Quoting from Spec: Selectors:
A selector f may denote a field or method f of a type T, or it may refer to a field or method f of a nested embedded field of T.
Beyond the field / method promotion, the method set of the embedder type will also contain the method set of the embedded type. Quoting from Spec: Struct types:
Given a struct type S and a defined type T, promoted methods are included in the method set of the struct as follows:
If S contains an embedded field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.
If S contains an embedded field *T, the method sets of S and *S both include promoted methods with receiver T or *T.
This is not inheritance in the OOP sense, but something similar. This comes handy when you want to implement an interface: if you embed a type that already implements the interface, so will your struct type. You can also provide your own implementation of some methods, which gives the feeling of method overriding, but must not be forgetten that selectors that denote methods of the embedded type will get the embedded value as the receiver (and not the embedder value), and selectors that denote your methods defined on the struct type (that may or may not "shadow" a method of the embedded type) will get the embedder struct value as the receiver.
It's called embedding, hits is composed of a sync.Mutex and an int. This should be true since there is really no inheritance in Go. This is more of a "has a" rather than an "is a" relationship between the members and the struct.
Read here for a more complete explanation
Quoted from the link
The methods of embedded types come along for free
That means you can access them like hits.Lock() instead of the longer form hits.Mutex.Lock() because the function Lock() is not ambiguous.
See the Go-syntax representation of hits variable:
fmt.Printf("%#v\n", &hits)
// &struct { sync.Mutex; n int }{Mutex:sync.Mutex{state:0, sema:0x0}, n:1}
When you declare the variable, it simply initializes the fields in struct with their default values.
Also, compiler automatically sets the name of the embedded struct as a field. So you can also access like:
hits.Mutex.Lock()
hits.Mutex.Unlock()
And you have access to all methods and exported fields (if any) of sync.Mutex.
I am learning Go language and comes across seeing this type of variable declaration:
i:=1;
But it says that Go has static variables. i,e variables should be defined in some way like this
var i int=1;
So what is the difference between these two methods? In the first one we don't need to indicate the data type. Why is it so?
The first one i := 1 is called short variable declaration. It is a shorthand for regular variable declaration with initializer expressions but no types:
var IdentifierList = ExpressionList
You don't specify the type of i, but i will have a type based on certain rules. Its type will be automatically inferred. In this case it will be of type int because the initializer expression 1 is an untyped integer constant whose default type is int, so when a type is needed (e.g. it is used in a short variable declaration), int type will be deduced.
So Go is statically typed. That means variables will have a static type and values stored in them at runtime will always be of that type. Being statically typed does not mean you have to explicitly specify the static type, it just means variables must have a static type - decided at compile time - which condition is met even if you use short variable declaration and you don't specify it.
Note that you can also omit the type if you declare a variable with the var keyword:
var i = 1
In which case the type will also be deduced from the type of the initializer expression.
Spec: Variable declaration:
If a type is present, each variable is given that type. Otherwise, each variable is given the type of the corresponding initialization value in the assignment. If that value is an untyped constant, it is first converted to its default type; if it is an untyped boolean value, it is first converted to type bool. The predeclared value nil cannot be used to initialize a variable with no explicit type.
Go is designed with ease of use in mind. So new variables are able to get an implicit type of the right side using the := operator. Also the constant 1 for example has an implicit type in go.
I came across this type declaration:
type Handler func(*Conn)
type Server struct {
Handshake func(*Config, *http.Request) error
Handler
}
(this is a simplified version of https://github.com/golang/net/blob/38c17adf51120973d1735785a7c02f8ce8297c5e/websocket/server.go#L55-L66
The second field in the Server structure is anonymous. There is just type and no name.
Here is the grammar for type declarations (https://golang.org/ref/spec#Type_declarations):
TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
TypeSpec = identifier Type .
and it clearly requires an identifier name. But yet the section that I referenced that contains the grammar, also mentions anonymous fields.
I do not understand why this syntax is correct and how anonymous fields are used.
You want to look at the part of the grammar that has to do with structures, not just types. See: Struct types and the use of AnonymousField. Looking just at the production for TypeSpec is focusing attention on the wrong place. Instead, look at FieldDecl; the grammar shows that we have two possibilities: named fields (IdentifierList Type), or anonymous fields (AnonymousField).
Anonymous fields are typically used for embedding. In your example, a Server will act like a Handler because it has embedded that field.