BT

Google Go: A Primer

Posted by Samuel Tesla on Jan 15, 2010 |

What is Go?

Google recently announced their new programming language, Go. It is designed to bring some of the advances of modern programming languages back down to the systems arena where C still dominates today. However, the language is still experimental and evolving.

The Go authors set out to design a language that would be simple, fast, safe and concurrent. The language is simple enough that it does not even require a symbol table to parse. It compiles very quickly; sub-second compile times for entire projects are normal. It is garbage-collected, so it is safe with regards to memory. It is statically type-checked and does not allow type coercion, so is safe with regards to types. It also offers a powerful mechanism for implementing concurrency that is built right into the language.

Reading Go

Go's syntax continues in the same vein as C's. Programs are organized as functions whose bodies are a sequence of statements. Blocks of code are surrounded by curly-braces. The language has a limited set of reserved keywords. Expressions use the same infix operators. There are very few syntactical surprises.

The Go authors have adhered to a single guiding principle when designing the language: simplicity and clarity above all else. Several of the new syntactical constructs provide concise means to express common idioms that are more verbose in C. Others address language choices that, after several decades of use, have been shown to be unwise.

Variable Declarations

Variables are declared as follows:

var sum int // Just a declaration
var total int = 42 // A declaration with initialization

Most notably, the type in these declarations comes after the variable name. This may seem strange at first, but has some benefits on clarity. For example, take the following snippet of C:

int* a, b;

It is not apparent, but that actually means that a is a pointer and b is not. In order to declare them both pointers, the asterisk must be repeated. However in Go, they can both be declared pointers as follows:

var a, b *int

If a variable is being initialized, the compiler can typically infer its type, so it is not necessary for the programmer to type it out:

var label = "name"

However, at that point, the var keyword is almost superfluous. So, the Go authors introduced a new assignment operator which both declares and initializes a new variable:

name := "Samuel"

Conditionals

Conditionals in Go have the same familiar if-else construction as those in C, but the condition need not be wrapped in parentheses. This creates less visual clutter when reading code.

Parentheses are not the only clutter that have been removed. A simple statement can be included before the condition so that the following code:

result := someFunc();
if result > 0 {
	/* Do something */
} else {
	/* Handle error */
}

Can be reduced to this:

if result := someFunc(); result > 0 { 
	/* Do something */
} else {
	/* Handle error */
}

However, in the latter example, result is only in scope inside the conditional block -- in the former, it is available in the containing scope.

Switches

Switches once again are similar, but improved. Like conditionals, they allow a simple statement to proceed the expression that is being switched upon. However, they deviate even further from their C counterparts.

First, to make switches more concise, two changes were made. Cases can be comma-separated lists of values, and fall-through is no longer the default behavior.

So, the following C code:

int result;
switch (byte) {
 case 'a':
 case 'b':
   {
     result = 1
     break
   }

 default:
   result = 0
}

Becomes this in Go:

var result int
switch byte {
case 'a', 'b':
  result = 1
default:
  result = 0
}

Second, Go switches can match on much more than integers and characters. Any valid expression can be the value of a case statement, so long as it is the same type as the switch expression.

So, the following C code:

int result = calculate();
if (result < 0) {
  /* negative */
} else if (result > 0) {
  /* positive */
} else {
  /* zero */
}

Becomes this in Go:

switch result := calculate(); true {
case result < 0:
  /* negative */
case result > 0:
  /* positive */
default:
  /* zero */
}

That idiom is so common, that if the switch value is omitted, it is assumed to be true. So the above could be rewritten as:

switch result := calculate(); {
case result < 0:
  /* negative */
case result > 0:
  /* positive */
default:
  /* zero */
}

Loops

Go has only one keyword to introduce a loop. However, it offers all of the looping behaviors available in C except the do-while.

Condition

for a > b { /* ... */ }

Initializer, Condition and Step

