The same issue comes up in Common Lisp where you find a codebase with heavy use of macros which effectively build a DSL within the program. Working alone, this can be fun, and can produce elegant code, but it means anyone new to a project needs to first familiarize themselves with the world you've built.
When many people work on a project it helps if everyone speaks the Queen's English, as it were.
Still, generics would be nice.
That sounds like a deepity[1] if ever I've heard one.
Just to add something a little more substantive: It may not be obvious at first sight (esp. in e.g. C++ or Java), but 'generics'/'parametric polymorphism' can actually incredibly powerful at restricting what your program can do and thus actually restrict the set of valid programs which will still satisfy the type checker. This is used to great effect in e.g. ML or Haskell and can be used somewhat effectively in Java/Scala code with subtype bounds. Of course in Haskell, being a language from the 1990s[2], you can use this to effectively restrict the types of effects used by any given function (database I/O, arbitrary I/O, networking, etc.).
[1] https://en.wiktionary.org/wiki/deepity#English
[2] Ok, this is slightly exaggerated since monads-for-IO were discovered quite a bit after 1990, but still... parametric polymorphism is crucial for this use case.
Your code becomes less peculiar to you and more in line with the peculiarities of the language as it's used by most people.
Shallow enough? Don't let an allergy to postmodernism become an allergy to a turned phrase.
Not sure what the rest of your comment has to do with my point, which was about, if you like, the pragmatics of programming.
Not concerned with the space of programs that type check. Insufferable haskellers...
I'm objecting to the attempt at sloganization as if witty/clever phrases mean anything. FTR, I also think this is a bad thing in FP. My "favorite" example being "if it compiles, it works" (or similar).
> Not sure what the rest of your comment has to do with my point, which was about, if you like, the pragmatics of programming.
My point, though perhaps somewhat obscure, was that eliminating a lot (i.e. "classes") of bugs up front (e.g. by exploiting parametric polymorphism) means that you spend less time fixing bugs... which means that you spend more time getting things done.
(Now, the jury is still out on whether static type checking leads to more productivity than dynamic type checking, but given that you're interested in Go, I'm guessing you're probably leaning towards 'static' anyway.)
> Not concerned with the space of programs that type check. Insufferable haskellers...
I used Haskell (and ML, you'll notice) as an example, but if you're not concerned with the space of programs that type check -- why are you even using a statically checked language? Surely you'd be infinitely more productive in a dynamically checked language? I'm saying you should be concerned and demand concern from the designers of your language.
Perhaps this is changing, but my guess is the prior comment was by a person who appeals to Haskell more often than uses it.
Two points:
One, I'm not keeping an exact score of how often I mention Haskell vs. use it, but I can assure you that I use Haskell almost every single day.
Two, this constant anti-academia thing is really getting tiresome at this point... but just for the record: I've never worked in academia and didn't even encounter Haskell until I was out of university. My interest and praise for Haskell (and Ocaml) is entirely based on practical experience.
Idiomatic is only good if the idioms are good. Historically for lots of languages, and I would include Go there, the prevalent idioms were crap.
E.g. Java circa 2000-2007 and the J2EE factory-singleton-factory-proxy-singleton-XML crapfest.
Or PHP and the "devil may care" attitude of pre-Composer PHP codebases (including big ones like Wordpress).
Or the tons of broken ways of working with Javascript until the community regained some sanity in the last 5-6 years.
Go has its quirks, and many design decisions that I find dubious, but so does every language I've used. I'd still much rather tackle a new project in Go than Python or C++ or Java. It's efficient, it's got great tools and a fully-stocked standard library, a fast compiler, static type checking, type inference, and is extremely easy to read other's code because the language is so simple. There aren't a million ways to write cryptic code, unlike say Scala - which appeals to me more on paper but is a disaster to work with in comparison.
When it is not balanced by an expressive type system, it becomes a cop-out where anything goes,including creating adhoc types at runtime ( reflect.StructOf() , reflect.SliceOf() , ... ), because it's the only way to get a little bit of expressiveness of out that language.
Yet it is there in the language. Why is that? how do you justify adding this to a statically typed language?
Classic. All languages stink, somewhere. The classic programmer Dunning-Kruger mistake: evaluating one language without self-awareness of all of the (probably unconscious) cost/benefit optimizations that mostly apply to the other language. This is like Smalltalkers and C++ programmers in the 90's arguing about the design decisions that went into Java.
Your definition of "effectively broken" actually means "doesn't fit my preferences." I'd expect "effectively broken" to more usefully mean "basically, very few people want to use it in production." Smalltalk now fits that. (Mostly through bad business/marketing decisions and incompatibility with mainstream programming expectations.) I bet there's many, many languages you might even call "elegant" that fit that as well.
basically promotes C styles errors and bad macros through go gen.
Funny, but my experience is that Golang basically eliminates my dealing with those. I'm writing an MMO, and my debugging time in that category amounts to literally 2 minutes. (Basically, oh duh, that member function should take a pointer reference. Otherwise, it can't mutate state!)
When I say the language is broken, look at Go type system, then look at how Go reflection makes the language look a dynamically typed one.
If you're such a poor programmer, that you can't get about the same level of type safety around array code in a Golang environment, as say, in a C++ environment, then just find a different language. On the other hand, if you can show an increase in productivity doing it your way in some kind of A/B quantitative comparison on actual production level code, then go ahead and take that show on the road. Go to conferences, write papers, and get yourself a nice consulting business preaching your gospel, getting paid, and advancing the almost-a-field of programming. Otherwise, just stop making noise and trolling.
To be fair, there are some languages with pathologies that are publicly apparent, like PHP with webapp security and C with security exploits. There are problems with programming in the large with C++ -- some involving the very features you probably think are admirable. If you have experience with Golang in production, and you've tried mitigating the type-system weaknesses to get compile-time or test-time warnings out of the tooling, and this incurred your company some cost, then talk about that. Otherwise, you are just making worthless angry programmer noise devoid of grounding in actual practice.
No need for personal attacks.
> then just find a different language.
What a warm an welcoming community the Go community is /s
C++ doesn't have reflection, because it doesn't need it. But somehow Go needs it ? Reflection is a cop-out, especially in a language that has a simplistic type system. And don't get me started on struct tags. If you cant see the obvious issue with all these "features", in comparison of the lack of expressiveness of types AT COMPILE TIME then good for you.
While I miss them certainly, I strongly prefer them being absent to a bad and complex/confusing implementation.
Go has generics ... but only for the core team. Go has polymorphism (there are polymorphic functions, all of which BEHAVE differently in the type system), there are return type polymorphic functions (functions that behave differently depending on whether you assign their result to one or two variables).
One look at github will tell you exactly what the go way of handling errors does in practice : ignoring errors. Golang code is like C code: it makes it sooo easy to just ignore errors. Second thing: errors are so hard to localize, as they're not tagged with location or stack trace. So I often find myself looking for string errors, while in Java/C# in 99% of cases I know exactly where shit happened. In Go I know in 20% of cases or so.
Speed. Go manages to be slower than Java, except in startup. For a compiled language, that's an accomplishment.
Besides the reactions to Go seem rather typical: it's simple and very, very limiting. Operations people are beside themselves. Predictable (although the ignoring of errors, channels and difficult to localize errors plus a number of mistakes in the standard library detract from that more than a little bit). Programmers don't like it.
I wish the core error library behaved like that, and that the core language made it less verbose.
This is a typical thing in Go: the language is kept stable and backward compatibility is king. Solutions for some things are left to the community.
Other languages changed a lot over the years, getting better but frustrating people because of breaking changes. I believe this promise of stability paved the way for much of Go's success, despite many shortcomings
C++16 beta compilers can compile the very first C program just fine. How's that for backwards compatibility ? 44 years. In fact, this is exactly what's frequently blamed for C++'s complexity. Support lots of weird edge cases because "at some point it worked". Over 44 years (wtf C is old now).
Java - same. ML - same. C++ - same.
> I believe this promise of stability paved the way for much of Go's success, despite many shortcomings
Actually for most of it's 7 year life the exact opposite is true. Go regularly broke it's weird cases (I would say because getting a compiler without a sound type system working well is a road that is littered with mines). This is why "gofix" exists ( https://blog.golang.org/introducing-gofix ). Go's authors are crediting this with Go's "simpleness".
nitpick: a c++ compiler can compile C only if it knows that it's a C source. Not every valid C source is a valid C++ source:
char *foo = malloc(42);
this is legal in C, but not in C++. See https://en.wikipedia.org/wiki/Compatibility_of_C_and_C%2B%2B...C++ is 33 years old. Still impressive backward compatibility track.
I guess that backward compat is a good reason for why C/C++ is still widely adopted.
IIRC there are some minor things that have been removed from the standard, e.g. the export keyword, but apparently it wasn't widely adopted if at all.
> ... This is why "gofix" exists I was under the impression that this was a thing before Go 1.0.
If your code produces errors, you can of course add location information like stack traces, there is an API for that.
I have not benchmarked Go against Java explicitly, but I do benchmark against C and it compares very nicely in performance to C code, so for most tasks it should be as fast or faster than Java code. Go gives you more flexibility about memory layout (true value types), which keeps GC times down.
I am a programmer, with 20 years of Java on my belt and I quite love Go.
On average, Go code is about 50% as fast as C code in calculations and algorithms, usually, and has more lines of code for equivalent functionality without cheating. Do your benchmarks tell you something different ?
Java is about 10% slower than C. 30% or so if you "don't cheat" (meaning write a direct translation of C code into java, e.g. using char[] instead of string)
There's also that C encourages you to write faster code, at least it does for me. Java, Go, and every other language I know, encourage me to do string mangling by making lots of temporary strings. C doesn't really allow for that, instead making me think about doing in-place string editing, which is far, far faster than using copies. Of course, get the tiniest little detail wrong and it'll blow up, but there's no beating it in speed.
I have to say, I've had the "warm an welcoming /s" from the Go community myself. I'll give you a hint: You can also get the same from Smalltalk if you complain that a method can't have more than 256 temporary variables, and that this means Smalltalk isn't a real language. (How that demonstrates cluelessness is left as an exercise.) Annoying Dunning-Kruger crap that would only be clever and well informed if posted as a deliberate troll -- I leave that to you for what sort of welcome one should expect.
I'll also note that you are "copping out" by responding to exactly zero of my arguments and deflecting attention instead. Probably because you can't.
Reflection is a cop-out, especially in a language that has a simplistic type system.
Says who? This could just as well apply to Smalltalk. If you're pedantic about it, you could even say Smalltalk-80 is a strongly typed compiled language. Reflection is just another tool that has trade-offs and potential problems like any number of programming language tools. And if you said it was a language design "smell" you'd be right. But to a dedicated practitioner, no programming language is free of those.
How would you describe RTTI?
If you don't, you'll never be able to find the name of the type, whether it has a member named "Bar", what the type of that member is, whether it can be set, whether Foo has a method named "Baz", what its argument types are, etc.
Even if you do know Foo is a type, the programmer has to do most of that stuff. For example, one cannot write a function that prints all fields of an object passed to it without specifying its concrete type. Add a field, and you have to adjust that function.
The only thing you can reliably do is determine whether Foo implements a given interface (= abstract base class) but again, that's only if you know that interface exists. You cannot determine the name of a superclass or the depth of an object's class hierarchy, for instance.
Which, as information is content-less.
All languages might stink "somewhere", but there are absolutely better and worse languages, and it's not just a matter of different tradeoffs.
You can give 10 language writers a set of the same tradeoffs to strive for, even hand them in order: it doesn't mean that the 10 resulting languages will be of the same quality.
Whatever. Just because the language is effectively broken doesn't make practices in other languages irrelevant. And it's funny when you talk about the "old" ways of thinking in language that basically promotes C styles errors and bad macros through go gen.
When I say the language is broken, look at Go type system, then look at how Go reflection makes the language look a dynamically typed one. It would have been smarter to tone down the reflection and make it unnecessary with a smarter type system. If it is there then it is because it was necessary for Go designers. If it had not been, then Go would not need that insane reflection.
Now Go back to your Go code and remember all tricks you need to learn when working with arrays :
https://github.com/golang/go/wiki/SliceTricks
Just because :
> A weakness of Go is that any generic-type operations must be provided by the run-time
https://blog.golang.org/slices
Now what was your point about the "old" ways of thinking again ?