Fri, Nov. 13th, 2009, 10:08 pm

Comments on Go Here are my preliminary thoughts on the Go programming language.



The most interesting feature for me personally is the built-in threading. Aside from its superb support for multi-core, it's just plain a good set of ways of doing networking. The lack of a decent built-in networking library (and generally coordination library) in Python has been a thorn in my side just about forever. In particular the promotion of queues to being one of the few built-in primitives with their own special syntax encourages good threading practice and is clearly warranted. Even such a simple command as 'wait until either the UI thread or the networking thread comes up with something' is a source of ongoing pain in most languages, but is built into Go as a core concept using select.



Go seems to finally get the static typing problem solved. Its := operator is a reasonable middle point between C++'s ludicrous verbosity and ML's excessive magic. Types being structural is also a huge win. There's no end of stupid architectural haggling over what module a base type sits in and who owns it, and the answer 'nowhere' completely gets rid of that problem. It seems to me that there are deep subtle problems with such declarations - for example, how does it statically check that the parameters accepted by methods of a type you're receiving are compatible with what you want to pass them? But maybe I just haven't thought about it enough. It's too bad that Go doesn't currently have generics. I for one won't start any new project in it until it reaches that level of maturity.



Go's lack of exception handling is a real problem, and another thing I'm blocking on to do real development in it. My own preferred method for adding it would be that if you call a function which has multiple return values and you don't handle one of them, it defaults to shorting to the same return of the caller, although some people might complain about that being too much like Java's 'throws'. That said, I've gotten so used to debugging by stack trace that I'd be loathe to not have stack building built into the language in some form, and in fact I've gotten really attached to a tricked out logging tool I wrote which can decorate any object and automatically logs a full stack trace of every assignment which is made to the object and allows you to print them all out at once. But perhaps such trickery is really the domain of highly dynamic languages, and not appropriate for something as low level and performance oriented as Go.



The primitives in Go are quite good. All languages should have special maps and lists built in. I think it actually doesn't go far enough with giving them special status, and should have Python-style special syntax for maps. The curly brackets could be freed up by simply eliminating their current usage and making formatting have syntax. It's more than a little bit absurd that the language designers themselves have a setup where a utility standardizes the formatting of their own code every time they commit, but they still maintain the nominal free-form nature of the language. Really guys, I know you were traumatized by Fortran's original awful enforced formatting, but that was a long time ago and it's time to let go.



That said, the primitives are given too much special status in other ways - they're the only things which have type parameterization, making it impossible to even implement their interfaces yourself, and worse, they're the only things which are call by reference. The call by reference thing worries me a lot. I really, really don't want Go to become the reference/pointer mix hell which C++ has become, but it's already headed in that direction. It really shouldn't matter that much - things which are passed are either an address or a copy, and the reference/pointer distinction really just has to do with what's the default (okay, so typically references don't let you overwrite either, but that's not a fundamental property). I for one strongly prefer the default be an address, and clearly when push comes to shove Go's designers do too, but more important than which way it is is that it should be consistent. Already transitioning to something consistent might require rewriting huge amounts of code, and it's getting worse, so fixing this problem might have to happen soon or never, and I'm afraid that it might already be never.



Go's speed of compilation is very nice, although I'm afraid I view that not so much as a strength of Go but as an awfulness of C++. Why C++ continues to take forever to compile even on machines many orders of magnitude faster than the first ones I ever used it on has long been a mystery to me. I hope the answer is simply that it's a language which wasn't designed with ease of parsing in mind, and has a whole layer of preprocessing on top of it which is horribly abused.



It's interesting that Go is going the garbage-collected route. If such a low-level language as Go can get away with that (and, truth be known, their preferred garbage collector isn't really integrated yet, so it's a little early to call it) then we may never see another non-garbage-collected language ever again.



I despise the use of initial capital letters to specify that something is public. Maybe if I used it for a while I'd learn to not hate it, but for now I hate it. Does chinese even have uppercase?



It's entirely possible that after using Go for a while something else would really start to gnaw at me about it, but it generally has a good smell, so hopefully not.



