It's not very like Java at all. The only OO-like feature it has is interfaces, which are more like Haskell's type classes combined with existential types than anything else. (The resemblance here is actually very close, implementation-wise: roughly, vtables at the per-instance level rather than per-class level).
The other semi-interesting things it has are (a) channels + parallel functions and (b) the return of error codes for error handling.
Java things it doesn't have start with reflection, bytecode (CPU independence), dynamic runtime code generation, inheritance hierarchies, generics, "everything is an object", array covariance, exceptions as an idiomatic error propagation scheme, scoping based on nested namespaces, no code outside of classes, nested types with scoping to match, inner classes with implicit outer class self pointer, only value parameter semantics, and only reference user-defined types.
In fact most of what makes Java distinct from the subset it shares with C is missing, except for a garbage collector.
It's not very like Java at all. The only OO-like feature it has is interfaces, which are more like Haskell's type classes combined with existential types than anything else.
That's a bit disingenuous, since Haskell typeclasses go hand in hand with parametric polymorphism, which Go doesn't offer.
Typeclasses plus existential types allow you to implement subtype polymorphism. But it is generally frowned upon in the Haskell community and certainly not widely used.
Disregarding implementation, if you drag in typeclasses + existential types, Java's interfaces are also comparable (yeah, they don't offer compile-time duck typing, but neither does Haskell).
Java classes have to be declared to implement an interface. Haskell types don't need to be declared to "implement" a typeclass, since the typeclass instance is declared separately. You don't need to modify the original definition in order to package up a value + functions into an existential; to me, that's the essential advantage of duck typing for larger projects, where you don't have the ability to freely modify any and all source included.
Java classes have to be declared to implement an interface. Haskell types don't need to be declared to "implement" a typeclass, since the typeclass instance is declared separately.
Let's be more specific: instances should be declared with the class or with the data type. Orphaned instances (that go with neither) are discouraged and with good reason - instances cannot be imported explicitly [1]. It is all to easy to have two conflicting instances if people start defining instances apart from the type class or data type. Don't do that! Luckily, -Wall will complain loudly about orphaned instances.
where you don't have the ability to freely modify any and all source included
Given the above, this is not really true in Haskell. Since orphaned instances are bad, people often wrap a data type using newtype and define the instances with that type. Of course, this is not so much different from creating a wrapper class in Java with another superclass or interface. Except that defining new types in Haskell comes with far less ceremony ;).
Duck typing is an exercise in ceremony reduction, ideally to the point of no ceremony at all. We can always add another layer of indirection to act as a proxy whatever language we choose. Java and similar OO languages make it harder, duck typing is the easiest it gets. Everything else is on a continuum.
FWIW, I was more interested in the implementation details of existential types, and how similar it is to Go (except that Go does it dynamically using reflection, last time I checked). You know more about Haskell and its idioms than I do, I just know about the features and make inferences from how they may be combined :)
I don't mean it's like Java in terms of particular language features, but in terms of "feel" and philosophy. It uses abstractions on the same level as Java (higher than C, lower than Clojure), designed as a blue-collar language, emphasizes readability (at the expense of verbosity), and generally avoids low-level bit-diddling as well as high-level meta-programming tricks.
What? Being a blue-collar language is a virtue! C#, Java, Python, Javascript etc. are all pretty much blue-collar languages; Haskell, Scala, C++ (depends), Rust (probably; I don't know much about it) and Clojure (sadly), aren't.
But you're right: "white-collar" languages have the habit of never being too popular.
If "blue collar" means "used in industry for real work", and "white collar" means "a research/niche language", Rust is designed to be blue collar. It's not designed to be a testbed for research beyond what was needed to get safety out of zero-cost abstractions.
Let me revise my previous comment. While many might categorize Python, Javascript and Ruby as blue-collar languages, they do encourage all sorts of metaprogramming tricks, while Java, C# and Go absolutely don't. I think this is a big philosophical distinction, because the second group favors readability and the ability to share code in a large team over language power, and this is what makes Go much closer to Java/C# in its philosophy than to Python et al.
the second group favors readability and the ability to share code in a large team over language power
Not to pick on you, but people say this all the time, as in it's probably the thing people say most often on this subject, and I wonder: do we have any evidence for it? That is, do we have any evidence that the mid-tier languages which eschew more powerful abstractions (Java and its peers) lead to either more readable or more shareable code? Or is it one of those things that everybody "knows" but ain't so?
Well, I can't claim that that's the case, only that those languages' designers think it is. There are some things we do know, if only anecdotally (maybe there's been some research on the subject – I don't know). We do know that C++ was a real boon when it first garnered wide appeal, but that very quickly large teams began to curtail the use of some of its more advanced features because of that reason. We also know that people have been writing much larger projects in Java (and possibly C#) than in any other language in history, certainly relative to the effort invested (there might have been larger C++ projects). Some of it just seems intuitive (though may not be the actual case). The problem is that it's hard to gather data because the languages adopting this view are the ones that are most popular, which helps them get selected for large projects to begin with. But we might have more data soon. I think JavaScript is the first "magic encouraged" language that will be used in multi MLOC projects. Ruby is more "magical" but doesn't seem to be favored by large teams working on large projects. So we might know more soon.
Personally, though, I think that's the wrong issue. Whatever extra productivity is gained by language magic, we're not talking orders of magnitude here. Usually it's mostly about developer enjoyment, lack of annoying boilerplate etc.. These are annoying issues, but not critical ones. I think the most crucial issue is state management, which can have an order-of-magnitude difference for some projects, as well as a significant effect on performance and scaling.
Most everything you're talking about is explicable by popularity effects. That's why more objective study would be interesting. Alas, I doubt it will happen: serious research on software engineering, as opposed to the thin broth we have now, would require at least an order of magnitude more funding, and no one's likely to provide that.
I'm not sure I like your distinction between developer enjoyment, lack of boilerplate, and state management. To me those things all have to do with good design.
Blue collar worker just usually means "one who is uneducated and unskilled". Putting that onto languages is sort of demeaning... it sounds like that's not really what you meant, though, and that's cool, just my misunderstanding of your meaning.
That's just how James Gosling described Java when he explained the philosophy behind it in 1997[1]. He wrote, "Java is a blue collar language. It’s not PhD thesis material but a language for a job. Java feels very familiar to many different programmers because I had a very strong tendency to prefer things that had been used a lot over things that just sounded like a good idea." He most certainly didn't intend the term to be demeaning, but more to contrast it with research languages that include features that are untried and unproven. The term has since been used as shorthand for Java's (and languages like it) goals and philosophy.
Uneducated I'll give you, though probably it should be qualified by something like formally educated, but blue collar certainly does not mean unskilled.
The paradigmatic blue collar job to my mind is not taking orders at McDonalds, it's welding.
I knew I should have qualified that more. You're right, McDonald's is not blue collar, but working in a manufacturing plant riveting part A to part B is. It also encompasses stuff like mechanics and welders that do require skill and even some education and certification.
But regardless, most of the time it's still used to mean something lesser.
Not sure if I'm reading your response incorrectly... but go has reflection. I'm not sure what you mean by scoping based on nested namespaces.... Go has similar scoping to pretty much every other modern language. Are you saying java has no code outside of classes? Because Go has that (and doesn't have classes).
Also... Go has OO features. You can make an object-like thing by tying data (a struct) with behavior (methods tied to the struct). It doesn't have inheritance which is not the same as not having OO features.
Yeah, I figured I was misunderstanding you. It seems like you were giving a list, half of which was stuff Go didn't have and half of which java didn't have.... anyway, no big deal, just trying to clarify.
The other semi-interesting things it has are (a) channels + parallel functions and (b) the return of error codes for error handling.
Java things it doesn't have start with reflection, bytecode (CPU independence), dynamic runtime code generation, inheritance hierarchies, generics, "everything is an object", array covariance, exceptions as an idiomatic error propagation scheme, scoping based on nested namespaces, no code outside of classes, nested types with scoping to match, inner classes with implicit outer class self pointer, only value parameter semantics, and only reference user-defined types.
In fact most of what makes Java distinct from the subset it shares with C is missing, except for a garbage collector.