Go 1.1 RC1 is out
groups.google.com
groups.google.com
But I'm still unhappy that using named return values still requires you to put a superfluous "return;" at the end of such a function.
The whole reason I use named return values is to cut down on the boilerplate code that carries the return value around -- so why not cut out the final boilerplate 'return'? It doesn't solve any problem or add any information!
Otherwise, there are some nice improvements here. Other than the things mentioned so far, I'm glad to see reflection filling out -- the day a Go REPL will be possible is approaching.
// Match checks whether a textual regular expression
// matches a byte slice. More complicated queries need
// to use Compile and the full Regexp interface.
func Match(pattern string, b []byte) (matched bool, error error) {
re, err := Compile(pattern)
if err != nil {
return false, err
}
return re.Match(b), nil
}
If the final line is missing, the compiler rejects the function. You might well have meant 'return', which could be inserted implicitly, but you might also have been interrupted while writing the function and meant to write a 'return something'. The compiler (really the language) requires you to be clear to avoid inferring an incorrect completion.One nit: the return rules are separate from escape analysis, which is about keeping things on the stack instead of allocating them on the heap.
This one weird simple trick could work (and give you white teeth): implicit returns only get inserted if all the named return variables are assigned-to at least once in the body of the function. Perhaps that breaks your pure syntactic rule, though.
2. Yup, wrong term.
Very close indeed! Struct, array and function types still can't be constructed at run time, but as of Go 1.1, function values can be as well as slice, map and channel types. I exploit some of this in my `ty` package. [1,2]
[1] - http://godoc.org/github.com/BurntSushi/ty
[2] - http://blog.burntsushi.net/type-parametric-functions-golang
I tried to convince rsc at some point about the enormous value of REPLs for rapid development.. imagine connecting to an embedded REPL on a server to do live debugging. I don't think I quite convinced him to drop everything and do it himself, though.
Do you have plans to experiment with a transpiler to smooth away all the remaining type noise?
Maybe a first step would be to explore how one could add pluggable 'dialect translators' to the go tool so that anyone could write simple extensions for the language while preserving the existing toolchain.
I don't have any particular plans; the `ty` package was a night of hacking plus several days of polishing/writing. :-)
One of the major bummers about moving into the reflection world is performance. My blog article talks about it a little bit, but it's also worth looking more closely at the things I didn't talk about in the benchmarks. (For instance, it seems that function calls in the reflection world pay a very steep price.)
Re transpiler: do you mean a {Language}-to-Go source translation? If so, it seems like you'd want to avoid `reflect` completely in that case. But maybe I am misunderstanding.
> I tried to convince rsc at some point about the enormous value of REPLs for rapid development ... I don't think I quite convinced him to drop everything and do it himself, though.
A REPL would be very nice, but a REPL using `reflect` would definitely be a lot of work. You'd need to make extensive use of the sub-packages in `go` to convert the `Read` portion of the `REPL` into appropriate reflection types. You could do it now, but you wouldn't be able to define new functions, structs or interfaces. And `reflect` cannot spawn goroutines either, which is a bummer.
A REPL is possible even today.
All is needed is an interpreter for the language and there are a few already available.
Nothing new, this is the same approach taken by many languages, provide an interactive environment for the REPL and a compiler for distribution.
Being done since the early days of computing.
When I work with ML or Lisp based languages, I am always copied code snippets, which might land in separate modules afterwards.
Unless you mean a JIT at the REPL environment.
Also I slightly disagree with you that named return values are for short code. This may be true in functions that return at many points. For other functions it may need some otherwisely added boilerplate. If you write inside an if-block f, err := os.Open(...) that err is a different one than your return value err. So you would need to add var f *os.Open above the if to write f, err = os.Open(...).
Having that said, IMHO the greatest pro of named return values is well understandable code, in particular for libraries.
2. You're right, they're not only for short code. That however is where the forced "return" is most glaring.
In Python, if you don't say `return` the function returns `None`.
From a personal perspective, I find having to include "return" a pain as there's times when it's completely unnecessary. eg in switch statements or if else where each condition has it's own return. While it's an easy fix for if else (just drop the else / default case), it makes the code look a little less pretty in my opinion.
Because race conditions are so hard to detect, the race detector is obviously prone to false negatives. Just because the tester doesn't find any race conditions doesn't necessarily mean that there aren't any. But the race detector never finds false positives. If it finds a race condition, that condition is very real.
You could just run your app with the race detector on all the time, but there is a performance cost to using the race detector.
One way to get around this in cloud/clustered environments is to deploy your app on a few machines with the race detector on and the rest with the race detector off. That way you're running your app with a production load and you're more likely to find race conditions, but you'll mitigate the performance costs associated with the race detector.
Running the detector on just a few nodes sounds like a great way to offset the performance penalty a bit. The docs on the race detector say that "memory usage may increase by 5-10x and execution time by 2-20x" which could be quite significant.
I also wonder about the effectiveness of randomly fuzzing your app with the race detector on as a form of testing.
Certainly for an entire program it is... not sure if you limit it to the just the code paths executed.
If you want a more guaranteed form of race freedom, you need to constrain what programs can do, either with dynamic restrictions on mutable state sharing (like Erlang or the parallel extensions to JavaScript do) or with a type system strong enough to reason about sharing of data (like Haskell or Rust).
https://code.google.com/p/data-race-test/wiki/ThreadSanitize...
Intended, yes. But that doesn't mean we also develop "cleanly&properly" at all times, in the real world. It's a great "backup" for when formerly-prototyping-now-production code is getting slightly out of hand over time.
The Go-documentation has a couple of great examples [1] that could easily happen in the real world (before the first coffee).
If you are worried about leaking goroutines,
import _ "net/http/pprof"
in your web server and then visit /debug/pprof/goroutine (or even just /debug/pprof). That listing shows all the active goroutine stacks, but it groups bunches with the same stack into a single entry with a count. Scanning the list it is usually easy to see leaks (hey, why do I have 5000 goroutines with that stack) and also why they are stuck (because you have the whole stack).Outside of the "dangling reference" issue above "leaking" in a GCd language is non-trivial. Here is a related Java discussion: http://stackoverflow.com/questions/6470651/creating-a-memory... . Also note Go doesn't have ClassLoader or class static fields.
So, you can pretty easily leak memory without messing with unsafe things.
It is also pretty easy to detect by this (or something better), which might be handy in a big program: http://play.golang.org/p/XmKfgQ4TmS
Sure it is, if you are leaking goroutines you will see an every increasing count, even when your app is idle if the count doesn't return to the proper baseline then you know you have a problem.
If you start a goroutine should should have a plan for terminating it. If you don't have a natural way like the life cycle of handling a request then you need to use channels (defer/close are your friends), waitgroups, condition vars etc. I work on some fairly large Go applications and this hasn't been a pain point.
func hello() int {
if true {
return 0
} else {
return 1
}
}
>go run func.go
./func.go:3: function ends without a return statement func hello() int {
if cond {
return 0
}
return 1
}
anyway. func hello() int {
var result int
if cond {
result = 0
}
result = 1
// New code with result
return result
}
Now, in this case, you don't want result to be 1 if cond, so you have to add the else condition. If you start with if-else, this is less likely to bit you in the future.This particular bug just bit me in a bad way in production because I had what you have and and to make an quick production fix and did a refactor just like this and missed adding the else.
int hello() {
return cond ? 0 : 1
}
In Go, I'd do this, but then I seem to like named return values more than most Go programmers... func hello() (res int) {
if !cond {
res = 1
}
return
}
Of course, coming from C/C++, it would have to be an extremely special case for me to have logic where "true" mapped to 0 and "false" mapped to 1, because that just seems wacky.https://plus.google.com/106356964679457436995/posts/LmnDfgeh...
EDIT: Sorry, let me explain (I'm not an asshole, really!). I disagree with using named returned for things outside of signaling error/ok states (as explained by Andrew). I feel that our signatures should be written concisely for users of our API, not for our convenience.
I respect Andrew Gerrand and Brad Fitzpatrick quite a lot but I still often use named returns on even small functions. I find doing so usually makes the actual function code more concise and easily readable for me and I don't think the negative impact on the docs is significant. IMO auto-generated go-docs have far worse problems than the 'noise' from named returns, I think they suffer a lot more from core language decisions like the flexible interface system. And to be clear, I think the interface system in Go is brilliant and I love using it, but I also think it makes auto-generated go-docs hard to digest (and use as quick references) in a way that auto-generated OOP language docs (javadoc, doxygen from C++, etc) aren't.
They were wrong and probably not as experienced as they/you thought. Guard clauses make code simpler and more understandable.
http://martinfowler.com/refactoring/catalog/replaceNestedCon...
I think a blanket ban on multiple return locations is silly, as they can often be used to simplify code. There may be times when setting a return value is preferable, and I think you should use your judgement there.
http://stackoverflow.com/questions/36707/should-a-function-h...
if x
return a
return b
if x
return a
else
return b
if x
r = a
else
r = b
return r
Out of these I find the first is the most prone to maintenance errors. It's easy at a glance to see the final return, insert something in front of it, and miss that it needs to happen on another path. At least in the other two cases the indentation makes it clear that it's a conditional return path and you look for others.I don't have a problem with a "throw" instead of "return a" in any of the forms because that's expected to be an aborted path anyway. In the case of two returns, maybe it is, maybe it isn't.
It's a small thing but when you read hundreds of thousands of lines of code, every little thing that makes it easier is worthwhile.
[1] http://martinfowler.com/refactoring/catalog/replaceNestedCon...
However, I happily make exceptions for:
a) Simple shortcut checks at the top of the function. These tend not to increase the complexity of the control flow and can really simplify it.
void free(void * p)
{
if (!p) return;
... rest of function
}
b) Cases where it's just plain unnatural to do it any other way. This can occur with state machines and complex loops.
When I do this, I make sure to put a comment way out on the right. void process_bytes(unsigned char * p)
{
...
for (;;)
{
...
switch (loop_state)
{
...
case specific_case:
switch (input_symbol)
{
...
case end_symbol:
return; //----- note inner return
...
}
break;
...
}
}
}
Before folks jump on me for having nested switch statements or "complex loops" in the first place, let me point out that when I write this type of code it's usually because I'm processing a data format defined by somebody else.On a separate note, my take is that multiple returns are necessary to write readable understandable code quite often. Guard statements (either handling normal simple boundary cases, or throwing exceptions) at the beginning simplify logic and gives a clean reading of the code.
I find that multiple return statements in a function are more often a symptom of ugly code instead of the reason.
if (x): do(thing1) y := do(thing2) if (y): do(thing3) return 0 else: return -1 else: do(thing4) return 0
___
As you can see, such logic could quickly become hard to test and reason about. Does a single return help all that much? Not in and of itself, but it does tend to make writing such code a bit more painful, leading to better designs. However, guard clauses are a superior design in general.
I still avoid multiple returns in my main logic when side effects are involved, at least when I can.
And if the function is not small?
There are times when this transformation yields simpler code, there are times when it makes things more complex, and there are a lot of cases in between where it's a judgment call.
No, gccgo has been developed as a first-class compiler; the intent has always been to separate Go-the-language from Go-the-implementation, to prevent a single implementation from becoming the de facto standard over the language specification - a problem which we've seen happen in many other languages.
You can essentially use gccgo as a drop-in replacement for gc; it's only an extra command-line flag you add to the compilation to specify the compiler.
gccgo is actually likelier to be faster than gc for most computationally bound code, since it piggybacks off of the optimizations that gcc has incorporated over the last couple of decades. However, gc may be preferred if you're relying heavily on goroutines (ie, in the hundreds/thousands), since gc is better optimized for that.
"It's worth mentioning the function representation change, since it means closures no longer require runtime code generation (which among other things allows the heap to be marked non-executable on supported systems)."
Anyone know what that means?
Edit: dylanvee was faster, the NX-bit is the underlying hardware feature
TL;DR: functions are now represented as (function pointer, pointer to a context structure), whereas before they were represented as a single function pointer.
It would also be nice to have a first-class array object - from what I understand, current support for multidimensional arrays is very C-like in that you're really dealing with pointer arrays.
I agree about the numerics. I'm tempted to write an very bare-bones implementation of Mathematica's kernel in Go, but I'll probably wait until people have done more numerics work in Go.
And I'm glad that they're bumping up the heap size to system-dependent values on 64bit systems. The fixed heap size of 16 GB was a really unfortunate constraint (even if it could be changed with a little hacking around).
Can actual products (Web apps in my case) be built with Go?
> "Not only is creating an App Engine application easy, it's free! You can create an account and publish an application that people can use right away at no charge, and with no obligation. An application on a free account can use up to 1 GB of storage and up to 5 million page views a month. When you are ready for more, you can enable billing, set a maximum daily budget, and allocate your budget for each resource according to your needs."
[1]: https://developers.google.com/appengine
[2]: https://developers.google.com/appengine/docs/whatisgoogleapp...
If I remember correctly Google switched their download service to using Go and there was a post here not long ago claiming they went from a lot of servers to merely 2 by switching to Golang.
See http://golang.org/doc/articles/wiki/ for an example.
And what might be the reason for that? Speed? Parallel processing?
Writing concurrent code is incredibly easy with the primitives Go provides: goroutines (think of them like green threads multiplexed to 1 to very few OS threads) and channels (similar to pipes). No more faffing around with details of thread creation and teardown or an unreadable mess of callbacks (like you would have in system with event loops). So, if you've written concurrent software (like network servers) before, check it out, you will enjoy it.
It always makes me smile when C and C++ young developers re-discover the compilation times we old timers already enjoyed with Modula-2 and Extended Pascal compilers in the mid-80's.
Ada, Modula-2, Modula-3, Delphi, Oberon, Oberon-2, Component Pascal, Active Oberon, Zonnon, ...
The industry just decided to look into another direction and now with buffer exploits everywhere, it is rediscovering that you can have strong typing with compilers that produce native code.
I explicitly mentioned Modula-2 on my previous post and most languages on the list are actually done by Wirth or with his input.
> None of them had anything fundamentally innovative or were just too obscure from the beginning.
Well, I consider systems programming languages with GC pretty innovative, given the way Native Oberon and Bluebottle were used in Zurich's Technical University. Even if the languages are pretty basic when compared with Ada or Delphi.
Go's method syntax is actually based in Oberon-2.
As a language geek, I tend to collect such information. :)
I wasn't claiming otherwise, but rather referring to Ada.
> And unlike Pascal, which was designed mainly for educational purposes, Modula and Oberon were designed for real world usage.
Guess which one caught on for real world usage and which ones mainly stayed in academia. Exactly.
Selling Oberon compilers for embedded systems since the late 90's
http://www.astrobe.com/default.htm
z/OS is coded in a mix of Modula-2, PL/I and Assembly. Newer parts of the system are nowadays written in C++.
The problem with any systems programming language is that it needs to be forced into developers by an OS vendor, otherwise very few will use it as such.
This is sadly what happened with those languages.
The synthetic language benchmarks also put it very close to gcc -O2 C performance. About the only things that need to be improved further (so I've heard) in Go are the GC, coroutine/thread scheduler and crypto performance. They are already better in 1.1 release but Crypto is still not close to OpenSSL performance.
Correction: It is a programming language with two compilers available as the main implementation, but there are also interpreters being developed.
I'm thinking something along the lines of honeybadger/hoptoad/etc -- automatic notification if the program crashes/deadlocks/what-have-you.
other issues: probably not, since these are new issues that are being worked on
1outyet.com and make a subdomain, so it could be
isgo1.1outyet.com ?
It was a demo in a talk by @enneff at Railsberry 2013: https://github.com/nf/go11
The site should update automatically once the repository is tagged.
I kinda figured they wouldn't leave the polling time at 5 seconds.