> In practice, this does not seem to be a problem on 64-bit systems, but it is one on 32-bit.
You seem to be referring to the problem where (since the address space on 32-bit machines is small) some values may be identified as valid pointers. But that isn't the only problem with the garbage collector. It performs badly when lots of short-lived small objects are created. Eventually, it'll need a better collector.
> They are looking at improving it, but it will take time.
That's the standard answer. But currently, its GC is weak.
> A lot of the languages Go is often compared to, like Python, have far worse GC (CPython _still_ can't collect datastructures which have cycles, if any of them has a finalizer).
Here, the discussion was about Java and C#.
> As far as error handling goes, the designers of Go thought about it for a long time. You may or may not agree, but calling it "contrived" is disingenuous. Basically, a lot of people have used and grown to dislike the confusion of routine errors and exceptions that prevails in languages like Java.
Every serious chunk of Go code is interwoven with if statements to check for errors. It breaks the logical flow of functions. Besides that, it's not mandatory to bind the return values of a function. So for side-effecting functions, it's easy to accidentally ignore errors. And then there is the whole 'nil may equal be nil' issue:
> You want exceptions only for signalling fatal errors.
I want errors as values, *without* having to check the result of every function call. This has long been solved in option types that are also monads, see e.g. Maybe and Either in Haskell. Java checked exceptions are not too bad either: they don't clutter the flow, but you cannot silently ignore them (you have to catch them or indicate that your method might throw that particular exception).
Go doesn't differ much from C wrt. to error handling. Except that in C I know that -1 is always -1 or 0 is always 0.
> Both are perfectly valid approaches. I don't feel like the colleciton of macro tricks and templates often glorified as "a DSL" in C++ requires any comment, other than: please, make it stop.
Right, I was referring to the latter (EDSLs). So, what facilities does Go provide to support the latter? I haven't seen any real EDSL in Go. DSLs have been done in static languages before, without the horror of C++. E.g. Hamlet is a EDSL in Haskell for producing HTML in a type-safe manner:
> With regard to generics: if you find yourself using interface{} everywhere, you're doing something wrong.
Sorry, I was being sarcastic there. It's the standard answer you will get on various Go fora: Go doesn't need generics, because there is interface{}. Anyway, the criticism still stands: Go doesn't have parametric polymorphism, so you either:
- If you are lucky, use non-empty interfaces.
- End up duplicating copying the same algorithm multiple times for different types.
- Write functions that take the empty interface and return the empty interface.
E.g. consider writing the Haskell function:
replicate :: Int -> a -> [a]
(Repeat a value n times.)
A Go equivalent is:
func replicate(n int, val interface{}) []interface{}
Not only does this completely throw away type safety, it's also an example of Go's tediousness. If you call, say replicate(20, 10), you cannot directly cast the result to an []int, because []interface{} is obviously something different.
By all means, don't take my word for it. I encourage people to read Mark Summerfield's Programming in Go. If you use a modern static language such as C#, Haskell, or whatever on a daily basis, you'll be thinking "heh, I could do this in X more elegantly in a far smaller number of lines" every half page or so.
Posted Oct 26, 2012 21:55 UTC (Fri) by cmccabe (guest, #60281)
[Link]
I programmed for Android back in the 1.1 days. I'm pretty familiar with the problem of lots of creating lots of small objects. That problem is now effectively solved on the newer versions of Android, due to Dalvik updates. I feel confident that Go will tread a similar path.
> Go doesn't differ much from C wrt. to error handling. Except that in
> C I know that -1 is always -1 or 0 is always 0.
This is really unfair. Numeric types are strongly typed in Go.
Also, in C, 0 may not always be 0. Technically pointer NULL is a logical representation, not a physical one, so casting a NULL value for a pointer to an int may result in something other than 0. As someone invoking the name of Haskell, you should know this :)
No real-world C compilers that I know make use of this liberty. As usually, C++ "outdoes" C in the amount of implementation-dependent crud. Specifically, NULL values for pointer to member functions are usually not represented by the bit pattern 0. Check this out for some nifty implementation dependent spew:
I agree that the way in which interface values are compared to nil in Go is a little weird. Since the interface types are represented by a tuple internally, it would have been nicer to force developers to write out that tuple when comparing an interface to a constant.
We are going to have to agree to disagree about error handling. I could point out a lot of other notable programmers who prefer error codes to exceptions, not just Joel Sposky. From the Google C++ coding standard, to Raymond Chen, to Linus Torvalds. But what do those guys know anyway? Java checked exceptions are the way and the light (hint: they're not.)
Comparing Go and Haskell is comparing apples and oranges. Go isn't intended to be a functional programming language. We already have a ton of those already (OCaml, Scala, Clojure, etc.) Maybe for algorithms work it's good, but for systems-level work I think those are all very uninteresting.
No thanks.
Posted Oct 26, 2012 23:04 UTC (Fri) by Cyberax (✭ supporter ✭, #52523)
[Link]
You might note that Scala and Clojure both require a JVM (see the referenced news article). And in fact if you want a cross-platform static typesafe language that is not C/C++ then your choices are quite limited.
Basically, it's Java or GTFO. At most you can make do with Mono. There are no other viable choices.
No thanks.
Posted Oct 26, 2012 23:54 UTC (Fri) by ibukanov (subscriber, #3942)
[Link]
> I want errors as values, *without* having to check the result of every function call.
I have found that in practice the moment one wants to add more context to errors the good old return flags to indicate unexpected return status results in least cluttered code.
For example, in Java stack traces in log files by themselves can be rather useless for problem diagnostics. To facilitate the analyzes it is often necessary to log state information from quite a few call sites. But in Java that results is rather ugly
With return error codes the extra clutter is minimal - one just needs to add log_extra_error_state(); on the error path.
Now, I presume in Haskell such annotated error reports should be rather simple to implement using Either. But even in Haskell checking for errors after return is inevitable if one wants to add the context information only on error paths.
No thanks.
Posted Oct 27, 2012 6:42 UTC (Sat) by Cyberax (✭ supporter ✭, #52523)
[Link]
Yeah, sure. So with error code you basically get:
> 42. Program failed. Now try to find out why, mwahahah!
In Java you can _rethrow_ exceptions, without losing the cause. I.e.:
> catch(SomeException ex)
> {
> throw new MyException(log_state(), ex); //We DO NOT lose the cause
> }
No thanks.
Posted Oct 27, 2012 8:30 UTC (Sat) by ibukanov (subscriber, #3942)
[Link]
> Yeah, sure. So with error code you basically get:
> 42. Program failed. Now try to find out why, mwahahah!
No - with consistent error logging one gets in C very useful stack-like information about the error state without the noise of deep Java stack trace.
Clearly in Java one can do the same and have a stack trace in addition, but even in C it is possible to get the stack trace. Yet the C solution brings less clutter to the server code where it is desirable to log on errors (and only on errors) the maximum information about the state.
RuntimeException ftw
Posted Oct 27, 2012 10:41 UTC (Sat) by man_ls (subscriber, #15091)
[Link]
With well coded programs a stack trace is all that is needed 99% of the time, or at least that is my experience. You can save the bit about "consistent error logging" and still spot errors.
There are weird occasions where e.g. the Android platform eats up your stack trace and generates its own, but that is not usually the case.
As to checked exceptions, they look good but in practice lead to byzantine exception hierarchies and hyper-delicate error handling, not well suited for humans (or for teams). Unchecked exceptions are good in that you don't need to handle all possible situations. In a web application you can just catch them at the root level, log them and print an HTTP 500 page; the user is not going to care at the moment as to why you are not showing the info they want, and the admins get a nice stack trace -- see above.
RuntimeException ftw
Posted Oct 28, 2012 0:09 UTC (Sun) by cmccabe (guest, #60281)
[Link]
Go has exceptions, it just calls them "panics" and doesn't make an attempt to give them elaborate type hierarchies. So if your program does something _really_ bad, it will abort with a stack trace.
As far as spewing stack traces for normal errors-- people who want this are not thinking clearly. Unless you are a developer, you shouldn't need to read stack traces.
It's really nice to have stack traces in the language-- lack of them in the language is awkward in C/C++, although there are libraries that can help a lot.
RuntimeException ftw
Posted Oct 28, 2012 8:48 UTC (Sun) by man_ls (subscriber, #15091)
[Link]
Unless you are a developer, you shouldn't need to read stack traces.
Absolutely true, I did not want to imply that the stack trace is shown to the user. The server displays a regular, nice 500 page (with no mention of "HTTP 500" either); but the stack trace is stored in the logs for further analysis.
Exceptions are good also to return from APIs, as long as they are documented: they come out in tests, are easy to spot and understand, and easy to deal with.
RuntimeException ftw
Posted Oct 29, 2012 18:31 UTC (Mon) by cmccabe (guest, #60281)
[Link]
I disagree that exceptions should be returned from APIs (shouldn't that be "thrown"?) The caller shouldn't have to understand the internal implementation of your library to use it. A null pointer exception 10 levels deep in library code is not a friendly API, even for programmers.
If you can fail, document how you can fail, and come up with return codes or another API to handle it cleanly. If you can't fail, then return void and be done with it.
Checked exceptions were an attempt to make exceptions "work like return codes." But it failed. Every method in the world ends up throwing IOException, and it basically functions exactly like unchecked exceptions.
RuntimeException ftw
Posted Oct 29, 2012 18:50 UTC (Mon) by man_ls (subscriber, #15091)
[Link]
Sorry, I meant "Exceptions are good also to throw from APIs, as long as they are documented".
But throwing a NullPointerException is not what I said; that is obviously a bad idea in any case. Just declare an unchecked exception for every failure condition (with an umbrella super-exception) and document them. That way you can throw them from any point in your code. This is not different from your description: "document how you can fail, and come up with return codes or another API to handle it cleanly". Unchecked exceptions are a wonderful way to handle failures cleanly; in effect these exceptions become another part of your API.
IMHO, avoid checked exceptions like the plague because they become, without exception, a mess. In a recent Android app I thought I could get off with a checked exception for offline mode to force implementors to deal with it, but in the end I had to change it back to unchecked.
No thanks.
Posted Oct 27, 2012 17:37 UTC (Sat) by Cyberax (✭ supporter ✭, #52523)
[Link]
Yeah, sure. So now you're proposing to do LOGGING from basically every level of stack. And where are you going to log things? If you say 'stderr' then I'm going to come and burn down your house.