for i := 0; i < 10; i++ { /* ... */ }

Range

The right-hand expression of a range clause must be an array, slice, string or map, or a pointer to an array; or it may be a channel.

for i := range "hello" { /* ... */ }

Infinite

for { /* ever */ }

Functions

The syntax for declaring functions differs from C. As with variable declarations, types are declared after the terms they describe. So the following function in C:

int add(int a, b) { return a + b }

Becomes this function in Go:

func add(a, b int) int { return a + b }

Multiple Return Values

A common idiom in C is to either reserve a return value to indicate error (e.g. read() returning 0), or to reserve the return value to communicate status and pass in a pointer to a memory location in which to store results. This encourages unsafe programming practices and is not viable in a managed language such as Go.

Recognizing that this problem extends beyond the simple need to communicate both function results and errors, the Go authors built in the capability to return multiple values from a function.

As an example, this is a function to return both parts of an integer division:

func divide(a, b int) (int, int) {
  quotient := a / b
  remainder := a % b
  return quotient, remainder
}

With multiple return values, it is good to have the code document which is which - Go allows you to give the return values names, just like parameters. You can then assign values to those return variables just like any other. So we could rewrite divide like this:

func divide(a, b int) (quotient, remainder int) {
  quotient = a / b
  remainder = a % b
  return
}

The presence of multiple-return values has given rise to the "comma-ok" pattern. Functions which can fail can return a second, boolean, result to indicate success. Alternatively, they can return an error object. So it's not uncommon to see code like this:

if result, ok := moreMagic(); ok {
  /* Do something with result */
}

Anonymous Functions

Having a garbage collector opens the door for a wide variety of features - among those are anonymous functions. Go provides a simple syntax for declaring anonymous functions. These functions create a lexical closure on the scope in which they were defined like blocks in many dynamic languages.

Consider the following program:

func makeAdder(x int) (func(int) int) {
  return func(y int) int { return x + y }
}

func main() {
  add5 := makeAdder(5)
  add36 := makeAdder(36)
  fmt.Println("The answer:", add5(add36(1))) //=> The answer: 42
}

Primitive Types

Like C, Go offers a handful of primitive types. The usual boolean, integer and floating-point types are available. It has a Unicode string type and an array type. The language also introduces two new types: slice and map.

Arrays & Slices

Arrays in Go are not dynamic like they are in C. Their size is part of their type, and is determined at compile time. To index into an array the familiar C syntax is used (e.g. a[i]), and as with C an array index is 0-based. The compiler provides a built-in function, which is evaluated at compile time, to determine the length of an array (e.g. len(a)). If a write to an index beyond the bounds of an array is attempted, a run-time error will be generated.

Go also offers slices, which put a new twist on arrays. A slice represents a contiguous segment of an array, allowing a programmer to refer to specific sections of the underlying storage. The syntax for constructing a slice is similar to the syntax for accessing an array element:

/* Construct a slice on ary that starts at s and is len elements long */
s1 := ary[s:len]

/* Omit the length to create a slice to the end of ary */
s2 := ary[s:]

/* Slices behave just like arrays */
s[0] == ary[s] //=> true

// Changing the value in a slice changes it in the array
ary[s] = 1
s[0] = 42
ary[s] == 42 //=> true

The segment of the array that the slice references can be changed by assigning a new slice to the same variable:

/* Move the start of the slice forward by one, but do not move the end */
s2 = s2[1:]

/* Slices can only move forward */
s2 = s2[-1:] // this is a compile error

The length of a slice can be changed so long as it does not exceed the slice's capacity. The capacity of a slice s is the size of the array from s[0] to the end of the array, and is returned by the cap() built-in function. A slice's length can never exceed its capacity.

Here is an example that shows how length and capacity interact:

a := [...]int{1,2,3,4,5} // The ... means "whatever length the initializer has"
len(a) //=> 5

