Stumbling Into the Golang Spec and Trying to Make Sense of It

· Exploratory Technical Journaling/Rambling

I am not sure whether this is worth reading, because the Go specification is good and self-contained. Anyway, I’m writing this. The Go language specification describes a general standard for the language itself and describes the syntax using Wirth syntax notation , a variant of EBNF . So I want to learn about the interface type in Go, and the first thing I want to know is how it is formed within a program, and I headed to Go Programming Language Specification .

And I see:

InterfaceType  = "interface" "{" { InterfaceElem ";" } "}" .
InterfaceElem  = MethodElem | TypeElem .
MethodElem     = MethodName Signature .
MethodName     = identifier .
TypeElem       = TypeTerm { "|" TypeTerm } .
TypeTerm       = Type | UnderlyingType .
UnderlyingType = "~" Type .

And one may wonder, what are these weird things?! These, my friend, are rules that say what is an interface and what is not. Let’s start with InterfaceType. This is a starting rule, and yes, each line here is a rule that is composed to finally make InterfaceType.

Let’s see the first line:

InterfaceType  = "interface" "{" { InterfaceElem ";" } "}" .

This defines how the entire interface block is formed within a Go file, from this we can infer that every interface block starts with the "interface" keyword,

this, my friend, "<anything>" is a literal string, the exact text within "" must appear in input.

Followed by a "{", which is also a literal string, and we can see a matching closing curly bracket literal string also exists at the end. So now, all we have left is what goes inside the interface { <mystery 🪄> }. We see curly braces, not literal strings, wrapped around the rule InterfaceElem and ";".

these curly brackets indicate repetition in this notation, specifically 0 to n times, for example { "a" }c can be “ac” or “c” or “a” repeated n number of times followed by a “c”

InterfaceElem is another rule. Here, we can compose rules together to manage complexity. It is similar to what we’ve seen, plus more operators, which you can reference here .

Based on this we can now write:

interface {
	Read([]byte) (int, error)
	Write([]byte) (int, error)
	Close() error
}

Ah yes, this won’t work, because it’s only part of the syntax, the rule itself does not give enough context for the compiler to work with, we need a type name for other things to assert interface restrictions.

Finally!

SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .

TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
Declaration  = ConstDecl | TypeDecl | VarDecl .

TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
TypeSpec = AliasDecl | TypeDef .

TypeDef = identifier [ TypeParameters ] Type .

Type     = TypeName [ TypeArgs ] | TypeLit | "(" Type ")" .
TypeName = identifier | QualifiedIdent .
TypeArgs = "[" TypeList [ "," ] "]" .
TypeList = Type { "," Type } .
TypeLit  = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
           SliceType | MapType | ChannelType .

As you can see InterfaceType the rule we previously explain is composed within TypeDecl which has the completed syntax we can work with, which the Go compiler gladly take.