C vs GO
crypto.stanford.edu
crypto.stanford.edu
C is for low-level code, where you usually want deterministic, real-time behavior. Go cannot deliver that because of its GC.
You can certainly write web server software in Go (what Go was designed for), but could you write an "AAA" video game in it? Or a mission critical embedded system with real-time requirements?
Also, the author's portrayal of C is misleading. If you have 'naked' malloc() calls all over your code you are doing something wrong. Much C code never calls malloc() or follows the "no allocation after initialization" principle.
If you write C like Python you will run into problems. In C you do not wildly allocate objects on the heap all across the program. E.g. in my current program almost everything comes out of memory pools. E.g.
Object* object = ObjectNew();
..and if I forgot to release it I would know quickly because any "memory leak" would cause the (pre-allocated, fixed size) memory pool to run out of free slots. In C you should manage memory in a systematic fashion.
I think the C standard library should be seen as the very foundation of a program, something you use to build the abstractions which solve the problem, not something you use directly to solve the problem. People often warn about the dangers of strcpy() (an the author uses it). I never use it except at the lowest levels. At the high level robust C code looks more like this:
ObjectSetName(object, newName);
than this
strcpy(object->name, newName);
..the difference is that ObjectSetName() can internally guard against overflow and that the concrete details of the object data structure remain hidden and thus later code changes are easier. It is a very common C idiom to use incomplete types and such functions to achieve a very high level of encapsulation.
That aside, in Go you can also do fixed allocations and manage your own memory pools to avoid the GC.
And I would also question how many C programs require real-time behaviour (even the definition of 'real-time' has issues, most things people call 'real-time' aren't).
Because we learned a lot about writing more robust and maintainable software since the 1970s. Also the original Unix source code was one thing more than anything: small. Really, really small. Mostly because it did not do much compared to a modern OS.
Things like encapsulation, separation of concerns, etc. only become important once the code grows to a certain size. Unfortunately some people think you need at least C++ for that, despite the fact that for example "private" member variables are way less private than incomplete C types. C is old, but that does not mean it is incompatible with modern software development approaches. Or that you have to write code as if your compiler only parsed the first few letters of an identifier. I think C's bad reputation in some circles can be explained by people only ever seeing 1970s style code.
No, sorry.
>is it all experiential from the trenches?
It's mostly about applying general principles of software construction like separation of concerns, encapsulation, robust interfaces, etc.
Plan 9 wasn't written in the 70s. OpenBSD is another example, probably a better example given that their sshd is far more important, and running on far more machines than anything you've ever written. So it seems rather disingenuous to suggest that the authors of such software are wrong for writing simple, concise, effective code instead of your bizarre vision of C.
Furthermore, memory pools compromise safety: if you free a pointer to an object in your memory pool and you accidentally had aliases to that pointer, then you'll get subtle bugs when one of those objects gets reused.
The only code I've seen that actually had zero allocations in a GC'd language is actually Emscripten-generated code in JS, which is of course not actually JS but C.
Hard real-time generally means that you have an actual deadline to finish your computation, and Very Bad Things will happen if you miss that deadline. Both of your examples are soft real time.
Go could do a recording type application with minimal guaranteed latency just fine, and the GC won't stop it doing so.
How many people are writing "hard real-time" code? I suspect not many, and yes, for them probably Go is not the right tool at the moment, but also in great part because nobody has needed/wanted to use Go in such environments yet.
You are correct that not many people write hard real-time code; it's generally found in such things as software controlling planes, power grids or power plants.
import "runtime"
...
runtime.MemStats.EnableGC = false
https://groups.google.com/forum/?fromgroups#!topic/golang-nu...Perhaps not, but an extremely large percentage of commercial indie games are written in managed languages.
Your C is not idiomatic even if you're right about avoiding naked mallocs and Go not being appropriate for systems programming.
I honestly can't tell if he is trolling or if he is serious.
I don't think he's trolling, but I do think he's playing to C's strengths and Go's weaknesses, possibly by accident.
It is ironic that their motivation is to tame and restrict the use of exceptions, and then they replace them by something even richer and much less structured. I fail to see any pros of this proposal. It seems mostly equivalent to exceptions, i.e., you can easily express raise/try/finally as syntactic sugar, and likely the other way round. But it is (1) much more ad-hoc -- you cannot give a simple reduction semantics for this, (2) much less orthogonal -- tying `defer' in with function definitions, (3) dependent on mutation -- for recovering and returning alternative results, and implicitly in the semantics of `defer'. One consequence is the loss of beta-convertibility, which means that you as a programmer cannot take an arbitrary piece of code and turn it into a function anymore, or vice versa, eliminate a function by inlining its body. Such abstractions/refactorings are impossible in general under this proposal, or at least require transforming the relevant code in potentially non-trivial ways.
"Go is not meant to innovate programming theory. It's meant to innovate programming practice." I really like the out-of-band errors since they make control flow very explicit. With languages that rely on exceptions a lot (python, for example) I feel less in control of my program since 'anything can happen' remotely from my code.
For any function which produces values of the form (a -> (b,e)) I'd refer to that as a product type. If this is what you're referring to, this is just a return value. There isn't really an exception system here.
If you think about how return values work in C you'll note that it's usually some subset of the range which is defined for an actual value and some subset defined for an error condition. This is basically the same as (b,e), just worse type safety. Easy and efficient tuple constructions are hard to create in languages with manual memory management.
Edit: Also, I didn't mean that Go should have innovated in PLT, only took advantage of innovations already established.
Yes, which is awesome.
> If you think about how return values work in C you'll note that it's usually some subset of the range which is defined for an actual value and some subset defined for an error condition.
This would be an 'in-band' error, as opposed to 'out-of-band.' It's terminology borrowed from communications theory. You also see it used to describe an 'out-of-band' console that is a secondary way to SSH into your machine if your network is hosed.
> Also, I didn't mean that Go should have innovated in PLT, only took advantage of innovations already established.
I think the point is that this is intentional. I love super high-level languages, but they're experimental for a reason -- things haven't 'settled down yet' and until they do, it will be difficult for the average person to reason about what is going on. Take garbage collection: this was technology that had been around for decades, but computers and garbage collection algorithms had to be sped up and tuned before general adoption. Large systems demand predictability and integrity on nearly every dimension. Luckily as time goes on, the experimental stuff becomes the expected; advanced programming language theory gets built into larger systems and we all benefit. Go is part of that evolution.
No, sorry, I should have been even more explicit: it looks like the designers were not even aware of new advances in PLT. As far as I can see, defer/panic/recover is objectively worse than an exception system for all of the goals which they lay out in their paper.
You like return values--ok, I can see that. I prefer that the type checker actually enforce error checking when using error return values, but fine.
Adding defer/panic/recover is an attempt to add a simpler and more constrained exception-like system to the language, but I think it is objectively (both from a PLT perspective and compiler-design perspective) worse than a more traditional exception system. Breaking beta-reduction is very unfortunate and I can't see a good reason to do it in this case.
Ken Thompson won a Turing award, dude.
I don't think GP was saying that Go should have provided some advance to programming language research, but that it doesn't show much awareness of advances that have already been made.
[Go] doesn't show much awareness of advances that have
already been made.
Go's response would be to question that the things you're talking about are, in fact, unqualified advances. Especially in the context of large (ie. LOC) systems applications, maintained by large (ie. dozens to hundreds) of developers. Java, C#, Python, Lisp, and Erlang would all criticize
Go for an unqualified new exception system
panic/recover is not an exception system in the sense that you mean. Nobody is writing large applications and using panic/recover for error handling. (At least, I hope not!) The idiomatic way of handling errors in Go is returning them explicitly, and checking for them at the call site. func canFail() (int, error) { ... }
value, err := canFail()
if err != nil {
// handle
}They can be used for other things, but in those cases they never cross API-calls so you never have to worry about whatever a library you call might panic, you can basically ignore panic/recover exists completely, and do just fine, and that is what most people do most of the time.
Structs with functions isn't the biggest deal, and namespaces can be simulated with a couple underscores. But I have a hard time with error handling if you don't have exceptions, any time I have a call stack more than 3-4 deep I find myself confused about how to treat certain errors. Then there's concurrency.
I do think that all semicolons really shouldn't be used. The only time I ever use semicolons is for error checking in Go.
Also, who cares what his style is?
If _you_ ever have to work on the code, run gofmt on it; if that's how he likes his go, good for him.
Me, because I found it unpleasant to read. Working on such code is beside the point.
What's the point of making the code so dense anyway? Without syntax highlighting I gave up pretty quickly.
Anything counts.
Go code is obviously formatted with gofmt. C code is obviously not formatted with "indent -kr".
Liberal use of comma operator unseen in real world.
Look at example of yes(1) with error-handling.
Author doesn't use strdup(3).
But even if he did, it still doesn't make sense to call fprintf(3) once due to allegedly hard error handling. Error handling is not common path, fprintf(3) doesn't fail!
He concatenates all string into once which makes it O(n^2) because of many many times strlen(3) is called (and kernel copied argv contents before that!).
I bet he did error checking wrong on C side (just checking return value should not be enough). It'd be interesting to see same code on Go side.
Obligatory quote: "considering that bad code can be written in any language, any language comparison performed using examples must be judged by the quality of the examples in each language. it can't be all that hard to write a bad example in language A and a good example in language B, and then proclaim language B to be the winner -- this is how people compare languages all the time, so either those who read them are bad programmers in any language (or are not programmers at all) and don't know how to reject the bad examples, or they already agree with the author of the comparison that language B is better than language A. in either case, it's a waste of anything but marketing money.
...
#\Erik"
Is not, he also inlined some things, e.g. this:
import ("flag";"fmt")
would be expanded to multiline by gofmt, as well as this: if i>0 { fmt.Print(" ") }
As to other things, I can't comment now, as I don't have time to read through all of the article at the moment.In fact, in pretty much every thread go turns up in. sigh I'm just going to link to my favourite review now, again (pertinent, and mentioned here only because the author of the original shared a favourite with me): http://www.math.bas.bg/bantchev/misc/on-go.html
Quote: "But I know I am not going to love Go. True beauty evades this language. Go may be practical, but is also eclectic, and has taken some unconvincing or downright ugly design choices. It definitely lacks that subtle but unmistakable touch of elegance that makes a language great."
1) That Go has i++ and not ++i. Don't even know what to say to someone who thinks this a major issue, really.
2) That the declaration syntax is 'unattractive' and different from other languages. Yes, the syntax looks a bit strange at first if you are used to C, but it is unquestionably cleaner and better, specially in more complex declarations. This is even covered in the FAQ: http://golang.org/doc/go_faq.html#declarations_backwards
His other complaints seem to be about the name of the language and how much some of the Go documentation acknowledges the influences of certain languages, which as he himself says, is just politics and not really relevant to the language itself.
At the same time there seems to be plenty of people who actually have used Go and love it, including the designers of other languages:
if (argc < 2) puts("y"); else {
for(int i = 1; i < argc; i++) {
if (i > 1) putchar(' ');
printf("%s", argv[i]);
}
putchar('\n');
}
A casual skim sees the if followed by an indented block, but that isn't the then-path but the else-path. Now yes, I can read it carefully and follow it, just as if I was debugging someone else's poorly formatted code, but in doing so my attention is being distracted from the main point of the article and frankly I have a huge pile of other things to read that are potentially more rewarding.This is particularly jarring in Go when gofmt exists and is used almost universally (I think this is the first time I see non-gofmt'd code in quite a while).
I think we need to coin a new term - indent-nazi, style-nazi, or something similar - for the purpose of dismissing this kind of post and keeping people on topic.
GoSublime and go.vim both integrate gofmt into the editor; you start to miss it when refactoring, because you can just shrug and say "gofmt will clean it up when I save" when you move a block to a different function or indent level.
I agree with the grandparent -- seeing non-gofmt code is jarring and deliberately distracting. It's like someone writing an entire Python program with nothing but lambdas.
Normally this alone is not an issue, but using non-idiomatic code is a weak argument when trying to describe language readability differences.
However (not slating Go, which I think is excellent), I genuinely think Go is going to go the same way as plan9 eventually. Unfortunately, its predecessor (C) is good enough, much as UNIX was good enough compared to plan9.
These languages also had OS fully implemented on them, just with tiny bits of Assembly to do the very low level stuff, similar to what C would require anyway.
The only advantage of C is that its runtime is so small, that in practice the OS is the C's runtime.
The point you mention is only valid when using entirely static memory, which is a very rare case in real C code (only really used in a few small embedded codebases).
The correct answer would be: depends on the concrete implementation. There are implementations with real-time guarantees.
However, assuming standard desktop OS malloc()/free() the answer is: No. These functions can execute very quickly.. or very slowly, depending on their current internal state. But you can control when they get called, which can be an important difference.
>The point you mention is only valid when using entirely static memory, which is a very rare case in real C code (only really used in a few small embedded codebases).
Depends on what you mean by "entirely static memory". No malloc() calls at all? Yes, that is rare and pretty much limited to the embedded realm I think. Memory pools however are very common in performance critical code.
Thanks for pointing this out.
This is often a misunderstanding from manual memory management fans. In many cases malloc()/free() also behave non-deterministic.
This is the main reason why for special types of applications, you need to have malloc()/free() implementations specially targeted to the use case at hand.
This is no different from the GC runtimes, which are coded specifically for real time applications, like avionics, for example.
Anyway, take a look at the OCaml GC. It's simple (probably simpler than glibc's malloc) and very performant particularly if you understand how it works and use it intelligently in your app.
Default platform malloc(3) and free(3) can be a crap indeed, but they are drop-in replaceable with the above at any time, unlike Go GC - if practical testing suggests such replacement is necessary (e.g. Firefox, Facebook servers)
Exactly, and you can also do that in Go to avoid the GC.
Yes, but only because no major OS manufacturer picked them up as the main system language.
The only way a system language can become mainstream is if it is picked up by an OS vendor that makes it the default system language on their OS.
As for the bare level stuff you describe, real systems like Native Oberon proved this is possible. At ETHZ Native Oberon was used for almost everything an OS is used for.
Sadly no major vendor has got interested on the system, even after some industry attempts tried out by ETHZ.
Not really true, you have direct control over the memory layout of your data structures, and if you want to do really tricky stuff there is also the unsafe package.
Go cleans up and fixes pretty much every issue C had, and improves it in many non-obvious areas, from the syntax to the type system.
And when porting an existing project I'm not surprised if goroutines would come up that often given that they probably don't have any equivalent in the original design.
I suppose that begs the question: if you can built it in the language, should it really be a part of the implementation?
There are also other language features that make it much more usable and that are missing from C, like garbage collection.
I know Rob Pike and Russ Cox have discussed this several times, it might be worth watching this talk by rob about the history of Go's concurrency model you can find here: http://go-lang.cat-v.org/talks/
And Russ Cox's article also about this: http://swtch.com/~rsc/thread/
I'm not sure either covers exactly the reasons why it is a great advantage to make it part of the language, but they are still interesting background.
If we could get dynamic linking and something less cumbersome for interfacing with existing libs, I could use Go for Serious Work.
In the end, static linking is almost invariably superior to dynamic linking: simpler toolchain, simpler runtime, better reliability, better performance and better security, see:
http://harmful.cat-v.org/software/dynamic-linking/
That said, I think you can do dynamic linking with gccgo, and when linking to C libs with cgo, you do dynamic linking.
Really? Today we are very much blessed with quite a few large libraries - not just X but Qt on top of that and KDE on top of that. WebKit. ICU. These come out to dozens of megabytes. Static linking would add somewhat less by eliminating unused symbols, but you'd still end up with massive bloat for your GUI processes; maybe with today's disk and memory sizes and SSDs that's not the end of the world, but it would be a rather pointless performance drag. That's not counting the difference between Go and Plan 9: I count 4,000 odd binaries in my PATH; if they each had the 1 MB overhead of hello world in Go, I'd be out 4 GB, more than I pay for the entire set of libraries on my system (with some redundancy). (And I hope you don't mind waiting for your programs to compile; despite the Go compiler's vaunted speed, it actually takes over 4 times as long to build hello world as clang for the same in C, the vast majority of which is spent in the linker.)
Security? Today's security environment requires frequent patches to library code. If you have a system to automatically re-link all the programs that link against libraries with security updates, great (make sure you don't miss any, such as manually compiled or copied binaries); otherwise, your system is impossible to keep secure.
And with magnitude orders more RAM. And just because there are large libraries doesn't mean they are either necessary or desirable.
> not just X but Qt on top of that and KDE on top of that. WebKit. ICU. These come out to dozens of megabytes.
Interestingly most apps that depend on Qt, WebKit or ICU include their own copies of this libraries.
> Static linking would add somewhat less by eliminating unused symbols
Thanks for reminding me of another benefit of static linking which I forgot to mention.
> I count 4,000 odd binaries in my PATH
I'm a fan of many small tools working well together but I can't help but feel that when you have systems with 4,000 binaries in your PATH, something has gone terribly wrong.
Also, Go's current binaries are large not because they are statically linked but because there has been basically zero optimization of generated binary size. There is no reason why Go binaries couldn't be much smaller, other than so far it has not been a problem for anyone building systems in Go.
> Today's security environment requires frequent patches to library code.
Which is not helped by dynamic linking for reasons both of complexity (see http://harmful.cat-v.org/software/dynamic-linking/versioned-... ) and because most programs anyway use their own version of such 'shared' libs (update your system's ffmpeg and chrome will keep using its own copy). Dll-hell has security implications too.
In practice people end up doing things that either nullify the alleged benefits of dynamic linking, or simply using static linking (Google deploys statically linked binaries, sometimes multiple Gb in size to their servers).
> Interestingly most apps that depend on Qt, WebKit or ICU include their own copies of this libraries. So you're not a Linux user, ok. In that case there really are not that much shared libraries. Using a free desktop means that a large majority of all programs you use requires the same set of shared libraries. And as least in KDE and Gnome, there is a large number of small programs running in the background.
> I can't help but feel that when you have systems with 4,000 binaries in your PATH, something has gone terribly wrong. A quick "ls /usr/bin | wc -l" gives me 3135. Considering this is not the whole PATH, I think 4000 is a normal number.
In Linux distributions, programs don't have to ship their own versions of anything. Maybe you should try it.
Doesn't mean I want to waste it. Some systems don't really have much RAM to spare, such as the iPhone.
> And just because there are large libraries doesn't mean they are either necessary or desirable.
This is an old argument, but short of rewriting the world there isn't presently much alternative.
> Interestingly most apps that depend on Qt, WebKit or ICU include their own copies of this libraries.
Not sure which system you're talking about. As far as I know, Linux distros tend to link everything against system libraries. Here on OS X, Qt is usually bundled, but WebKit and ICU are part of the system and dynamically linked against. Independently distributed Linux programs are an exception and arguably a bad idea.
> I'm a fan of many small tools working well together but I can't help but feel that when you have systems with 4,000 binaries in your PATH, something has gone terribly wrong.
Most of it I don't use and thanks to MacPorts, I have a lot of duplicate copies of tools. (Maybe not the best system, but disks do have enough room to waste some.)
> There is no reason why Go binaries couldn't be much smaller, other than so far it has not been a problem for anyone building systems in Go.
Fair enough. It is a problem for me mainly because I value very fast compilation of small tools.
> Which is not helped by dynamic linking for reasons both of complexity (see http://harmful.cat-v.org/software/dynamic-linking/versioned-.... )
This does sound awful but I have not really seen it anywhere outside of libcs. OS X libc has only a few switches (UNIX2003, INODE64) and uses them to provide wide backwards compatibility.
> and because most programs anyway use their own version of such 'shared' libs (update your system's ffmpeg and chrome will keep using its own copy).
And indeed this can cause serious problems (I remember a vulnerability report or two about some program shipping an out-of-date library), but luckily you're exaggerating its prevalence. Chrome will keep doing its own thing, but when WebKit gets another of its innumerable security updates, I don't have to redownload the 32 applications I have that link against it.
(ffmpeg might be an exception because it doesn't care about stable releases, but I also remember a blog post complaining about Chrome's (former?) gratuitous forking and bundling of libraries. It's a bad idea.)
> Dll-hell has security implications too.
Only on poorly organized systems. On a Linux distro, the package manager takes care of dependencies and generally gets it right. OS X is uniform (and willing to break backwards compatibility) enough that when there are problems, the developers update their apps.
> In practice people end up doing things that either nullify the alleged benefits of dynamic linking,
in a small minority of cases, yes; in the vast majority of cases where, on a well-organized system, I just want this security or framework update to make it to everything, no.
> or simply using static linking (Google deploys statically linked binaries, sometimes multiple Gb in size to their servers).
Facebook also does the gigabyte binary thing. It's a ridiculous waste of space, but if they don't care, they don't care; servers don't have as many constraints as user-facing computers (they have a fixed workload and expected disk usage), and are often less vulnerable to library security issues, not having to expose the full web stack + PDF rendering + Flash + GL to to any random web site the user navigates to. :)
It's a royal pain writing go that talks to C code, compared to say, lua or python, and there just _isnt_ a way to make other languages pickup go libraries and run the symbols from them afaik...
For illustration, here's how I call the openproc() function from libproc:
import (
/*
#cgo LDFLAGS: -lproc
#include <proc/readproc.h>
PROCTAB* my_openproc(int flags) { return openproc(flags); }
*/
"C"
)
func parse_procs() {
proc := C.my_openproc(C.PROC_FILLUSR | C.PROC_FILLCOM | C.PROC_FILLSTAT)
...
}
This illustrates one issue I found with Cgo: calling functions with variable number of arguments is not supported. I had to define a new C function "my_openproc" with a fixed number of arguments, which you can see in the metadata of the import statement. It also includes the compiler and Cgo directives that make editing a Makefile unnecessary. The code for the whole tool is contained in one Go file.This is plain wrong, you can pretty much call C code directly, while in Python and the like you really have to write a wrapper.
Of course in Go you will write a wrapper anyway to give the library a more Go-like API, but I don't see how this could be any worse than in any other language.
> there just _isnt_ a way to make other languages pickup go libraries and run the symbols from them afaik...
To get non-Go code to call Go code is trickier (also Go really wants to run your main()), but can be done, and there are even libraries to write Python extensions in Go, see:
For instance Russ Cox did coroutines and channels in his C libtask in a few thousand lines of code. It's not pretty but it works. Include something like it behind an API as 'libgrt.o' with a few other features and the rest of the code transpiles cleanly.
...but say this existed. What would be the point of writing Google Go code? A more compiler-friendly syntax, less flexibility to make simple memory/pointer mistakes? Would that be enough or would you, with perfect C linkage, just end up writing most of the code in C and Lua? It certainly seem the effect of creating their own compiler (worse than gcc), an opaque "go" tool that does everything, project layout and hosting rules, complicated FFI, etc is to make a 'toolchain island' locking you into writing everything in Google Go, where you might not otherwise.
Yes, gcc now also compiles the language, but they still pimp their own compilers... iirc the "go" tool uses them by default (or maybe exclusively). Why create a new compiler? Why a project management tool that does everything except work with other build systems? Why isolate the language by making it difficult to use with others? I feel those are good questions to ask.
The key opportunity in the future is smart devices everywhere. Embedded, connected intellgence, everywhere. Everything is a communication device. Today your phone and your car; tomorrow: Your shoes, your office, the grocery store, your refrigerator. Think of xbox Kinect-type sensors embedded into everything.
Writing solid C code for all those systems will be too hard. We also definitely do not want an serendipitously-designed language (Javascript). Yes, that leaves Python Ruby and so on, which brings us full circle. Go will compete with those languages but not in the domains that are evident today. Not in web browser, and not in a new! improved! web server. It seems to me that Go is a forward-looking design, aimed to meet the challenges of the everything-connected world of tomorrow.
To make tomorrow happen, we need a better C. Go is that.
* You can turn off the GC.
* You can compile with gccgo.
* You can call assembly code from Go.
What is the major hindrance from using Go in embedded environments?In 10 years your sunglasses will have more compute power and memory than today's smartphone .
Looking at other systems such as Haiku shows that porting Go is encouraged, the only issues have to deal with assumptions in the build (in this case, I think /bin/env/bash is included everywhere, there's no global variable to change this definition from different OS types).
One day we may see a change in Go for different platforms, but I don't think it will prove to hinder that many people, only the niche groups. And for all intents and purposes, Go is built for practical application (!! Don't kill me !!), which systems programming on plan9 or haiku may not be considered "practical" at the moment.
EDIT: for clarity.
I think this is not longer a problem with the new build system that is part of Go 1.
Also AFAIK at least the Plan 9 port is almost complete, and is certainly functional.
Go is a replacement for Python, Ruby, etc. Garbage collection, duck typing, an excellent library. Go is a language with the same level of abstraction of many other "scripting" languages, but is unique because it uses static typing and is compiled.
You use the compiler toolchain in OS A, while generating executables to run on OS B.
With a bootstraping compiler, you can use this technique to bring a native compiler to new platforms.
This is not to say Go will not get there eventually, if the language gains popularity. Someone had to write or modify a compiler to target all those architectures for C, after all. This is just a reaction to what I see as assumptions tying operating systems to certain hardware architectures (in this and other discussions). Go can be used on a range of operating systems on two hardware architectures. Very good progress, but the language needs to get that second number up before we can seriously talk about it replacing C.
[0] Only had to perform well on two, fortunately.
Also, OpenBSD, NetBSD, and Plan 9 in the works.
Also there is gccgo, which AFAIK also works on Solaris and probably elsewhere.
I'd also like to add that the gc compilers support ARM as well as x86 and amd64 and are very, very easy to port to new platforms.
But the problem is, I've already tried haskell, which also fits that same area, and is semantically a vastly better language. I just wish go had been more willing to push the envelope and at least try to be somewhat modern and useful instead of being "C with modules, but slow". On the other hand, haskell is a terrible language syntactically, and from a development environment perspective. Go is near enough to perfect in those regards. Having a fast compiler, a simple, working build system, a sane and easily enforced code format all make a huge practical difference. I wish I could use go, as it is much nicer than haskell from a usability perspective. But the language is just too primitive.
[1] http://www.scala-lang.org/ [2] http://typesafe.com/stack
Scala ends up more like the worst aspects of haskell and go combined, rather than the best aspects of both.
When was the last time you used Scala and/or SBT? I know a lot of the tools in the Scala ecosystem were unstable prior to Scala 2.8. However, now they have become pretty good. Even the, previously notoriously bad, Eclipse plugin has become good.
From my perspective Scala solves a lot of problems with Haskell:
- Working module system (From my experience, especially people coming from OO languages are surprised that this is such a huge unsolved problem in Haskell, because all the languages they know have come up with a working solution.) It will be interesting if some OCaml-style module system as currently discussed makes it into Haskell.
- It is much easier to reason about space consumption.
- It benefits from the best general-purpose VM with its superior garbage collection algorithms. (I agree that the lack of VM features is deeply annoying.)
- Tons of tools for monitoring.
- Debuggers. I'm not certain that Haskell will ever have decent debugging capabilities, taking its approach to laziness and compilation into account.
- Exceptions which don't leave the developer wondering where exactly an error has occurred. (Stack-traces, anyone?)
- Libraries for basically everything. Even if you don't use them, you can have a look at how other developers have approached a certain problem.
- Tool support. The Scala IDE alone has 10 people working on it. Compare it to Leksah and EclipseFP.
- Commercial support. Scala has Typesafe (> 30 people) and dozens of partners, consultancies, etc. In Haskell, there is Well-Typed, which is more or less payed by the “Industrial Haskell Group” (which consists of Galois and Amgen).
- The REPL is just a lot more usable.
I don't have any problems with the compile time. When developing in Eclipse there is just no delay between pressing “Run” and the execution of the program. It is instantaneous.
Syntax ... well, that's a completely subjective topic.
“terrible dependency/package/module management” ... SBT delivers a top-notch experience here. Have dependencies as source on sites like GitHub? SBT will fetch and build them without problems. Need to deploy artifacts into the local repo, to Maven Central or other services? SBT will happily do that. Need to cross-compile to different versions? Easy. Want to build software for Android? SBT will compile, jar, proguard, dex and install it on your device in seconds. I would love to hear what you would like to see here!
“semantically an inferior language”: Well, I guess every language is inferior to Haskell. I appreciate the hard work done in Haskell to track side-effects and other things. While I don't think these exact approaches will ever see much adoption, it leads the way to more manageable approaches. I'm pretty sure computer science will come up with some great solution in the next decade and Haskell will play its part here.
“less powerful language”: Well, it depends on what you mean with “Haskell”. “Haskell” == the Haskell standard? Scala is a lot more powerful than that. “Haskell” == GHC with all its proprietary extensions enabled: Yes, probably.
I don't think Go is really comparable with Scala or Haskell. It feels a bit like it was designed in an ivory tower. It is certainly a nice language if you ignored the last 20 years of progress in language design and have never used anything except C.
Let me know what you think and if I missed something!
>Tool support. The Scala IDE alone has 10 people working on it. Compare it to Leksah and EclipseFP.
I don't think insulting the people working on the scala eclipse plugin is very productive. Yes they have more people, and yes it is annoying that it is still not as good as haskell's eclipse plugin, but give them some time.
>The REPL is just a lot more usable.
In what way? The fact that it is way slower? You seem to be just listing random things as if you've never tried haskell.
>SBT delivers a top-notch experience here
You are the first person I've ever seen make that claim. Hell, people use maven because SBT is so bad.
>I don't think Go is really comparable with Scala or Haskell. It feels a bit like it was designed in an ivory tower
You might want to look up what "ivory tower" means. That is the most backwards characterization of go I've ever seen.
Further, these examples are so trivial that one doesn't see an advantage over C and so this comment thread is like every other. Those who've written "Hello World" dismiss it as neither C nor Haskell and most others seem to be generally happy with it.
I disagree. I think any new language should be designed to best meet the kind of problem it's being created to deal with. Making it "beginner friendly" (whatever that means - I bet there are lots of different interpretations) is a nice extra, but should not come at the expense of solving the problems.
That makes no sense to me. In any industry with a sizeable number of workers, there is a huge range of tools, from the entry level easy-to-use up to the fantastically intricate and arcane. Tools that are not "beginner friendly" are that way for a reason.
As an example, assembly code is never going away; for the obvious reason that if nobody understands it, nobody can write compilers, and also because there are cases where knowing assembly is useful and helps to make better code, whether it's taking apart the code to really, truly get every last clock-cycle of power out of the thing, or to take apart code in the search for arcane bugs and wonderfully subtle interactions causing unexpected behaviour. Assembly is old, and will never go away, and is (for most meanings of the phrase) not beginner-friendly.
The only advantage to a language being "beginner friendly" is that beginners can learn it fast. What you then get are inexperienced programmers who know just enough to be dangerous (this is not an attack on them; it's the case in any industry with a low barrier to entry, and a stepping stone to being better). One expert, experienced programmer with knowledge of a "beginner unfriendly" language is worth literally dozens of first-day coders wielding their hand-holding, garbage-collecting, counting-begins-at-one modern version of BASIC. That is never going to change, and every first-day coder wants to become that expert.
Even if somehow all the non-"beginner friendly" languages died, the very next day someone who'd been coding in this "beginner friendly" language for a decade would finally get sick of it and start designing a language she can truly express herself in without having all the hand-holding that holds her back.
If you mean someone that is a programmer and hasn't used go before, I can tell you I went from "never having seen Go before" to "reasonably proficient" inside of two months. Further, my Go code is easier to read and maintain than anything I've done in other languages. (I came largely from Java, so maybe that's not saying much.)
I think that for beginners of either kind, the documentation and community support are just as important as the language itself. I mean, look at something like JavaScript, which is picked up by "beginners" all the time and is, frankly, obtuse as hell. Go has great docs and a really friendly and helpful community.
If you want to launch a career as a systems programmer, which is a fundamentally different goal, then yes, you should learn C, even if you end up using other things.
> smaller than most languages around
I'm not certain that this is specific to Go, insamuch as it's a property of nearly all young languages. After 1.0, language complexity can only ever increase. Even Python has followed this trajectory, although Python should perhaps be commended for being willing to shed some of its complexity along the way (depending on how you view backwards-incompatible changes, some would say it should be denounced rather than commended).