/* Slice from the middle */
s := a[2:4] //=> [3 4]
len(s), cap(s) //=> 2, 3

/* Grow the slice */
s = s[0:3] //=> [3 4 5]
len(s), cap(s) //=> 3, 3

/* Cannot grow it past its capacity */
s = s[0:4] // this is a compile error

Often, a slice is all that is needed for a program. In that case, a programmer need not have an array at all. Go offers two ways to make slices directly without ever referencing the underlying storage:

/* literal */
s1 := []int{1,2,3,4,5}

/* empty (all zero values) */
s2 := make([]int, 10) // cap(s2) == len(s2) == 10

Maps

One data type that is present in almost every dynamic language that is popular today, but that is missing from C, is a dictionary. Go offers a primitive dictionary type called a map. The following example shows how to make and use a Go map:

m := make(map[string] int) // A mapping of strings to ints

/* Store some values */
m["foo"] = 42
m["bar"] = 30

/* Read, and exit program with a runtime error if key is not present. */
x := m["foo"]

/* Read, with comma-ok check; ok will be false if key was not present. */
x, ok := m["bar"]

/* Check for presence of key, _ means "I don't care about this value." */
_, ok := m["baz"] // ok == false

/* Assign zero as a valid value */
m["foo"] = 0;
_, ok := m["foo"] // ok == true

/* Delete a key */
m["bar"] = 0, false
_, ok := m["bar"] // ok == false

Object Orientation

The Go language supports a style of object-oriented programming similar to that used in C. Data is grouped together into structs, and then functions are defined which operate on those structs. Similar to Python, the language offers a way to define the functions and then call them so that the syntax is not cumbersome.

Structs

Declaring a new struct type is simple:

type Point struct {
  x, y float64
}

Values of this type can now be allocated using the built-in function new, which returns a pointer to the value in memory with all slots initialized to the zero value.

var p *Point = new(Point)
p.x = 3
p.y = 4

That can get verbose, and one of the goals of the Go language is to be concise whenever possible. So a syntax is provided that both allocates and initializes the struct at the same time:

var p1 Point = Point{3,4}  // Value
var p2 *Point = &Point{3,4} // Pointer

Methods

Once a type has been declared, functions can be declared which take that type as an implicit first parameter:

func (self Point) Length() float {
  return math.Sqrt(self.x*self.x + self.y*self.y);
}

Those functions can then be called as methods on the struct:

p := Point{3,4}
d := p.Length() //=> 5

Methods can actually be declared on both value and pointer types. Go will handle referencing or dereferencing objects as appropriate, so it is possible to declare methods on both type T and type *T and have them be used as appropriate.

Let us extend our Point class with a mutator:

/* Note the receiver is *Point */
func (self *Point) Scale(factor float64) {
  self.x = self.x * factor
  self.y = self.y * factor
}

Then we can call it like this:

p.Scale(2);
d = p.Length() //=> 10

It is important to understand that the self that is passed in to MoveToXY is a parameter like any other, and parameters are passed by value, not by reference. That is why it must be declared as a pointer type in order to actually change the value. If it were declared as just Point, then the struct that was modified inside the method would not be the same one at the call site - values are copied when they are passed to a function, they are also discarded at the end of it.

Interfaces

Dynamic languages such as Ruby emphasize a style of object-oriented programming that places more importance on what behavior an object has rather than what type that object is (duck typing). One of the most powerful features that Go brings with it is the ability to program with that duck-typed mentality, and check for adherence to those defined behaviors at compile time. The name given to the behaviors is interfaces.

Defining an interface is simple:

type Writer interface {
  Write(p []byte) (n int, err os.Error)
}

That defines an interface with a method for writing a buffer of bytes. Any object which implements that method also implements the interface. No declarations are required as in Java, the compiler just figures it out. This gives the expressiveness of duck-typing with the safety of static type-checking.

