Introduction to Go 1.1
go.googlecode.com
go.googlecode.com
> The garbage collector is also more precise, which costs a small amount of CPU time but can reduce the size of the heap significantly, especially on 32-bit architectures.
Previously, 32-bit version was almost unusable is some cases when garbage collector kept the allocations for which he falsely believed to be used even if they were not. I'd like to know if this means that the problem is finally solved.
> Previous Go implementations made int and uint 32 bits on all systems. Both the gc and gccgo implementations now make int and uint 64 bits on 64-bit platforms such as AMD64/x86-64.
This is a C-like can of worms, forcing you to test on more platforms just to be sure that you have portable code. I believed there's no reason to do such things with primitive data types in the new languages of 21st century (compare with http://docs.oracle.com/javase/tutorial/java/nutsandbolts/dat...). I'd like to see any discussion about such in my opinion quite strange decision.
The size of these types have always been specified to be either 32 or 64 bits. The only change here is that 64-bit platforms will actually use that flexibility.
The probably most important consequence is that now you can have very large slices. The length of a slice is defined as fitting in an int, so slices were restricted to 2B items (signed 32-bit max); now they can be much larger.
I don't think there's any new gotcha here with having to test on multiple platforms. This is a change intended to give much more flexibility, but that flexibility naturally has to come with possible platform variation. If you are highly concerned with portability, avoid the int/uint types, and use the sized types (int32, int64, etc.) as much as you can. But in real code, as it turns out, it is rarely a big deal.
Hardly. If you need fixed integer widths, use the fixed integer width types. If you need types that are 'optimal' for the target architecture, use the non-fixed-width types.
The only time you run into trouble is when you make silly assumptions about the width of non-fixed width types, which is a bad idea in almost any language that doesn't vend automatic "bignum" scaling integers. It's not as if you can ignore the width of the types in Java.
Apple does the same thing themselves with ObjC; NSUInteger/NSInteger are uint32 on 32-bit systems, uint64 on 64-bit systems. All in-memory lengths, counts, sizes, etc (but not offsets) are defined as NS(U)Integer values.
I've done the same in my own code that's portable from 8-bit to 64-bit CPUs. Works out just fine.
Java is itself an odd duck; using fixed-width signed types without also offering unsigned variants has been a plague on every single person who has ever had to parse binary data in Java, ever.
People writing CGo code can avoid this easy enough by understanding the issue and using C.int where they want C style ints, but I've run into more than a handful of examples of actual code in the wild using CGo that has issues because it expected 'int' in Go to be the same size as 'int' in C, which it will be if the arch is 32-bit, but won't be if the arch is 64-bit. eg:
https://github.com/visualfc/go-ui/issues/11
IMO the right call would be just go with what C does and treat both int and int32 as 32-bit ints, int64 exists if you need it, but having 'int' size be different between C/C++ and Go on the same arch violates principal of least surprise, IMO.
The new GC is still not a precise GC, it's still conservative and non-tracing, just "more precise" (probably means they refined their heuristics) so you should probably not call it a precise GC.
Google could spend some cash to get them a real GC expert to work with the Go team, like they did for JS.
https://code.google.com/p/go/source/detail?r=eb2c99e6ec17db2...
https://code.google.com/p/go/source/detail?r=e7304334527349c...
https://code.google.com/p/go/source/detail?r=e5620fd3ba5fb1d...
Fast approaching OpenSSL speeds.
Also, the integration of the network poller into the main scheduler is likely to make a big difference to Go programs that make heavy use of the network.
If you want a timing safe cipher, use (X)Salsa20 from go.crypto repository.
Probably the easiest mistake to make is on DH/RSA exponentiation. Using the simple square-and-multiply algorithm gives away plenty of timing data; you usually need to explicitly protect against it by either using blinding or always performing both the square and multiply at each iteration.
Another worry I have is the 'backwards compatibility'. It sounds good but in the long run creates its own problems. I think Java and even Python run into major problems with this.
If you actually follow the links, you will see they are reimplementations of the algorithms in assembly.
GCC doesn't have any crypto code, fast or otherwise. Crypto algorithms routinely get dramatic speedups when going from C to hand-coded assembly, C compilers produce code that is far from optimal. See eg. http://cr.yp.to/aes-speed.html
> Another worry I have is the 'backwards compatibility'. It sounds good
> but in the long run creates its own problems. I think Java and even
> Python run into major problems with this.
At this point in Go's life, it makes more sense to be backwards compatible as the last thing you want to do is turn your back on your small current developer base. As Go grows and people have started adapting to the changes, then you can start depreciating the old stuff.And the compiler support is not yet mature. GDC has missed inclusion into GCC 4.8, while Go went into GCC 4.7, which makes using Go possible on a number of platforms and configurations.
http://benchmarksgame.alioth.debian.org/u32q/benchmark.php?t...
Not surprising though, as GCC's optimization backend is very strong and has been developed for a long time, meanwhile Go's compiler toolchain is very young.
As for Scala vs Go, Scala compiles into Java bytecode and then makes use of Java's excellent and very mature JIT compiler so I'm not surprised Go loses out to it for the same reasons mentioned above.
Also note that the Go version used on the 'Language Shootout' is the 1.03 version, not the upcoming 1.1 version, it will be interesting to see what improvements in performance have been made.
AFAIK the 32-bit version of Go (which is what you compared with in your link) has not been given as much love in the optimization department as the 64-bit version, which I guess would do slightly better atleast.
The reason the code quality (in optimization terms) of Go's compiler isn't that great is that the Plan 9 C compiler was always designed for fast compiles. This is a matter of design.
By comparison, LLVM/GCC passes code through multiple internal representations and performs many complex optimizations on them before emitting assembly.
Without knowing it's name :-)
If you have something specific to say, say it.
Is there a point to you continuing to spin on this???
Maybe once 1.1 is out and the language game switches to it, that will be the case (the benchmark is using the current stable release of Go 1.0.3).
Also, I assume you are talking about execution time, Go destroys Scala in your linked comparison in terms of memory usage.
One note, Scala uses more memory than Java does, so it appears not all of this usage can be blamed on the JVM itself: http://benchmarksgame.alioth.debian.org/u32q/benchmark.php?t...
Do you really think the JVM memory-use should be optimised for 100 line toy programs?
Why would you expect that? The JVM has years worth of advanced optimizations.
The link you provided doesn't point to anything called that.
On another note, your threads about the name change are adding little value to the conversation. Perhaps the time could be better spent? You are sort of wasting people's time. Next time, maybe simply say that the "Language Shootout" has been changed to the "Benchmark Game?"
It's important as an indicator of how much or how little you noticed when you looked at those web pages.
The other ways people don't see what actually is shown are more difficult -- taking memory use and code size measurements out-of-context.
Static typing arguably makes it easier to provide a deeper and more accurate translation, but Python did at least try. And note that's a link to Python's official docs, not a side project or something; 2to3 was created by the core Python team as part of the official upgrade path, not an afterthought.
For whom? Five years is long enough to realize that you might as well try new languages instead of porting all your code base (and maybe some libraries that you need) to the slightly improved but backwards incompatible version of Python.
I'm about to start a largish project in Go and I'm thinking I'd rather start in Go 1.1 rather than worry about upgrading and testing the project mid-development.
Go 1.1 is strongly backward compatible. You can start working on a large project right now with Go 1.0.3 and it'll work just as correctly under Go 1.1.
Thanks for the feedback :)
This is a clear API bug, and it's the only exception to the backward compatibility rule.
And the company is betting big time on Go, more than 50% of their codebase will be (re)written in Go in a couple of years.
Source: core dev on the golang team.
Teams and engineers at Google can use whichever language they want. (trade-offs abound) We're trying to make Go be the most compelling language with the fewer trade-offs so they're willing to switch. It's getting increasingly popular.
It's possible that 50% of new code will be written in Go in a couple years, but I've never seen that written as a goal. (And we do have goals. And usage charts over time, for each language, inside and outside the company, etc.) There's no way we'll rewrite 50% of all code in a couple years... there's so much code.
How feasible is something like this, considering Dalvik is a major piece of the way Android behaves? Would the VM just go away?
I really hope this is a skunkworks project happening at Google right now. Or actually I'd prefer it have major support up the chain, but I'll take a skunkworks project.
Android now has the installed base for developers to be forced to go along with whatever changes Google requires, and Dalvik could be kept around for quite a while as a backstop. I don't think the problems with Oracle are going away, so this might come to pass eventually, but I doubt it is on the roadmap right now.
They have been known to oversell the language.
No way is the quote accurate.
There's a lot of hype about Go, but I am not aware of cases where Google is overselling the language. Can you give examples?
Not Google. Just the Golang guys (Pike and co).
1) They sold it as a "systems programming language" at the beginning, to replace C/C++. When that didn't play well with actual system programmers, they reverted it to mean mostly server and similar back-end programming.
2) They emphasize as often as they can the "compilation speed", while for one is not a great concern for most projects, and second, other languages are just as speedy on that front.
3) They made claims of Go being "very fast" based on its statically compiled nature, whereas in practice it's slower than Java/Scala et co.
4) They downplay the fact that their GC is basically crap.
5) They make frequent statements about Go being used all around Google, but I've read Google employees deny that and say that it's use is quite marginal. The 2 greatest success stories they had offered are a simple component for Google Downloads (not the one that handles the whole thing) and a load balancer for MySQL fro YouTube. Not the kind of adoption to write home about.
2. It clearly does have an extremely fast compiler.
3. It clearly is very fast, and Pike never claimed it was the fastest.
4. The GC works and is an active area of development. They are open about this. What do you want them to say?
5. Could you cite them actually saying Go was used all over Google?
2. Sure. Much faster than C++. But, as Go is really a Java alternative rather than a C++ alternative, the compiler is not that much faster than Java's.
3. Yes, but not fast enough as a C/C++ replacement. It's not even as fast as Java.
4. The Go team has made some interesting, and risky, design decisions with the GC. They write: "Go must support what we call interior pointers to objects allocated in the heap... This design point affects which collection algorithms can be used, and may make them more difficult, but after careful thought we decided that it was necessary to allow interior pointers because of the benefits to the programmer and the ability to reduce pressure on the (perhaps harder to implement) collector. So far, our experience comparing similar Go and Java programs shows that use of interior pointers can have a significant effect on total arena size, latency, and collection times." It will be interesting to see how this decision pans out.
5. I think he pretty much just did. Or, to be precise, he quoted what is likely a false prediction.
It is true that both Go and Rust were first touted as a C/C++ replacement. Go clearly isn't while Rust clearly is. Go is a Java alternative minus the dynamic code-loading, and as such, hardly revolutionary. You get similar compilation speed, a slower runtime and none of the dynamic stuff. Go is sure a nice language, but Java shops are better off moving on to Clojure or Scala if they need a better language.
I don't accept your premise of "Java is the floor for acceptable performance in systems programming languages". Plenty --- perhaps most! --- new serverside code is written in languages much, much slower than Java. I'm not sure if I accept your premise that Golang is consistently slower than Java (if it is, the difference is marginal). On the other hand, Golang code starts instantly and has no runtime requirement.
I'm peripherally aware of some kind of rivalry between Rust and Go, but I'm not interested in discussing it; I use programming languages as tools to solve problems, not as tribes to join. When Rust is ready for prime time, I'll check it out and see if it solves any of my problems better than C, Golang, or Ruby, and if it does, I'll start using it. I have no plans to take seriously the idea of benchmarking the whole of Go against the whole of Rust.
I don't think there's a rivalry between Rust and Go, and if there is -- there shouldn't be. They serve completely different purposes: Go is an alternative to Java, while Rust is an alternative to C/C++. It's not about speed, either. It's about level of control.
So, having watched Rob Pike talk about Golang many times, and read a lot of what he's written about the language, I object to the way you're distilling what he's saying about the project. But, more importantly, I object to the sideshow.
One of the major selling points of Go is its concurrency features built into the language. Namely, first class channels and lightweight threads. Java has neither of those. In particular, very few languages support lightweight threads in an M:N scheduling style (Haskell, Erlang, Rust), which in and of themselves makes Go a very attractive tool for concurrent programming.
But the point wasn't to debate the merits of Go over Java or vice versa, just to say that they are both intended to be used in the same domains.
More importantly, I wasn't talking about scheduling. I was talking about lightweight threads. They are also commonly known as: goroutines, green threads, fibers, user space threads, etc. This has a dramatic effect on the style of concurrent programming, as spawning a light weight thread is cheap relative to spawning an OS thread.
Joe Armstrong explains [1] things better than I can:
Processes in Java or C# are pretty much like the objects in the flawed object
system which we described earlier - you can’t have many of them, and if you
have more than a few hundred processes the system will start misbehaving and
to do any real work with them you have to write your own scheduler and start
combining multiple threads of control into single processes. All of this
gives concurrent programming a bad name - and would probably make any sane
person think that concurrent programming was a difficult and should be avoided
whenever possible. The opposite is true.
And: In Erlang processes are *light weight*. This means that very little
computational effort is required to create or destroy a processes. Light-weight
processes in Erlang are one to two order of magnitude lighter than operating
system threads.
Not only are Erlang processes light-weight, but also we can create many
hundreds of thousands of such processes without noticeably degrading the
performance of the system (unless of course they are all doing something at the
same time).
In Go, "goroutines" are analogous to "processes" in Erlang in the above excerpt.My point here was that Go solves the concurrency problem much differently than Java does, to a point where Go is much better suited to write concurrent programs than Java is. Joe Armstrong's argument in his paper applies pretty well here.
I'm not really sure what is to be gained by debating over whether Go was "intended" to be in the same domain as Java. I've used Go to solve problems that I might have otherwise solved in a variety of other languages (C, Haskell, Python). Had I ever been a Java programmer, I'm sure that would have been in the list too. Experience in speaking with other Go programmers leads me to believe that I am not unique in this regard.
[1] - "Concurrency oriented programming in Erlang", 2003. https://guug.de/veranstaltungen/ffg2003/papers/ffg2003-armst...
As for 3 and 4, Go _is_ fast compared to a lot of languages, and has just gotten a lot faster. I think we're pretty realistic about the GC, in that we say it's simple and it works, and for most people it is more than adequate. We continue to spend a lot of time working on the GC.
One thing we do say, however, is that unlike Java, Go gives you more control over memory use so that you don't need to put so much pressure on the garbage collector.
5 - there's a bunch of Go usage at Google that we can't talk about. It is being used increasingly all over the place, but growth is pretty organic at this point. The public things we can talk about, we do. The Google Downloads thing is not a small component, by the way, but rather the entire download server. We hope to release part of that as an open source project soon, so you can get an idea as to what it actually does. One of the more impressive things about that particular service is that it serves massive traffic with Go's built in net/http package.
There are desktop operating systems being written in GC enabled system programming languages, namely Native Oberon and AOS. Both were and are used at Zurich Technical University (ETHZ) in operating systems research.
In the late 90's some developers even used them as their main OS.
You just need to have an escape mechanism to do the usual low level tricks, which is achieved by having a virtual package like unsafe, system or similar.
The problem with getting new languages adopted for systems programming is that they will only get adopted if there is a mainstream OS that makes use of them thus forcing the developers at large to use it as such.
Only now we see big companies replacing OS code that used to be written in C by C++. So how long it will take for any of the new contenders to defy C++ and in which OS?
As for the Oberon systems, you might find this interesting,
http://www.inf.ethz.ch/personal/wirth/books/ProjectOberon.pd...
But I can imagine, seeing how obsessive Google with performance usually is, that it mostly will be rewritten to save "millions of years" in optimizations. I believe Google is mostly using Java and Python.
Who? I am convinced you have misheard, as nobody in their right mind would make that claim. We have a ton of code, and thousands and thousands of programmers, so it's just not realistic. These kind of hyperbolic statements are harmful as they build distrust in what we're doing. I, a Go core dev, have no interest in being anything but straightforward on this topic.
Google uses C++ for most compute-intensive code.
I feel though that having a set, or a multiset, whatever... is exactly the kind of abstraction that makes it easy to think about your programs.
In the end I felt that my Go port of some Python felt much more error prone that the original code.
I agree. But many abstractions meet that criteria. That doesn't mean you include it in the language.
Also, it isn't just easy to implement a set with a map in Go, it's downright trivial:
type Set map[string]int
// Create set
set := make(map[string]bool)
// Add to set
set["new element"] = true
// Remove from set
delete(set, "new element")
// Membership test
if set["new element"] {
// "new element" is in the set
} else {
// "new element" is not in the set
}
Of course, this lacks common set operations like intersection, union, difference, etc. But in my experience, sets are most useful in their ability to represent a unique collection of elements with fast membership testing.Of course, it was simple to write a removeDuplicates fn that inserted elements from the array to a map, and back to an array. But that is the point of my parent comment... :)
Once, while writing something in Java, I found out that I needed a Multiset (didn't knew the term) and that Java had a implementation. As strange as it sounds, that made me very productive and confident my code was working... (Of course, soon you're writing getters and setters and hating Java again..)
type Set map[string]int
// Add to set
set["element"]++
// Remove from set
s[el] = max(0, s[el]-1)
// Membership
s[el] > 0
Here's a working example: http://play.golang.org/p/zMvVF1yERcN.B. This is a fiendish way of making good use of "zero" values in Go.
So to me it seems the Set type should be map[string][]type_of_elem, if that is possible.
[edit]
I'm confusing Multiset with Multimap... sorry.
[note]
Actually Multimap/Mutliset is not shipped with Java, but from Google... So it's not that "included".
Yeah. Remember, a multi-set is just a bag. If the bag is `{a, b, a, a, b}`, then it can also be represented as a simple frequency vector: `{a: 3, b: 2}`. There's no need to actually store duplicate values.
> So to me it seems the Set type should be map[string][]type_of_elem, if that is possible.
OK, now I see. It depends on what your definition of equality is. If the entire value represents identity, then my solution works. But if only part of your value (say, some but not all fields in a struct) represents identity, then my approach won't work at all. My approach relies on Go's built in definition of equality, which isn't flexible and cannot be changed. For instance, if you're storing values with this type in your set:
type MyValue struct {
Id int
Tag string
}
And these two values are equivalent: MyValue{5, "abc"}
MyValue{5, "xyz"}
Then you'd have to roll your own implementation. (Since in the eyes of Go, these two values are not equal. And that cannot be changed.)There are elegant ways around this, but it is certainly more clumsy in Go than it would be in a language with some sort of ad hoc polymorphism (like overloading in Java or type classes in Haskell). I think your idea is pretty close:
type MultiSet map[MyValueIdentity][]MyValue
type MyValueIdentity int
Anyway, best of luck to you. Don't be afraid to drop by the #go-nuts channel on IRC. We're a friendly bunch :-)!!! wow !!!
Now, if you want to see a recent language with a bit of style to it -- and bear in mind I know nothing of how it is to use in practice, so I'm basing my opinions entirely on the look of it -- I think Rust is one of the best of the pack. So much smoother.
TL;DR (for any Redditors who may have stumbled in on their way to the Ron Paul fansite): languages have a flavour, and Go's flavour is "mess".
But you can criticize its aesthetic nevertheless? Maybe if you could bring yourself to use it you might appreciate the elegance of the Communicating Sequential Processes implementation. Or maybe the clean OOP practices derived from using interfaces. Or the beauty of coroutines mapped unto multiple OS threads.
tl;dr: learn it properly before complaining it's not like mom's cooking
Compared to Erlang, for example, it's positively beautiful. I like Erlang's execution model, but the unnecessarily gnarly syntax and the antique approaches to some things (no real strings, no Unicode, tuples that depend on positional values instead of named attributes, horrible stack traces, tail-call recursion as a looping construct, etc.) has made me stay away.
Go is a decent alternative to both C/C++ and Ruby for me these days. There are plenty of things I don't like about Go, but it's easy to forgive many of them when the language makes you so productive (at least for the things I need it for; it's pretty bad at web app development and completely useless for GUI development), so I do. Sometimes you just want something that works, with minimal amounts of pain. C++ works, but is always painful to me because it feels like the language is working against me, not with me.
I love the simple syntax in Go; the no-nonsense approach to object-orientation, the way the typing system allows adding methods to arbitrary types, which may have been inspired by Haskell's typeclasses. I love having native Unicode strings, first-class functions, a simple package system, built-in concurrency and decent networking in the standard libs. I love the built-in documentation generator (although it's too simplistic at this point; why not Markdown?).
Things I don't like:
* Capitalized names for visibility.
* nils in the language instead of Haskell-style Maybe.
* nil cannot be used in place of false.
* The "non-nil being nil" insanity (an interface value can be nil, but it can also be non-nil and contain a nil value).
* Functions return errors instead of Haskell-style Either monads, or Erlang-style matching. (I see the problem with exceptions, but Go's solution is worse and leads to very awkward code that has to branch a lot to catch errors.)
* The fact that "go" is a language keyword; compare with Rust's very elegant task spawning, which is part of the standard library rather than being built into the language, and yet relies on first-class language constructs to integrate perfectly.
* That "range" is not extensible (that I know; it only works on maps, arrays, slices and channels).
* The whole GOPATH thing, pretty much requiring that you maintain a local tree with symlinks.
* That "import" when used with Git cannot be pinned to a specific revision (so if you rely on a third-party package, it could break your app at any time if HEAD changes; it's ridiculous, and counter-productive, to have to fork third-party repos just because of this).
* That packages have only a single nesting level. I don't mean that I should be able to create a package "x.y.z", I mean that given a package "x", all the files have to be in the same folder. I can't organize the tree in multiple subfolders.
* That statements are not expressions.
* That semicolon elimination necessitates some insane syntax at places (like having to end a line with ",").
* The lack of structural tagging in the language (similar to Python and Java annotations), and the fact that they did add tagging, but only for struct fields, and the tags can only be strings.
Right now, Go is, in my opinion, mostly an inelegant, weirdly-shaped thing that fits into the weird hole not filled by C and C++, a stepping stone to the next big language. I don't love the language, but I love how I can do the same things I was planning to use C++ or Ruby for; as a C++ replacement I gain productivity and simplicity; as a Ruby replacement I gain performance.
Go is, if anything, a very pragmatic compromise that favours simplicity over complexity at the expense of structural and syntactical elegance. It looks a lot like Java around 1.3-1.4, before the enterprise stuff derailed its focus. My concern is that Go has no particular philosophy as a foundation; it bakes in some current concerns (concurrency, networking, ease of use) and made itself a very useful hammer for hammering today's nails, but may not be as easy to extend to work with tomorrow's screws.
PS. I, too, come from Pascal — specifically, Borland's Object Pascal. While I have fond memories of that language, I'm not sure elegance was one of its main traits.
Re nils, yes this still feels pretty ad-hoc, I wonder if they'd do anything differently there now if they could? Probably there is no easy way out now they're past 1.0.
It would be nice to see an extensible range and I've had this thought myself (as have others), there has been some discussion on the list, and they're not sure: https://groups.google.com/forum/?fromgroups=#!topic/golang-n...
but then you can also turn it around and iterate by passing in a function to the structure to iterate:
func (self *DataStructure) Iterate(fun IteratorFunc)
Re GOPATH, what do you mean here?Re packages having one level - I actually love this - if you want to nest things in folders, Go is trying to tell you to split it into sub-packages (in that opinionated manner it sometimes adopts). Of course this might feel restrictive, but if a package has lots of files I'd rather it was split up and organised into packages with clear boundaries between them rather than into an interconnected set of files/folders which only makes sense to the author of the code because it's all in one package with no boundaries. This restriction means we will see apps composed of packages by default rather than all in one namespace because it's easier.
Re the versioning, they originally resisted versioning the language, but eventually gave up on that idea and used versions, so I suspect for packages they'll eventually recognise the need for this when the ecosystem of packages grows sufficiently. Versions do introduce problems of their own (dependency hell), but IMHO being able to reliably import snapshots of a package (tag, branch or version) will be essential long term without having to fork a repo and rename it just to do so. If go becomes popular you can expect this to be addressed by third parties if the go team doesn't bother.
Re the tagging, in a way I'm pleased that they avoid adding lots of features like this, as this is the stort of thing I hate even in the limited version they have (on struct fields) - it's untidy and gets misused and overridden to try to extend the language (see sql libraries in Go tagging fields with all sorts of their own meta-data).
Re commas on lists, this bothers me less than having to put semicolon & LF on every line, I think it's a fair trade.
Re philosophy, I can't speak for the Go authors, but I've found radical simplicity to be its overriding principle, which explains some of the limitations which annoy you above and the ditching of a lot of OO baggage which languages nowadays are expected to carry whether they want it or not. I've found the simplicity worth the trade for some small frustrations.
Yeah, any attempt to change this would have to introduce something like a per-package pragma flag to disallow nils. I feel they have painted themselves into a corner there.
> Re GOPATH, what do you mean here?
I mean that the "go" suite of build tools (build, get, install) rely on a specific convention: Your GOPATH is supposed to point to folders each containing bin, pkg and src subfolders with all packages.
Let's say I am developing a package A that uses my own package B. Both on Github. You're supposed to then create: $GOPATH/src/A (which contains A's files as immediate children) and $GOPATH/src/B (ditto for B).
The manuals I believe suggest that you have something ~/projects/go, under which you create bin/src/pkg and put your work. But I don't organize my home folder like that and I find it presumptuous that the tools assume that I do, so I have ~/.go, which contains bin/src/pkg, and I symlink stuff into ~/.go/src. Acceptable if annoying.
> Re packages having one level - I actually love this
I want to use folders as an organizing unit, the way they are intended. It makes sense even for small packages.
Generic example (I have something very similar to this, but I don't want to go into details): I have a framework. There is a bunch of core interfaces, and then a bunch of implementations. Let's say that my interfaces are called Queue (with concrete implementations FooQueue, BarQueue, BazQueue etc.), Block (again, a bunch of concrete impls) and Stream (same). For my brain not go insane every time I look at my source tree, I want to have the core interfaces in the root, and then subfolders queues/, blocks/, streams/.
That's not much to ask. Putting these things in separate packages with dependencies on the original package makes no sense, in particular because the original package has internal dependencies. For example, the framework has a configuration builder that connects queues, blocks and streams, and it knows certain things about the implementations and how they interconnect. Putting that into yet another package is just insanity.
It's one package. And it needs subfolders. (Especially with how Go mandates that tests be in the same folder as the unit being tested!)
I have encountered lots of C projects that pile all the files into a single root folder, instead of having a src/ folder with appropiate subfolders by category. I think that's what the Go guys are mimicking. I hate it.
I mean, just the fact that a package needs the Go files to be in the root is pretty bad. I may have a docs/ there, a readme file, an examples/ folder, a locales/ folder -- why must the source files go in the root? They're not that special. I know you can import directly from a src, but the convention is 'import "github.com/foo/bar"', not "github.com/foo/bar/src"'.
As I said, I don't want Java-style nested package names. All I want is to be able to organize the files. After all, the location of the files doesn't matter to the compiler. (Java used to be like this at one point, too, unsure if it's still the case: What you put in the package decl didn't need to match up with the structure of your folders.)
> Re the versioning, they originally resisted versioning the language ...
Hope this will be solved. I suggest something similar to Ruby's Bundler -- don't make it part of the language, but part of the development environment.
> ... as this is the stort of thing I hate even in the limited version they have
Agree, I would rather see no tagging at all, rather than the flimsy stuff they have today.
Re folders versus sub-packages, yes I take your point - again there are some conventions here they've tried to impose to make it simpler for the package tools, but those could get in the way. I also hate projects that have all the files piled into one dir, so I prefer to break into sub-modules where possible and make the organisation clear. The other advantage of this is that people could use just your sub-module if they want.
I've developed a few packages which I wanted subfolders for, but those subfolders naturally became sub-packages without much wrangling - seeing too many files on one level forced me to organise them and create more packages. One case for example mirrors your usage - a top level pkg, with interfaces and concrete types for specific databases, which lived in their own folder 'adapters' this became a sub-package, which contained the interface and concrete implementations, and it being a package forced me to remove any knowledge of the enclosing package and any circular refs - the top level pkg knows about the adapters, but adapters don't know about the top level. I felt like this was making the code better, not worse, by removing internal dependencies, but YMMV, and I can see how it would be annoying. I'm willing to forgive conventions like this if the tradeoff feels worth it (in this case I really like the go gettable packages, and to have that am willing to live with restrictions like some code must be in root, folder=subpackage, etc.).
import (
"github.com/foo/x-core"
"github.com/foo/x-adapters"
)
or import (
"github.com/foo/x"
"github.com/foo/x/adapters"
)
If the second, then do you need to do something special with regards to compilation or anything else?One thing that bugs me with the second approach is that the package names then have to be different. If the original core package is called "x", and you have an "adapters" package, would the package name be something like "x_adapters"? Just "adapters" seems a bit presumptuous (it's very generic).
So I'm using obvious names, with the pkg (say core) in one folder, and subpkg in the subfolder named adapters.
"github.com/user/core"
this has a few .go files in it to split things up into different concerns, and a subpackage with adapters (again with a few files), imported with: "github.com/user/core/adapters"
and using adapters.XXX in the core code. You can also do this: import
(
mypkg "github.com/user/core/adapters"
)
and use mypkg.XXX to refer to the subpackage, so you're not tied to the folder names for package import names, that's just the convention, and if someone needs to rewrite the name on import, they can do so.What attracted me to Go initially, was Oberon's influence in the language, like the packages, method signatures, Pascal declaration way and low level tricks exposed via the unsafe package.
But like yourself after a while using the language, before the 1.0 release, I came to the conclusion that I am better served with more expressive languages.
So nowadays I play around with C++11, Rust and D.
Go's design seems like a step back for my sensibilities. I do like how it forces you to do something when the error is easy to contain, but checked and unchecked exception handling seems to make it more obvious how to treat an exception. Of course exception hierarchy can be abused, but done properly it seems more descriptive and flexible. Only when people abuse exceptions to drive business logic have I found them unappealing.
I'm adapting though.
I use make for this:
GOPATH := ${GOPATH}:${PWD}
all: always
always:
@go build -v myprogram
deps:
go get github.com/mattn/go-sqlite3
go get code.google.com/p/gorilla/context
go get code.google.com/p/gorilla/mux
fmt:
go fmt package1 package2
docs:
godoc -http=:6060 &</sarcasm>
Rust makes me think on Haskell but it is not so far away from Go, IMHO. I just skimmed Rust tutorial so I'm probably missing something.
* GC works on 32 bit systems.
* Scheduler improvements so that things are a bit more robust ( http://code.google.com/p/go/issues/detail?id=543 )
* A fairly solid library implementing supervision trees or something like it.
* Probably some other things, but those strike me as the big ones. The important thing is for the system to be able to run for months at a time.
I think they'll get there eventually. Maybe not 100%, but 'good enough' sooner or later.
I've done Erlang for years and Go for weeks, so I'm trying to withhold judgement, but I still feel like Erlang got it more right here; it's way easier to restrict yourself to a subset of Erlang that looks like a channel if that is desirable for some reason than to implement process features with channels in Go.
Something like
type Crash struct {
PID int
Panic interface{}
}
var crashed = make(chan Crash)
func parent() {
go child()
oops := <-crashed
panic(oops)
}
func child() {
defer func() {
if r := recover(); r != nil {
crashed <- Crash{1, r}
}
}
panic("boom")
}Erlang: perform a maximum number of reductions, then switch, or switch on IO. The number of reductions is cleverly adjusted so that a process which is swamping other processes will be throttled.
Go: switch on IO.
Go's design is much simpler, and closer to Ruby Fibers than to Erlang processes, except that goroutine scheduling can use multiple threads. To cooperatively switch without doing IO, call runtime.Gosched().
* You're still using Java threads, so the potential to access [shared memory][1] is there (i.e. "shared nothing" can't be guaranteed).
* You're still subject to global GC pauses, whereas the Erlang VM has per-process GC.
[1]: http://doc.akka.io/docs/akka/snapshot/general/jmm.htmlShared memory when running on the same machine is actually more efficient since there is no need to copy immutable objects.
If the sophisticated low-latency GC options available on the JVM are not sufficient for you feel free to fire up more JVM instances on the same machine or on other machines.
If you follow the comments there, someone improved the Erlang benchmark to 3M messages/sec, beating Akka once again: http://musings-of-an-erlang-priest.blogspot.dk/2012/07/i-onl...
> Shared memory when running on the same machine is actually more efficient since there is no need to copy immutable objects.
Many Erlang processes fit onto an OS-level thread or process, so passing messages is very fast ("copying" shouldn't be equated with context switching OS threads).
> If the sophisticated low-latency GC options available on the JVM are not sufficient for you feel free to fire up more JVM instances on the same machine or on other machines.
Akka is a library and can't make guarantees about how the JVM will perform garbage collection of actors while Erlang has it built into its VM. No amount of creating new JVM instances will change that.
You assume incorrectly. I'm referring to the version where Scala was 44% faster than Akka: https://plus.google.com/112820434312193778084/posts/HdKFx4VQ...
In any event the application logic in Java will likely outperform erlang. See: http://benchmarksgame.alioth.debian.org/u64q/benchmark.php?t... where Java outperforms Erlang by 3-30x in most cases and uses significantly less memory in most cases.
> Many Erlang processes fit onto an OS-level thread or process, so passing messages is very fast ("copying" shouldn't be equated with context switching OS threads).
Many Akka actors fit into a single process and there are many actors per OS level thread, so this isn't really a useful point for comparison.
> Akka is a library and can't make guarantees about how the JVM will perform garbage collection of actors while Erlang has it built into its VM. No amount of creating new JVM instances will change that.
The JVM does the GC, not the library. Is 100 microseconds not short enough for your application? http://mechanical-sympathy.blogspot.com/2012/03/fun-with-my-...
> Is 100 microseconds not short enough for your application?
GC time is not a useful benchmark by itself. The important thing with the JVM is that you can't predictably reason about when the global GC will happen (global GC pause). Your JVM actors aren't shielded from these global GC events so building a soft real-time system is less practical under the JVM than the Erlang VM IMHO.
Regarding soft realtime requirements Erlang may be a better choice, but I doubt there are too many use cases where it will make much difference.
Why are the methods we define restricted to the types we define? I'm SURE there is a good reason.
Others have said that it's because if you did allow that kind of thing to happen, you might get naming collisions in packages. I don't buy this argument, you could get naming collisions anyway from packages, Go resolves those issues by aliasing. Go also allows for polymorphic behavior by packaging the actual type of the method caller with its actual value, so resolving which method to use isn't any more complicated.
I don't get it, I'm sure there's a good reason! I just hope it's a good enough reason to throw out the kind of freedom that would allow you.
Besides, embedding a type is very easy http://golang.org/ref/spec#Struct_types
I'm reading through the embedded types now. I am new to golang so this one is lost on me. I thought if you wanted your own methods on a type from another package, you just aliased it with your own type def.
though it looks like there's some kinda prototyping behavior being described here?
If S contains an anonymous 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 anonymous field *T, the method sets of S and *S both include
promoted methods with receiver T or *T. v, ok := x.(T)
http://golang.org/ref/spec#Type_assertionsIf you "monkey-patch" x to satisfy T in another package, the value of ok may change.
If you make package A depend on package B, package B monkey-patches x with method Foo so now x is a Fooer
x now satisfies the Fooer interface in package A, well that seems ok. You imported B after all. In things that don't import B, x doesn't satisfy Fooer. Is this unexpected behavior? If B depends on C, C's x won't satisfy Fooer right?
You might be interested in this document: http://talks.golang.org/2012/splash.article
Naming collisions are a solved problem.
On the other hand, you have to import functions, so your example isn't a problem.
No. Some people's experience with Go. People that might not have much experience with generics to start with.
And if they think the rest are "doing it wrong", they are mistaken.
Well, I as someone who has professionally worked with C++ for over 5 years and used C++ templates quite a bit, I never ever needed generics in Go even once.
Why do you think is that so? Maybe because I do not force my C++ style of thinking onto what language features Go offers and instead write idiomatic Go code?
(n.b. I did more than just playing around with Go a bit, I wrote serious applications in Go some of which are in production use)
I agree that in most other cases, it turns out you can write a simpler API than Thing<OtherThing<Key, ? extends Value>>, and nobody wants to open the door to that mess. But for containers, they either need to dramatically multiply the number of built-in container classes (slice[] map[] are generic in a way), or create a way to write your own.
Using a functional programming approach, data processing is easy because you can create new data by taking old data and specifying a transformation process. With Go, I had to manually handle the iteration through the old data's container object.
Not a huge deal, but it felt like I was reinventing the wheel in every goroutine.
When you are writing an application, you can know all the types you are going to need, so that you can work around the limitations of Go's typing system. When writing a library, you definitely don't have all the information.
I found that in some languages (Haskell, OCaml, Scala), a common way to write applications is to write the different parts you are going to need as generic libraries and then combine them together. I don't think this is the common way Go programmers do thing.
Go's packages make the practice described above explicit, and many go programs are made up of generic libraries (packages) which define protocols (interfaces) for the types which are passed in, and need know nothing else of those types in advance. So what you describe above as what Go should be like is the normal approach to programming in Go, and many parts of apps (packages) are actually reusable in other apps without modification precisely because of this.
Are you saying that every one of the many serious engineers who miss generics when writing Go are just not thinking outside the generics box? Or are you willing to admit that, while Go without generics may be a great language for many applications, there clearly are applications where generics are the right language construct for the job?
Not to mention the fact that this makes it harder to reuse data structures and algorithms, which can have a much bigger impact on performance.
If I want to create a new wrapper class, the last thing I want to do is either make it hold an Object, or have to write a new version of it for every type it can hold.
Can't you solve this problem with an interface defining the behaviours your wrapper expects? The interface can then be passed in or held as a ptr without requiring a specific type, allowing a generic implementation. You can create a generic iterate or sort function for example which operates on slices of a given interface. Sorry if I've misunderstood, if so a code example might help clarify what you mean.
In C# I can define this once, and then any service can just return a Reply<string>, Reply<int>, Reply<Address>, etc. The calling method can check the associated reply status, and then unwrap the data if the call was successful, displaying any associated messages as needed.
Or, for a different example: If I want to store a long list of Customers in a dictionary, keyed on String, then in C# I'd create a Dictionary<string,Customer>, and know that it would always contain the types I'd expect.
How would I do either of those in Go?
1. Generic reply (for a good example of this in use see the way errors are used in go; errors are extensible and can contain info like that in your example).
http://blog.golang.org/2011/07/error-handling-and-go.html
For your example, you could have a reply interface, defining the requirements, then concrete types which conform: http://play.golang.org/p/e18n36Ub5u
There are probably shorter ways to do this, this is just an off the cuff example, but it's quite possible to have generic reply types which respond to any methods you want, and can be created easily and extended if necessary. You can also cast back to the original type.
2. Just use map[string]Customer - Customer could be an interface (duck typing) or a type.
Something like this: http://play.golang.org/p/ZoftbY8mQX
IMHO using an interface here is more interesting, as it lets you define your requirements, and forget all about the type system, while letting the compiler check that any uses will always work as they conform to the interface.
Here's what I think you want, written in (as far as I am able to) idiomatic Go:
That strikes me as terribly unmaintainable.
Yes, if you want it to actually be a Reply, it has to implement Reply.
That's acres of template code being duplicated all over the place
No, if you need to reuse code you can use other techniques like embedding (not shown in examples).
The features and restrictions differ from many other OO languages but I think the creators of Go deserve a little more credit than you are giving them - they do not produce unmaintainable code (see std lib for Go), worked on a large scale with C++ OOP previously, designed the forking Unix operating system, and are not unaware of the ramifications of the decisions taken.
Maybe I don't know what exactly you want.
The Foo and Bar in my example have quite different CheckStatus() methods because those two structs are quite different. If there were more similar, then you could share more code.
In the second example no, in the first example, if you want two types to conform to an interface, you need two types - Go interfaces require an implementation.
In real code this is not really a limitation - types require minimal boilerplate in Go, and the complete definition can be one line (e.g. type StringReply string). You can create them very easily, and wrap standard types in them (see the error type example NegativeSqrtError). I'm not too familiar with C# generics I'm afraid so am guessing as to what you want to do. Go already has support for generic maps and lists which can take any type or interface (as in your dictionary example), so that's not really a problem. Maybe someone else who knows both better will jump in.
If you wanted to treat two types (string and Customer) in Go as the same sort of thing (a Reply), you can do this with an interface. Then you can work with anything which conforms to that interface. Let's say you have this reply interface:
type Reply interface {
Reply() string
}
That requires a Reply method returning a string. You want to pass around both a string and a Customer (using say its name) as a reply? Define what each does when it replies - this is required so that the compiler knows you are passing the right sort of type, and so that you can actually use them as replies (NB you can't add to built-ins, so you have to add a new StringReply type): type Customer struct {Name string}
func (c *Customer) Reply() string {
return fmt.Sprintf("%s",c.Name)
}
type StringReply string
func (s StringReply) Reply() string {
return string(s)
}
http://play.golang.org/p/uLgSpbTx24so you could have a list []Reply or a map[string]Reply, or some custom collection type which can only have Replies added to it and nothing else.
If you want to reuse code between types, you can have helper methods or embedded types (NB only reusing code, not data, this is not inheritance).
Code above is trivial of course, and if you see code repeated in other examples it'll be because of these are little toy examples - you can use composition of types or helpers which act on interfaces to avoid repeating yourself. In real code you tend not to have quite such simple interfaces or types. If you feel we're not getting at what you want, posting a C# example of something you think would be impossible in Go would be helpful, otherwise you can assume that what most of what you can do in C# etc can easily be handled in Go as well even if the concepts don't map 1-1.
Reply<T>{
T ReplyData;
bool TheCallWorked;
string AssociatedMessage;
// other stuff here
}
and that's it - I can now have a reply that bundles up any type I like. My GetAddress function can return a Reply<Address>, my GetCustomerAge function can return a Reply<int>, etc.Whereas you're having me recreate that boilerplate for every different reply type - which means that if the information needed for a Reply changes, or I have to make a fix to the associated code, I need to change every instance of it.
You could reproduce your example above using a base reply type with ReplyData as an empty interface{} ptr (you'd have to wrap built-ins like int) and accessible fields. You could attach functions to that and only change them once and extend by embedding it in other special types of Reply if you wished. Typically though you'd have a base reply with bool and string say, and then extend that with other types of reply which make sense in certain situations rather than a generic payload which could be anything - so make ReplyData or a Reply type conform to an interface to ensure it does what your receiving methods want.
You can do the same things without them - but you have to write separate code for each type you deal with.
.NET has generics? I mean, actual generics, not simple first-order parametric polymorphism with type constructors of the kind (* -> *)? Can you write, say, a generic reader or a generic printer that will work with all types? How would you go about doing that?
Looking at the Parametric Polymorphism article on Wikipedia, that indicates that implementing it produces generic functions and generic datatypes, which is what I'm talking about here.
Sadly, beyond about the third sentence of that article I'm lost :->
How often do be people accidentally divide by a constant 0? I personally use that to simulate runtime errors all the time in python. It's shorter than writing "raise Exception()".
const int SomeNumber = 0;
// then much later in the program
return 3 / SomeNumber;
An accidental and not immediately obvious divide by constant 0. const weasels = 5
const lawyers = 5
const mustelids = weasels - lawyers
feedWeaselsEach(chickenPortions / mustelids) > How often do be people accidentally divide by a constant 0?
As much as I do love the level of checking that Go's compiler does, I must admit I asked myself that same question when I read the article.Depends how far the compiler goes to simplify constant expressions. It could be quite useful if it detects something like:
f(x,y) : x / (x - (2*y))
f(6,3)
If the size of an integer is critical to the execution of your program, then you should be using int16 or one of the many other types that specify the number of (un)signed bits.
The int type is designed to be platform specific to optimize on execution speed when the maximum size of the integer isn't an issue.
And regarding optimization. Language-defined integer type size is one thing and CPU register sizes used in calculations is different thing. It's not like having 32-bit int forces you (or compiler) to use 32-bit registers.
For every int we (i.e. programmers) should be aware of possible min and max values that can be stored in it. Thus we can easily use fixed-size ints everywhere, paying attention to signedness too of course. The problem is that there is high temptation of using int most of the time, because it's easier to write (it's shorter). For the same reason many C programs use int instead of unsigned short or uint16_t for instance. Well-defined int size is part of self-documenting code, as it shows mindfully applied constraints.
My point is this: the problem when talking about "best practices" is there's some approaches that actually doesn't make a huge deal of practical difference, so it's more subject to specific circumstances (eg developer time constraints) or even just personal preferences (eg the arguments between ()\n{\n\t and (){\
Anyhow, in answer to your other post, the intn and uintn types have been available in Go since day one. So (and in answer to your original post as well), this int issue you raise isn't an issue unless developers have written extremely bad code to begin with (ie written counters which they know will exceed a 32bit integer and not cared enough to write an error handler nor specifically use an int64 type). Go does do a lot more to protect the developer from shooting his own foot off (more so than C/C++), but if we're completely honest, if the developer is crap then no amount of hand-holding from language design will help.
Actually, memory is even more of a luxury than ever, since your caches have limited size and main memory bandwidth is atrocious, compared to the speed of your execution units. Using 32 bit fields for stuff that safely fits into 16 bits can cost you for that reason alone.
I'm all for performance tuning and writing efficient code (like I said, I learn to program back in the 80s when every bit of data mattered and various tricks were used to work around the limited power of those systems), but let's be clear about one thing, memory these days is not "more of a luxury than ever". The exact opposite is true.
In practice, as noted in the link, this is not a big deal as most people will use a specific type to avoid any potential issues, particularly when dealing with bitfields etc. you should be doing this anyway.
In practice, only when you're writing some loops with small number of iterations etc., you don't care whether your counter for instance is 24-bit integer or 48-bit, because 16-bit or maybe even 8-bit would be enough. In most other cases you care whether 64-bit value will fit into your value or not and whether it can be there at all. And if you care about memory you use smaller ints in your structures when bigger ones aren't needed.
So, to some extent, it is indeed not a big deal. But it still isn't "not an issue". We gain more than 2^31-1 elements in slices on 64-bit platforms, true, but it should be possible from the beginning, without need to redefine int on such platforms.
> Previous Go implementations made int and uint 32 bits on all systems.
> Among other things, this enables the allocation of slices with more than 2 billion elements on 64-bit platforms.
If they truly wanted to have platform-dependent int, then why 64-bit int on 64-bit platforms wasn't introduced from day 0? It's a valid question, because it would avoid this big (implementation) change at all.
> However, programs that contain implicit assumptions that int is only 32 bits may change behavior.
I can agree that this assumption is wrong, but why changing int implementation now?
> Due to the change of the int to 64 bits and some other changes, the arrangement of function arguments on the stack has changed in the gc tool chain. Functions written in assembly will need to be revised at least to adjust frame pointer offsets.
My main point is that variable-sized int implementation and usage gives more problems than we get profits in return, even more when previous and widely used 1.0 version, which 1.1 is going to be backward-compatible with, did it differently.
Again, I wouldn't comment if variable-sized int was in Go 1.0 implementation, but it wasn't.
It has always been in the Go 1.0 specification:
"There is also a set of predeclared numeric types with implementation-specific sizes:
uint either 32 or 64 bits
int same size as uint"
http://golang.org/ref/spec#Numeric_types
It's just that the Go 1.1 implementation now takes advantage of this freedom.
Because we have finite time, and it was easier to implement at the time. This property has been in the language spec since day 1. It should not come as a surprise to anyone.
How much of my hundreds of thousands of lines of Go code have I needed to change because of this implementation change? None.
And quite frankly, if your code relies on a an integer to be 32 or 64 bits, you should be using int32 or int64.
Personally, I think it's silly to delete this thread, but I appreciated his warning that this [article / document / HTML page in a source code repository / whatever the hell you want to refer to this as] is only a draft document for a version of Go that's not yet been finalised.
Does anyone know if it is possible to determine what version of Go a given binary was compiled with? Perhaps extracting some metadata from an ELF section?
I'm not sure if I understand what "method values" are though
func (w *Writer, int n) {
}
is actually a method, like: func (w *Writer) Anon(int n) {
}