Jesus, are people really this excited about features that existed for at least 15 years in other languages?
This one language for everything mentality is ushering in a huge NIH cycle.
Jesus, are people really this excited about features that existed for at least 15 years in other languages?
This one language for everything mentality is ushering in a huge NIH cycle.
Pretty sure they know a thing or two about "real threading".
And data structures in Go, that's just plain painful.
People were exited about the fresh compromise-less nature of the C++ standard library in the 80s, even in the 90s. About the fresh no-compromise approach of the java ones at the end of the 90s, and again right after java introduced generics.
Go is no different. It's standard library is not that far from the cruft-level of the python standard library, and the next language change (which they absolutely need : generics) will bring it to the level of the java standard library, due to the need for backward compatibility with pre-generics go programs.
Come on people, I realize at 16 I too thought that language X is forever (C++ in my case, on the plus side: it fared better than most. Some people, mostly the academics later switching to java, actually picked modula-2/oberon, which is/are a lot like Go. A lot went for visual basic, object pascal, and some for objective-C). But we're not 16 anymore ...
When it comes to 15+ year old languages, I'd actually say C++ is the most cruft-free easily usable language. Depends, a lot, on what libraries you use though.
Static types - of the worst kind that get in the way of creating any significant abstractions (no parametric polymorphism or generics) and don't provide much safety (no nil safety). For a new modern language, this is just weird.
Well integrated multithreading - yes. 40-year-old error handling strategy: also yes.
Haskell, Scala, F#, C# are all much better choices that I think fulfill all your criteria (Well, one might argue that functional languages are obscure, but that's increasingly not the case these days)
I find the popularity of Go rather depressing. If Go becomes the next Java, the inventors of C would set the programming world decades back in the past for the second time.
I was just going to disagree about C# being old. Then I checked the year... Now I'm sad, because 2000 came quite a long time ago.
That quote succinctly captures the essence of the problem with Go: it's warmed-over hash.
When you asked for exceptions you actually wanted an Either type, which means the function either return a result or an error (not both).
You also want something that propagates errors automatically (the monadic bind) in case you don't want to check every result.
An Either type lets you get the best of both worlds. It lets you model exactly whether an error can or cannot happen (unlike exceptions that are not optional). It lets you check every return value directly via pattern matching (similarly to Go) but also, the compiler will warn you if you "forget" to handle the error case. Finally, the bind operator lets you chain operations in a way that only executes in case of no errors, plus attach a single error handler at the end to handle any of the errors (in a manner similar to exceptions)
So yeah, there are better solutions today.
You cannot dereference a nullable value normally. However, inside a (x != null) block, or rather anywhere the compiler can infer that the value cannot be null, it automagicially turns into a non-nullable type. And there's the null-safe dereference operator (.? or similar) that returns null in case the first value is null.
Similarly with casting - if you have an if block with an instanceof check, within that block the variable has the type given by the check.
You still have to have a runtime-checked NPE in some cases (in case of hotswapping, casting to non-nullable types (which should be allowed but throws a checked excption), etc), but mostly this avoids the issues with NPEs, I think.
I agree that pattern matching can be powerful, and underutilized in most language designs.
Alternatively, I've been growing more in favor of the idea of not having null at all in the base language - if you actually need it it's relatively easy to implement if you have boolean algebra on types (Nullable<x> being equivalent to Either<x, Null>, where Null is an enumerated type with one value, null. Like what you said). And that way it's explicit, and people are more likely to use a better (read: more informative) exception type). Null ends up being an exception with no additional information, which can work in some cases, but often you want additional information. Even just "NotInitialized" or something like that is often better.
You can write code in typical imperative fashion but all blocking IO statements will cause a co-operative green thread switch.
Rust was also experimenting with green threads and similar async IO but they recently changed to use all-native threads.
I'm pretty sure that I/O is only task-blocking in Rust, and tasks can be 1:1 or M:N with native threads.
tasks can be either 1:1[0] or m:n[1]. The default is 1:1, but m:n should be equally supported by force-booting with libgreen[2].
[0] http://doc.rust-lang.org/native/index.html [1] http://doc.rust-lang.org/green/ [2] http://doc.rust-lang.org/guide-runtime.html#force-booting-wi...