The way interfaces behave in Go allows developers to discover their programs' types as they write them. If there are several objects that all have the behavior, and a developer wishes to abstract on that behavior, they can create an interface and then use that.

Consider the following code:

// Somewhere in some code:
type Widget struct {}
func (Widget) Frob() { /* do something */ }

// Somewhere else in the code:
type Sprocket struct {}
func (Sprocket) Frob() { /* do something else */ }

/* New code, and we want to take both Widgets and Sprockets and Frob them */
type Frobber interface {
  Frob()
}

func frobtastic(f Frobber) { f.Frob() }

It is important to note that every object implements the empty interface:

interface {}

Inheritance

The Go language does not have inheritance, at least not the way most languages do. There is no hierarchy of types. Go encourages the use of composition and delegation over inheritance, and offers some syntactic sugar to make it more bearable.

Given these definitions:

type Engine interface {
  Start()
  Stop()
}

type Car struct {
  Engine
}

I can then write the following:

func GoToWorkIn(c Car) {
  /* get in car */

  c.Start();

  /* drive to work */

  c.Stop();

  /* get out of car */
}

When I declared the Car struct, I gave it what is called an anonymous member. That is a member which is identified only by its type. The anonymous member is a member like any other, with a name the same as the type. So I could have also written c.Engine.Start(). The compiler automatically delegates calls made on Car to methods on its Engine if the Car does not have methods of its own to satisfy them.

The rules for resolving methods provided by anonymous members are conservative. If a method is defined for a type, it is used. If not, and a method is defined for an anonymous member that is used. If there are two anonymous members that both provide a method, the compiler will produce an error, but only if that method is called.

This composition is achieved via delegation, not inheritance. Once the anonymous member's method has been called, flow has been delegated to that method entirely. So you cannot simulate type hierarchy like this:

type Base struct {}
func (Base) Magic() { fmt.Print("base magic") }
func (self Base) MoreMagic() { 
  self.Magic()
  self.Magic()
}

type Foo struct {
  Base
}
func (Foo) Magic() { fmt.Print("foo magic") }

When you create a Foo object, it will respond to both methods that Base does. However, when you call MoreMagic you will not get the results you expect:

f := new(Foo)
f.Magic() //=> foo magic
f.MoreMagic() //=> base magic base magic

Concurrency

The Go authors chose a message-passing model as their recommended method for concurrent programming. The language does still support shared memory, however the authors have the following philosophy:

Do not communicate by sharing memory; instead, share memory by communicating.

The language offers two basic constructs to achieve this paradigm: goroutines and channels.

Goroutines

Goroutines are lightweight parallel paths of program execution similar to threads, coroutines, or processes. However, they are sufficiently different from each that the Go authors elected to give them a new name and discard any connotative baggage that the other terms might have.

Spawning a goroutine to run a function named DoThis is as simple as this:

go DoThis() // but do not wait for it to complete

Anonymous functions can also be used:

go func() {
  for { /* do something forever */ }
}() // Note that the function must be invoked

These goroutines are mapped to the appropriate operating-system concurrency primitives (e.g. POSIX threads) by the Go runtime.

Channels

With goroutines, parallel execution of code is easy. However, a mechanism for communicating between them is still needed. Channels provide a FIFO communication queue that can be used for just this purpose.

Here is the syntax for working with channels:

/* Creating a channel uses make(), not new - it was also used for map creation */
ch := make(chan int)

/* Sending a value blocks until the value is read */
ch <- 4

/* Reading a value blocks until a value is available */
i := <-ch

For example, if we wanted to do some long-running numerical computation we could do this:

ch := make(chan int)

go func() {
  result := 0
  for i := 0; i < 100000000; i++ {
    result = result + i
  }
  ch <- result
}()

/* Do something for a while */

sum := <-ch // This will block if the calculation is not done yet
fmt.Println("The sum is:", sum)

