I don't think that's possible to retrofit onto a language. Best you can do is to add non-nullable types. But zero values are so core to Go's semantics that I kind of doubt it's possible to even add those in a sensible way.
Can you elaborate on this? I write go for 3+ years and I have no idea what corner cases and failure conditions do you mean.
Writing to a closed channel panics, but writing to a nil channel blocks forever.
Appending to a nil slice works fine, but inserting into a nil map panics.
If you have a function that returns an error struct, and you wrap it with another function that returns the error interface, nil returns from the inner function will no longer test equal to nil.
Defining a method with a receiver type of Foo, rather than <star>Foo, means all modifications to the Foo get silently dropped. This can also happen to methods that correctly take a pointer receiver, if their caller incorrectly takes a value receiver.
Maps are not threadsafe/goroutine-safe.
Expression evaluation order is not defined, and varies between compilers. (https://github.com/golang/go/issues/15905)
- Using an iterator more than once silently produces nothing. I notice this when I insert print statements to debug something, but then accidentally turn the following for-loop into a no-op. The Python 3 change that made more top-level functions return iterators made this problem more common, though I agree with the performance justification for doing it. It would be nice if iterating again after hitting the end raised an Exception, though I'm sure that would break all sorts of code that assumes it doesn't.
- Mutating function default arguments affects all subsequent calls. This is most common Python gotcha people seem to talk about.
https://gist.github.com/patio11/bc883d566778c323742432c203e6...
(You can see it here in the playground, but try it on your local machine if you don't believe me and/or think the playground has an inconsistent understanding of what time actually means: https://play.golang.org/p/ltdV9dI609 )
The docs are quite clear on this behavior and say "Timer will send the current time on its channel after at least duration d." -- key words being at least and says nothing about when you choose to read from the channel.
See https://github.com/golang/go/issues/11513 and https://groups.google.com/forum/#!topic/golang-dev/c9UUfASVP... for some background.
[1] https://www.reddit.com/r/bash/comments/4ksl7w/golanglike_gor...
As someone who writes Go every day for work,
I can't agree that Go is simple.
You may be confusing "simple" with "good". A simple solution to a complex problem may not be a good one. Go can be simple and still not a great solution because it pushes complexity to a higher level.Does it have "cheap threads", like offered by Go?
Coincidentally, I just looked at Nim this evening, wrote some code and came away with the opposite impression. I'll copy-paste my sort-of-blogpost on this from [1]:
Nim itself feels a lot unlike Go and, interestingly, a lot like C++:
1. Non-orthogonal features. In C++, there are references, which are like pointers, but not quite, so you always have to think about which one to use. In Nim, non-orthogonal features include tuples vs. objects, and sequences vs. openarrays.
2. Feature creep. Just look at the language manual [2]: generic functions, type classes, 10 calling conventions (10!), garbage collection (not sure if optional or not), inline assembler, operator overloading, exceptions, an effect system, AST macros. Name any contemporary programming language feature, chances are that Nim has it.
Then there's the documentation. The language manual [2] is okay-ish, considering the size of the language. But when I dive into the library reference, the built-in module "system" [3] is so outlandishly huge and the documentation so badly formatted that it takes a lot of hunting to find what's in this module (and what isn't). Just look at all the duplicate entries in the navigation bar on the left. The system module should definitely have been split into multiple modules for the multiple concerns it covers, possibly with reexports in the actual "system" module to make sure they're all imported by default. Some parts should just be moved out of it, for example the whole file IO business belongs into "os" IMO.
Another thing that concerns me about the standard library is how many duplication is going on in there. There are at least 4 different XML parser AFAICS, and two regular expression libraries, both based on the same backend (pcre). This might be the same confusion that most languages suffer from in their pre-1.0 stabilization phase, but especially then, it's a strong argument not to use the language in production pre-1.0.
The thing that really killed it for me that I was able to produce SIGSEGV by accident, without the compiler warning me about it. I think I wrote something along the lines of:
type Config = tuple
someSetting: string
anotherSetting: string
proc readConfigFile(path: string): Config =
var file = open(path)
defer: file.close()
# TODO: implement the rest
var cfg: Config
return cfg
var cfg = readConfigFile("./example-config")
echo(cfg.someSetting) # this produces a SIGSEGV; probably because
# the memory backing `cfg` is not initialized
In 2016, I expect any new language to warn me about (or outright refuse to compile) code that might access uninitialized memory or do any other unsafe stuff, especially for a program that will run as root.[1] https://github.com/holocm/holo/issues/8#issuecomment-2412822... [2] http://nim-lang.org/docs/manual.html [3] http://nim-lang.org/docs/system.html
However, if I write
echo(cfg.someSetting[0])
it will segfault. This makes sense because it dereferences a null pointer (in Nim-speak, a nil value). I would guess that's what you experienced.Dereferencing a null pointer is not unsafe. The program cleanly exits. Compiling that via C is sketchy though, because the C compiler may treat provable null pointer dereferences as undefined behavior.
Is it as good at concurrent services as golang is?
Go is a language that pushes remembering corner cases and failure conditions onto the programmer rather than the language and runtime itself.
When you already have to remember a myriad of corner cases for business logic, also remembering so many corner cases for your code hurts productivity.
I also believe that languages exist to make getting to an end result in given domains easier. Go does not make my life easier.
I really hope it gets generics. I wish it would do away with nil/null.
Nim is a very good language that actually accomplishes the simplicity Go wanted imo.
Go affords simplicity to the Go compiler writers at the cost of burdening Go users with having to remember inane things.