If you've read this far, you should Here are my preliminary thoughts on the Go programming language.The most interesting feature for me personally is the built-in threading. Aside from its superb support for multi-core, it's just plain a good set of ways of doing networking. The lack of a decent built-in networking library (and generally coordination library) in Python has been a thorn in my side just about forever. In particular the promotion of queues to being one of the few built-in primitives with their own special syntax encourages good threading practice and is clearly warranted. Even such a simple command as 'wait until either the UI thread or the networking thread comes up with something' is a source of ongoing pain in most languages, but is built into Go as a core concept using select.Go seems to finally get the static typing problem solved. Its := operator is a reasonable middle point between C++'s ludicrous verbosity and ML's excessive magic. Types being structural is also a huge win. There's no end of stupid architectural haggling over what module a base type sits in and who owns it, and the answer 'nowhere' completely gets rid of that problem. It seems to me that there are deep subtle problems with such declarations - for example, how does it statically check that the parameters accepted by methods of a type you're receiving are compatible with what you want to pass them? But maybe I just haven't thought about it enough. It's too bad that Go doesn't currently have generics. I for one won't start any new project in it until it reaches that level of maturity.Go's lack of exception handling is a real problem, and another thing I'm blocking on to do real development in it. My own preferred method for adding it would be that if you call a function which has multiple return values and you don't handle one of them, it defaults to shorting to the same return of the caller, although some people might complain about that being too much like Java's 'throws'. That said, I've gotten so used to debugging by stack trace that I'd be loathe to not have stack building built into the language in some form, and in fact I've gotten really attached to a tricked out logging tool I wrote which can decorate any object and automatically logs a full stack trace of every assignment which is made to the object and allows you to print them all out at once. But perhaps such trickery is really the domain of highly dynamic languages, and not appropriate for something as low level and performance oriented as Go.The primitives in Go are quite good. All languages should have special maps and lists built in. I think it actually doesn't go far enough with giving them special status, and should have Python-style special syntax for maps. The curly brackets could be freed up by simply eliminating their current usage and making formatting have syntax. It's more than a little bit absurd that the language designers themselves have a setup where a utility standardizes the formatting of their own code every time they commit, but they still maintain the nominal free-form nature of the language. Really guys, I know you were traumatized by Fortran's original awful enforced formatting, but that was a long time ago and it's time to let go.That said, the primitives are given too much special status in other ways - they're the only things which have type parameterization, making it impossible to even implement their interfaces yourself, and worse, they're the only things which are call by reference. The call by reference thing worries me a lot. I really, really don't want Go to become the reference/pointer mix hell which C++ has become, but it's already headed in that direction. It really shouldn't matter that much - things which are passed are either an address or a copy, and the reference/pointer distinction really just has to do with what's the default (okay, so typically references don't let you overwrite either, but that's not a fundamental property). I for one strongly prefer the default be an address, and clearly when push comes to shove Go's designers do too, but more important than which way it is is that it should be consistent. Already transitioning to something consistent might require rewriting huge amounts of code, and it's getting worse, so fixing this problem might have to happen soon or never, and I'm afraid that it might already be never.Go's speed of compilation is very nice, although I'm afraid I view that not so much as a strength of Go but as an awfulness of C++. Why C++ continues to take forever to compile even on machines many orders of magnitude faster than the first ones I ever used it on has long been a mystery to me. I hope the answer is simply that it's a language which wasn't designed with ease of parsing in mind, and has a whole layer of preprocessing on top of it which is horribly abused.It's interesting that Go is going the garbage-collected route. If such a low-level language as Go can get away with that (and, truth be known, their preferred garbage collector isn't really integrated yet, so it's a little early to call it) then we may never see another non-garbage-collected language ever again.I despise the use of initial capital letters to specify that something is public. Maybe if I used it for a while I'd learn to not hate it, but for now I hate it. Does chinese even have uppercase?It's entirely possible that after using Go for a while something else would really start to gnaw at me about it, but it generally has a good smell, so hopefully not.If you've read this far, you should follow me on Twitter Sat, Nov. 14th, 2009 03:36 pm (UTC)

toddmarshall what does Go compile into byte codes or machine code? You're complaining about C++ taking time to compile and link? That's hard to believe. It's all file processing (and re processing and linking) so use 'precompiled headers' and a fast disk. It does alot of optimization AND compile time correctness checking to get to machine code. Also, wasn't it Dijkstra who said you shouldn't even need a debugger, you should write your code such that it's obvious what the bug is when it runs. A good goal if nearly impossible in practice. like attaining infinity, always worthwhile the effort. what does Go compile into byte codes or machine code? You're complaining about C++ taking time to compile and link? That's hard to believe. It's all file processing (and re processing and linking) so use 'precompiled headers' and a fast disk. It does alot of optimization AND compile time correctness checking to get to machine code. Also, wasn't it Dijkstra who said you shouldn't even need a debugger, you should write your code such that it's obvious what the bug is when it runs. A good goal if nearly impossible in practice. like attaining infinity, always worthwhile the effort. Sat, Nov. 14th, 2009 05:24 pm (UTC)