The blocking behavior of channels is not always the best. The language offers two ways to customize this:

  1. A programmer can specify a buffer size - sending to a buffered channel will not block unless the buffer is full, and reading from a buffered channel will not block unless the buffer is empty
  2. The language also offers the ability to send and receive without ever blocking, while still reporting if the operation succeeded
/* Create a channel with buffer size 5 */
ch := make(chan int, 5)

/* Send without blocking, ok will be true if value was buffered */
ok := ch <- 42

/* Read without blocking, ok will be true if a value was read */
val, ok := <-ch

Packages

Go offers a simple mechanism for organizing code: packages. Each file begins with a simple declaration of what package it belongs to, and each file can import the packages it uses. Any names which begin with a capital letter are exported from a package, and are available to be used by other packages.

Here is a complete source file:

package geometry

import "math"

/* Point is capitalized, so it is visible outside the package. */

type Point struct {

  /* the fields are not capitalized, so they are not visible
     outside of the package */

  x, y float64 
}

/* These functions are visible outside of the package */

func (self Point) Length() float64 {
  /* This uses a function in the math package */
  return math.Sqrt(self.x*self.x + self.y*self.y)
}

func (self *Point) Scale(factor float64) {
  self.setX(self.x * factor)
  self.setY(self.y * factor)
}

/* These functions are not visible outside of the package, but can be
   used inside the package */

func (self *Point) setX(x float64) { self.x = x }
func (self *Point) setY(y float64) { self.y = y }

What's Missing

The Go authors have tried to let clarity of code guide all of their decisions regarding the design of the language. A secondary mission has been to produce a language which compiles quickly. With these two criteria to steer them, many features from other languages have not made it in. Many programmers will find that their favorite language feature is not present and indeed some may feel that the language is not yet usable for lack of certain features common in other languages.

Two such missing features are exceptions and generics, both very helpful in other languages. Neither feature is currently part of Go. But since the language is still experimental, these may make it in there eventually. However, when comparing Go to other languages, we should remember that Go is intended to be a replacement for C in systems programming. And in this light, the various missing features don't look like such a drawback.

Finally, since the language has just been released, it does not have much in the way of libraries or tools: there are no IDEs for Go. The standard library has useful code, but it is small compared to what is available in more established languages.

Rate this Article

Relevance
Style

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

ugly by Duraid Duraid

looks like a very ugly language

Re: ugly by Sal Fuentes

I disagree. I think it has a good design, and the fact that it has a C family syntax should make it easier for most developers to learn. I think many people forget that Go is specifically targeting the systems programming space.

Re: ugly by withyou gakaki

ugly python javascript and scala minx with one
ugly than objective c
c is ugly too for the pointer

Re: ugly by Maxim Zaks

+1

Google Go by Musthafa CK

exactly after 15 years of C++ java introduced. the same has happened in the case of Go too so we can expect gradual growth that has happened in java case. any way touch of C and javaFx is very visible bcz Joshua Bloche may be behind.

Re: Google Go by Christos Papalekas

I think the clear quiding principle of composition instead of inheritance is more telling of Josshua's hand in GO...

intersting by Christos Papalekas

Nice Article.
Interesting mixin having in mind the target domain (systems).
I liked the conditionals,loops and switches approach.
Evemore so, the comma-ok idiom in terms of simplicity and readability of code. There is still a risk for readability though, if programmers won't explicitly document the return values by name. Not a huge fun of duck-typing. Capitalization replacing access modifiers seems little weak.It would be nice if the Concurrency section was desribed in more detail as it seems on of the main reason for the existence of GO. For example, what is the exact shared memory model and how chanels are mapped to the underlying OS. How the concurrency support copes with goroutines running on different physical machines e.t.c

PS: reference to MoveToXY seems to be a typo. I guess Scale should be referenced from the text instead.

Re: ugly by roberto parra

that programmers who says Python is Ugly must be a HTML programmers, I wrote code in both, Java and Python and i think Python is more ellegant and compact, while java is too verbose

