Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Well I'm the guy who runs that particular blog, and I can tell you I'm no marketing guru. While Reinaldo and I edited the post together, I'm pretty sure that the line was in his original text. (Just checked: it was.)

Maybe people keep saying Go feels like an interpreted language because it feels like an interpreted language? :-)



I've done a fair bit of Go programming (https://github.com/jbarham), but have programmed professionally mostly in Python for the past 10 years, and for me Go does feel an interpreted language because it requires so few type declarations compared to mainstream statically typed languages like C++ or Java.

Checking the app source code for the article at http://code.google.com/p/go-thanksgiving/source/browse/app/a..., the only type declaration I can see in the body of a function is in a type switch where it obviously makes sense. Otherwise the code uses the combined declaration and assignment := operator (http://golang.org/doc/go_spec.html#Short_variable_declaratio...) which is type-safe because it infers the types from the value(s) on the right hand side. IMO this is even better than working w/ a dynamically typed language like Python because the required parameter type declarations in the function declaration tell you the types you're dealing with, but unlike C++ or Java you don't have to repeat that information back to the compiler.


C++11 has support for inferring types; http://en.wikipedia.org/wiki/C%2B%2B11#Type_inference.


I see that claim everywhere as well, and I don't understand it. Does it just mean "it has a type system that you won't hate"? There are still plenty of type declarations in that code, whereas if you ported it to OCaml they'd all be inferred.


Yes, basically. As far as I can tell Go is entirely about getting rid of unnecessary cruft and boilerplate and making a practical language you won't hate working in. Inasmuch as most interpreted languages are intended to be practical languages you won't hate working in, they are similar to Go.

As far as the actual type system, the reason they feel similar is probably because interpreted languages tend to be duck-typed, and so is Go. When you code in an interpreted languages you expect arguments to functions to be of a certain type, where type just means "responds appropriately to methods I call on it". In Go, interfaces are just method specifications and any type that has appropriate methods satisfies the interface. For example, you might have an argument "input" of type "io.Reader"[1] to a function. All this really means is that you expect to be able to call "input.Read()" to populate a byte slice. As a result the implicit type guarantees you expect from an interpreted language and the explicit type guarantees you get from Go are basically the same.

[1] http://golang.org/pkg/io/#Reader


> As far as the actual type system, the reason they feel similar is probably because interpreted languages tend to be duck-typed, and so is Go. When you code in an interpreted languages you expect arguments to functions to be of a certain type, where type just means "responds appropriately to methods I call on it".

The person you respond to talked about OCaml. From this I infer he at least has some basic knowledge of OCaml. You don't seem to have any.

Here's a hint: OCaml's object types are structurally typed (and OCaml can actually infer types).

Your whole second paragraph is unnecessary (and unwarrantedly condescending), and the first one is basically a lie (Go is chock-full of special syntax and cases, and Go code is full of cruft).


> Your whole second paragraph is unnecessary (and unwarrantedly condescending)

Your whole post is unnecessary and unwarrantedly condescending since all you do is state "truths" like:

> Go is chock-full of special syntax and cases, and Go code is full of cruft

just like that, out of thin air.


> just like that, out of thin air.

Oh I can expand on that if you want, though I expect you don't and you'll just handwave it away as is usually done of criticisms of Go.

* Go uses a special syntax for multiple return values, this is a restriction on the more general concept of tuples. Go could simply provide tuples instead of having MRVs be a syntactic special case. This makes the language smaller and simpler: instead of `,` being a magical syntactic feature of the language, it's just an operator for building tuples.

* Go has generic types, but only for blessed types implemented directly in the interpreter (map and channel, for instance). All user-defined types are second-class citizens at best. That's elevating special syntax to new heights.

* Go has two different initializers in `new` and `make`, `new` is garbage as it only allocates and can't be used to initialize and `make` only works with (again) a restricted number of types living directly in the runtime, which get to have special treatment for the only reason that new is insufficient.

* Talking about things only builtin types get, only builtin types get to be indexed via an operator, this is special syntax dedicated solely to builtin types.

* `defer` and `go`. They feature special magical evaluation order (they have to be a complete expression, all inner expressions are evaluated immediately and the outer one and that one only is not evaluated) which leads to weirdness like creating an anonymous function and calling it immediately, and they're not actually needed due to Go having anonymous function in the first place, both could be builtin function taking a callable instead of being special forms and they'd work just as well (better in fact, since their evaluation model would be the same as everywhere else in the language). These special cases are even weirder when you realize that `recover`, which needs to hook deep into the interpreter and do actual strange stuff to stop the stack unwinding in place, is a builtin function rather than a special form.

That should be a good start, 4 clear-cut examples of special syntax (either unnecessary or which could/should be general) and one of a special case.


Here's some kneejerk devil's-advocate responses to some of your points. As an idealist I generally agree with you, but I can see practical arguments against many of your nitpicks:

* Having first-class multiple-return as part of the specification allows compilers to generate stack/register allocated return values. If the comma operator were a tuple-constructor, then every multivariate return would be a heap-allocated structure, which might have significant performance implications. (I don't know if the Go compiler actually takes advantage of this on any architectures, but the possibility is there.)

* Agreed. Go's way is perhaps simpler, but definitely limiting.

* Here I think Go does things entirely wrong. I actually like that `new` only allocates, because it lends itself to designing very minimalistic and elegant data structures, something that I feel gets out of hand in many large programs in other languages. Being a GC'ed language, I'm OK with the idea of just exporting and documenting some static initialization functions along with the type. But that begs the question of why `make` exists, since it is basically a first-class syntax feature for initialization of the magic builtins that need it. Consistency, please.

* This is pretty silly, I agree.

* I can see definite reasons why the evaluation order of `defer` and `go` should be as they are. Here's an example use case: I want to defer a statement to print the current value of a local variable. If defer took a callable, then the only way I can see to do that with Go's current syntax would be to (1) define a function that closes around my variable and returns (2) an anonymous function that calls fmt.Print(myvar), and (3) evaluate the original function with the local I want to close around. If you allow more syntax alterations, I suppose you could properly generalize to something like C++11's lambdas where you explicitly state those variables that you want in the closure so that you only need to write one anonymous function, but that is complicated as all hell. The 90% use-case here is `defer Close(abc)`, so even needing the syntax for one anonymous function feels more crufty than the occasional `defer func() { ... }()`. I much prefer Go's way of just saying "We will close around all of the parameters to the outermost function" because it is wayyyyyy simpler.


The problem with "it feels like a dynamic language" meaning "you probably won't hate it" is that it's somewhat insulting to existing statically-typed languages that are actually pleasant. It sounds all right if you've only ever been exposed to Java or C, but it's not like Go is the first language to have a good type system. It's especially odd considering Go's inference isn't able to handle all the types in even such a short sample.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: