REVIEW: Google Go Marries the Benefits of Both Fully Compiled and Modern, Runtime Languages

 
 
By Jeff Cogswell  |  Posted 2010-01-04
 
 
 

REVIEW: Google Go Marries the Benefits of Both Fully Compiled and Modern, Runtime Languages


Google recently made headlines when it announced the creation of a new language. Called Go, the language has already received a good bit of attention. The language is fully compiled in the vein of C++, but includes many types and constructs that make it more similar to something like Python or JavaScript. (Click here to install and learn more about Go.)

I spent some time with Go, and one thing that strikes me is that the compiler is much more intelligent than the older-style, native compilers such as those used for C++. For example, how many times have you wondered: If the C++ compiler can detect that the semicolon is missing, why can't the compiler just recognize the end of the statement and move happily along? Certainly it's possible. And the JavaScript parser, for example, is perfectly fine if you leave off a semicolon. And that's the case with Go. You can leave off semicolons when they aren't necessary.

You can also let the compiler figure out the type of the variable based on the initial assignment--again demonstrating it's an intelligent compiler. (For example, if you assign a string constant to a variable, clearly you're intending that variable to be a string, right? Because if you're trying to stuff a string into a non-string variable, you'll get a compiler error.)

I do, however, see a problem with this kind of declaration. It's too easy to just declare variables haphazardly, on-the-fly, akin to the way people once wrote old BASIC programs. Constructs like this make it easy to write messy code. But I suppose that's going to be the case in any language. (Remember when people would declare arrays of bytes in C and use the individual bytes for all their storage?)

Go is rich in built-in types, such as those found in most languages. Strings are interesting. Unlike the original C language (which didn't technically have strings but rather used pointers to array characters to represent strings), Go strings are immutable, meaning you can't change them. This is actually similar to many modern languages, and is something that bothers some programmers. But it's just a reality. And it's not like you can't change a string variable--you can assign a different string to the variable. You just can't change the individual members of a string.

Also unlike C, Go arrays aren't simply glorified pointers. Rather, arrays are an actual type, as they are in other modern language. And as the Go documentation almost apologizes about, the language does have pointers.

The language also has many newer types, such as maps, as well as a special type of "sub-array" called a slice. (The slice concept is new and foreign to a lot of programmers, but they're pretty flexible and useful. Check out the Go docs to learn more about them.)

Control structures in Go have a rather compact structure to them, and the for statements, for example, include support for iterating through maps. (And there is no while or repeat statement in Go, only a for statement. If that bothers you, I'd say just deal with it.)

When you explore the functions in Go, you really start to see the influence from modern, scripting languages. Functions can return multiple values, just as they can in Python and PHP, for example. In both of those languages, you can return a list, and have the members of the list go right into separate variables in a single line of code. In Go, on the other hand, you can actually specify that a function can return multiple values, like so:

func complex_f1() (re float, im float) {

       return -7.0, -4.0

}

And then you can call the function with multiple values receiving the returned values:

x, y = complex_f1()

Then this is interesting: If you don't want all the values, instead of creating a dummy variable, you can use a "blank identifier" (denoted by a single underscore) to ignore one of the returned values:

x, _ = complex_f1()

The official docs show a rather unique application of this. Check this out:

a, b = b, a

will swap two variables.

Classes (or Not)


 

Classes (or not)

Classes-or what are used for classes-are strange in Go, and it'll be interesting to see how people respond to their unusual nature. To create a class, you first declare a structure type. Structures can only include member variables, no functions. To add member functions to the structure (resulting in a class with methods), you create a function that includes an additional parameter called a receiver. For this receiver, you specify your structure. After that, instances of the structure can call the function as a member, just as in other object-oriented languages.

But this design results in something fascinating: Your receivers (that is, the types you're adding your methods to) don't have to be structures. They can be any type, including an array type or any of the built-in types. The end result is that you can enhance the built-in types, resulting in an extremely object-oriented language akin to something like Smalltalk.

But this isn't really that unique if you've worked in C#, which uses extension methods. Or, if you've worked in JavaScript, this will remind you of how you can use prototypes to add methods to existing object types (such as String). But it is rather unique in a natively compiled language. (And it makes me wonder how some coding purists will feel about it. When C#, for example, added such a feature, some people were upset because it's easy to hack into existing objects and create confusing code.)

Another interesting thing about Go is that it doesn't support inheritance. Why not? Because instead it's interface-based. This might take some getting used to, just as JavaScript's prototype-base takes some getting used to.

Concurrency

If you look through the specification, you'll see a "go" keyword (which is where the language gets its name-plus the fact it's the first two letters of Google). At first I figured this was an old goto statement, and I skipped over it. Wrong.

Go supports what Google has called goroutines. This is basically a coroutine approach, but much more lightweight than what you'll find in some other compiled languages. The whole idea behind goroutines is that data can be shared between the routines, except only one can access it at any given time. Basically that means a form of mutexes is built right into the shared data using what are called channels.

To call a function concurrently, simply use the go keyword, like so:

go list.Sort();

Take a look at the official docs for more information. I think you'll find it pretty cool.

More Features

The language is sprinkled with some nice little features: Declarations can be grouped, which is handy and quick. Break statements aren't necessary inside switch cases. The default is to not fall through. (How many times do you actually use the fall-through feature in C/C++, anyway?) But if you need it to fall through, you simply add the word "fallthrough" at the end of the case. And your code is all package-based, similar to the way Java is.

Further, the language includes a small but rich set of packages for handling things like I/O, regular expressions, and more. Google apologizes that the package list is still small, although growing. Frankly, I think it's already pretty good.

Interestingly, the language also includes no assert. That's fine with me, and I completely agree with Google's rationale that too many C/C++ programmers use assert as a crutch, resulting in bad code. (I, for one, never use assert in my code for just that reason. Well-constructed code should properly handle error condition without covering every other line of code with calls to assert.)

Finally, the language includes garbage collection, even though it's compiled and doesn't make use of an external runtime. The presence of garbage collection is a sticking point for a lot of C++ purists who have grown up with the mantra "for every new, there's a delete." But in today's huge systems, garbage collection is more of a necessity, even though some people might object.

Final Analysis

I like Go. I think we're going to see more of it. But do we need it? I would say yes, and here's why. Let's face it--C++ programming is a pain. Don't get me wrong, I've programmed extensively in C++ since about 1990. I've written several books about it, and have worked with advanced concepts in C++. But that doesn't change my feeling that C++ is a pain in the butt to code compared to modern languages.

With that said, modern, runtime-based languages are not light-weight, and they're not usually as fast as something like C++. Yes, we have just-in-time compilers that can really haul. But they still rarely keep up with a well-written C++ program.

Go seems like the decent replacement for C++. It's truly compiled, yet it has the beauty and simplicity of modern languages. It isn't perfect--for example, I'm not sure I welcome the return of pointers, and I'm a bit suspicious of the interface and receiver approach to classes and objects. That's going to take some relearning, which isn't always easy. But I would say that Google is certainly on to something here.

 

 

 

Rocket Fuel