terrible language by Knox Liam

I really dont understand why this is getting any airing. After coming so far from the boiler plate with Java and further still with Scala why would you sacrafice very readable and maintainable code for this junk?

I dont really know what Google are doing but I guess you let many developers chuck crap at the wall some good things will stick. This is definitely not one of them

Something's strange by Florent Blondeau

Hi,

When you say

/* Construct a slice on ary that starts at s and is len elements long */
s1 := ary[s:len]

wouldn't it be "is len-s element long" ?

see golang.org/doc/go_spec.html#Slices :

For a string, array, or slice a, the primary expression
a[lo : hi]
constructs a substring or slice. The index expressions lo and hi select which elements appear in the result. The result has indexes starting at 0 and length equal to hi - lo


Right, that's just a primer, not specs....

Interesting presentation Article... You should do the same for the ANI language (code.google.com/p/ani) which is interesting, but not from Google

Cheers

Dazz

Re: Google Go by AlSayed Othman

Yeah, and Also Python .. abut I don't know who is behind that :)

Very nice tutorial and can't understand what's ugly about that ?!

Re: Something's strange by Steve Graegert

That's code.google.com/p/anic actually.

Re: Google Go by Musthafa CK

whoever behind Go that doe'nt matter. Let it mature so that we can enjoy different thinking in system programming.

Re: terrible language by Michael Swierczek

I usually associate the term 'Systems Programming Language' with high performance. There are two compilers for Go at current, one (called 6g and 8g depending upon your architecture) that sacrifices code efficiency for speed of compilation and one built on top of the GCC compiler that focuses on code efficiency. From the introductory Google presentation on the language by Rob Pike, the GCC version produces code about 20% slower than C++.

20% slower than C++ puts Go programs at conservatively twice as fast and requiring 70% less memory when compared to an equivalent Java or Scala application. In many cases that difference is irrelevant, but for a company like Google with thousands of servers the potential efficiency improvements are worth the investment.

Is it Ugly ? No ! It is HORRIBLE ! by alessandro borges

Sorry guys, but it is a bad language.

Why := as assignment ?? It is from stone age Pascal !
No commas at end of statements ? Like crappy VB ???
Why this horror to () in for, while, switch and other classic statements ? Why ?
Dynamic typing ? No types ? We know it requires extra programing in background, as well more space requirements to deal with different data types as strings, int, floats, arrays etc.
Easy learning ? Are you going to teach this to young people, just to teach all over again with first class programming languages ?

Seems is it was designed by very, very, lazy JavaScript programmer.

We need clear code, not typing laziness.
And all modern IDE has auto-complete, code snippet today. (Btw, Eclipse is light years ahead of MS-Visual Studio)

Imagine debugging or support tons of codes like this, codes made by an obscure mind with a messy language.Or vice-versa. Not sure which scene is worst, anyway...

Imagine what kind of programmer will use it for living. The good ones will stick with C,C++,Java and C#.

We all know that is the *COMPILER* who does the performance thing, no matter the language you use.
I guess they build a good compiler, CONGRATULATIONS!
Change the parser for a C/Java/C# dialect and it will be a HUGE sucess.Because programmers will use and *love* it.
Continue with this childish, weird language and seen what will happens...