misterajc Didn't Dijkstra suggest in "A Discipline of Programming" that each program should come with a mathematical proof of it's correctness so that it was by definition bug free? Of course, one would need a meta proof (or at least publication in a peer reviewed journal) to prove the correctness of the proof.



One of my standard interview questions is, "What is your approach to debugging?" I'm expecting something like, "First I reproduce the problem in a test environment, and then I run the debugger or add debugging code to identify the exact place where the error is introduced." Extra points if the person says, "First I log it in a bug tracking system." No points at all if the candidates claims to write bug free code. Didn't Dijkstra suggest in "A Discipline of Programming" that each program should come with a mathematical proof of it's correctness so that it was by definition bug free? Of course, one would need a meta proof (or at least publication in a peer reviewed journal) to prove the correctness of the proof.One of my standard interview questions is, "What is your approach to debugging?" I'm expecting something like, "First I reproduce the problem in a test environment, and then I run the debugger or add debugging code to identify the exact place where the error is introduced." Extra points if the person says, "First I log it in a bug tracking system." No points at all if the candidates claims to write bug free code. Sat, Nov. 14th, 2009 06:16 pm (UTC)

dizietsma Extra points for logging first and tackling second? Wow, I'm glad I don't work as a bug dispatcher at your company. Extra points for logging first and tackling second? Wow, I'm glad I don't work as a bug dispatcher at your company. Sat, Nov. 14th, 2009 07:26 pm (UTC)

darius Agreed about initial capitals. Oberon did it by prepending a * to the name in the declaration instead.



Not sure what you mean by ML's excessive magic. Isn't := just like let in ML, except for meaning an assignment instead of a new binding if there happens to be one in scope already for the same variable -- which is more magic than 'let'? (I wonder if := might need the value restriction like 'let' does since Go has a few parameterized types built in. I haven't really looked into Go yet.)



I guess you just mean they don't also have type inference for func definitions -- fair enough. Agreed about initial capitals. Oberon did it by prepending a * to the name in the declaration instead.Not sure what you mean by ML's excessive magic. Isn't := just like let in ML, except for meaning an assignment instead of a new binding if there happens to be one in scope already for the same variable -- which is more magic than 'let'? (I wonder if := might need the value restriction like 'let' does since Go has a few parameterized types built in. I haven't really looked into Go yet.)I guess you just mean they don't also have type inference for func definitions -- fair enough. Mon, Nov. 16th, 2009 04:46 am (UTC)

uke No, Chinese doesn't have uppercase. Except sort of for numbers, where there is an alternate and intentionally more complex way to write them intended to prevent fraud and errors in accounting and banking matters. No, Chinese doesn't have uppercase. Except sort of for numbers, where there is an alternate and intentionally more complex way to write them intended to prevent fraud and errors in accounting and banking matters. Mon, Nov. 30th, 2009 01:48 pm (UTC)

peter_geoghegan The reason that C++ takes so long to compile is because it allows you to instantiate classes on the stack (as against instantiating a mere pointer to the class) - the size of the class must be known at compile time, so you must give the compiler the classes' definition, as well as any class definitions on which the class is dependent on in turn, and so on. C++ programmers endevaour to minimise compilation dependencies, by the use of declarations when a full definition is unneeded (such as when you just have a pointer to the class, or are just passing it as a parameter to a function that is defined elsewhere). There is actually an idiom called "pimpl" or "chesire cat" which entails creating a facade, forwarding class that just has the public interface of the implementation, to which it is the only client - this is something I'd only use in extreme cases though. Slow compile times are a weakness of C++, to be sure.



Have you developed in C++ (as against just compiling a C++ program)? Typically, you have a debug build without compiler optimisations, which tends to speed things up considerably, especially if you're using GCC.



I don't know about Chinese, but Hebrew doesn't have uppercase or lowercase.



I'm not sure why the whole reference/pointer thing causes confusion/annoyance; references are just safer alternatives to pointers, in that they must be initialised (cannot be NULL or wild), and cannot change that which they refer to - they're an "alternative name" for the variable, not a distinct thing - they have the same memory address as the original, referenced variable (at least ostensibly). They exist to facilitate easy passing by reference to functions (no need to use pointer semantics), and to faciliate operator overloading (no need to de-reference a pointer returned by an operator, defeating the point of overloading - exploiting client's intuition about what the operator ought to mean).

Thu, Apr. 1st, 2010 03:07 pm (UTC)

romanticboy That's one of the main selling points of the D language. The ease of implementing compilers. That's one of the main selling points of the D language. The ease of implementing compilers.