Sorry if it sounds bitter, but something is wrong with this. Someone must say it is bad before it goes so far and make a lot of people loose their time and money, just because it is "as 'fast' as 70% of C". Dah !!!
Common, guys !
Hardware improve over time (Moore's Law), but GOOD CODE is forever !
Good code is made with clear, objective, good pattern and straight forward programming.

Strange Language by Song Colin

A strange language...
It will become popular bcz it made by Google?

Re: Is it Ugly ? No ! It is HORRIBLE ! by Michael Swierczek

alessandro,

Go does NOT have dynamic typing. It has TYPE INFERENCE, which is used in Haskell, Scala, and a number of other languages. If you write in Go, abc := "hello", the compiler figures out that abc is a String variable without having to type it. You cannot do abc = 3 later in the same variable scope, the code won't compile.

In Go, any class that implements all of the functions of an interface is automatically considered an instance of that interface. But it's still static, not dynamic, typing - the author just does not need to explicitly list all of the interfaces a Go class implements.

:= in Go both declares and sets a variable. In Pascal := only sets a variable. abc := "hello"; abc := "goodbye" might be valid Pascal, but it is not valid Go. It's like doing char *p = "hello"; char *p = "goodbye"; in C++ (that may be bad C++, I haven't used the language in five years).

And while the *COMPILER* does performance, even with the massive improvements in virtual machines (JVM for Java and Scala, .NET VM for C#, etc..) and scripting language interpreters (Ruby, Python, Perl, Javascript) none can come close to C and C++ for performance. If Go is 20% slower than C++, that's still two to ten times faster than any language that's not statically typed and compiled and far more memory efficient.

C++ is an outstanding language, but between the lack of automatic garbage collection, the preprocessor - which has syntax totally different from the rest of the language, and the different meanings of the keyword 'static' depending upon where it is used, it is awkward. There's a reason thousands of companies and developers have been willing to forego C++ blazing speed for Java and C# cleaner syntax, lack of a preprocessor, and automatic garbage collection.

Re: Is it Ugly ? No ! It is HORRIBLE ! by William Smith

Seems is it was designed by very, very, lazy JavaScript programmer.

Is this for real?
I mean not that it matters that much but the designers on the project include Robert Griesemer, Rob Pike, Ken Thompson and Russ Cox.

A replacement for C++ is an admirable goal and something that the world of computing desperately needs if we're ever going to have an OS that is fit for the 21st century. Is this it? Hard to tell so far - the lack of exceptions (and please make them checked) seems like a bad decision but I like the overall philosophy of the language deign. It will be interesting to see how it evolves over the next 2-3 years.

Strange due to familiarities by Rhys Parsons

I think people are finding some of the syntax strange because it's both familiar and different.

Much of what seems immediately weird (e.g. :=) is just syntactic sugar.

What really matters is whether the code is more readable, so which is more obvious:

Java: int x = 0;
Scala: var x: Int = 0
Scala: var x = 0 // type inferred
Go: var x int = 0
Go: x := 0 // type inferred

My immediate response is that, when you're used to seeing 'var' as an indicator of a definition, when it's not there, you miss it. However, I guess that when you get familiar with the language, you probably wouldn't. Having the type follow the variable name without a colon in-between could also take a bit of getting used to.

The := syntax obviously comes into its own when using it within the for-loop constructions.

The BIG thing I don't understand is why they've deliberately avoided using OO constructs, but have fitted OO-like constructs in an unintuitive way. So, there's no inheritance, but you can make something appear to be inherited; polymorphism is through duck-typing rather than explicit type declaration. Doesn't this just mean that OO is implemented in an non-explicit, non-intuitive way? I can see that this is sometimes useful; but it could also lead to some really horrible code!

I expect I'm missing something.

Looks nasty by Tracy Nelson

I dunno, looks pretty nasty to me. What's the point of this whole "comma-ok" thing? Why not just have a meta-variable (a la Perl's "$_") that indicates success? Then you can just do
if foo := bar(0); $ok { ... }

Or, hell, if this compiler's supposed to be so smart, why can't it recognize an assignment from a function call and just allow you to
if(foo := bar(0)) {...}

And if the answer to that is "because then it would evaluate the return value of bar(0)" then what happens if I do
if(v <- ch)
Does that evaluate the value I get from reading the channel, or does it do a non-blocking read and branch on whether I got a value or not?

And I think the whole concept of ignoring return values is a design smell. If I couldn't use C I'd rather go back to PL/M than soil my hands with this glop. I'm quite honestly shocked to see Rob Pike and Ken Thompson's names associated with this.<//pre>

Re: Is it Ugly ? No ! It is HORRIBLE ! by alessandro borges

Thanks for the explanation about := and type inference.

Re: Is it Ugly ? No ! It is HORRIBLE ! by alessandro borges

Seems is it was designed by very, very, lazy JavaScript programmer.

Is this for real?
I mean not that it matters that much but the designers on the project include Robert Griesemer, Rob Pike, Ken Thompson and Russ Cox.


I see it this way :

As JavaScript :

var i=0;
for (i=0;i<=5;i++)
{
write("The number is " + i);
}

As Go ( as far as I understand it):

var i:=0
for i=0; i<=5; i++
{
write("The number is ", i)
}

In my limited view, Go just removed some ; and (). But it didn't increased readability, did it ?


Anyway, I agree with Rhys Parsons about the
"Strange due to familiarities" :

I think people are finding some of the syntax strange because it's both familiar and different.
<//pre><//pre>

As a Java programmer, I ... by Leandro Coutinho

As a Java programmer, I would like Java to have like Go has:

The switch statement;
To return a function;
I liked a lot goroutines and channels!!!;

Some nonsense things:
- syntax argh. why change the order? I don't agree with the justification. Do they want that folks that program in C for years to change the way their brains work. crazy
- capitalization stuff

Variable declarations can still be misleading in Go by Richard Fearn

The article says:

...the type in these declarations comes after the variable name. This may seem strange at first, but has some benefits on clarity.


The confusion with the C code

int* a, b;


arises because the * declarator is attached to the variable name (a), not the type (int), but C's syntax allows you to write the declaration in a way that would make you think otherwise. However even Go lets you write declarations in potentially misleading ways. For example:

var a, b *int


could instead be written

var a, b* int


and reading this you might expect a to be an int, and only b to be a pointer.

So even with Go, you still need to understand that the * declarator is attached to the type, not the variable name. In this respect, Go's syntax doesn't really give it any advantage over the syntax of C. You can still write misleading declarations in both languages.

Thank you by Satya P

It's a wonderful article with easy examples and clear definitions. Thank you!

It's sad that some clueless people are mindlessly bashing the Go language here!
Look at the guy who calls the := as a stone age pascal assignment! He has no clue that Go is declaring the variable & assigning the value while the good old pascal only used it for assigning.

Besides this is an extra / optional feature! You can still declare a variable with a var and assign a value with just the = and without using the : in front of it.

For me, it looks beautiful and sounds logical!

Go language by jan verhoeven

Looks like they used the structure of Modula-2 and Oberon but the keywords of C. And even some aspects of my toy language Plov fruttenboel.verhoeven272.nl/m4m/Plov22.html in that the semicolon is replaced by the linefeed.

All in all: it looks promising!

Re: Go language by Oliver Plow

Looks like they used the structure of Modula-2 and Oberon but the keywords of C.

Yes, that was also my first thought that it looks much like Oberon when seeing how structs also serve as classes. Some late kudos to Niklaus Wirth as Oberon back then did not catch much on...

There is no inheritance, no multiple inheritance, no traits and nothing. It is all solved through delegation. To me this is an excellent and superb approach! (And this is not taken from Oberon). To me this is the beginning of the end of inheritance. *no kidding*

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

27 Discuss
General Feedback
Bugs
Advertising
Editorial
Marketing
InfoQ.com and all content copyright © 2006-2016 C4Media Inc. InfoQ.com hosted at Contegix, the best ISP we've ever worked with.
Privacy policy
BT

We notice you’re using an ad blocker

We understand why you use ad blockers. However to keep InfoQ free we need your support. InfoQ will not provide your data to third parties without individual opt-in consent. We only work with advertisers relevant to our readers. Please consider whitelisting us.