Asked on Reddit: Which of Rust, D, Go, Nim, and Crystal is the strongest and why?

Dave via Digitalmars-d digitalmars-d at puremagic.com
Thu Jun 11 06:21:26 PDT 2015


> It seems to be a controversial subject: 
> https://github.com/D-Programming-Language/phobos/pull/1090#issuecomment-12737986

As the topic has been argued for the past 50 years. No one ever 
agrees
on the best way to handle errors. But I think most of this is 
because programmers tend to be the most stubborn and unchanging 
type of folks in the world. They often care that they look right. 
Not that they are right ;)

> Exceptions are not meant to force handling errors at he source.

This attitude is why so many exceptions go unhandled at the upper
layers. When you have a top level that calls a function that 
calls 50 other functions, each that throw a handful or more 
different exceptions, it's unreasonable to expect the upper layer 
coder to account for all of them. In fact, in practice they 
usually don't until bugs arise. This is provably bad practice.

> If you want to force handling errors at the source they should 
> be part of the return type.

Again what errors are worth throwing as exceptions in your
paradigm? Which ones are worth returning? This separation is very
arbitrary for my taste.

> Exceptions are not "hard fails".

They can be if they go unaccounted for (depending on the
language/environment). Java has the infamous,
NullPointerException that plagues Java applications. C# has the
NullReferenceException.

> You don't have to crash the entire program just fail the action 
> the user was trying to do and display a nice error message with 
> whatever information you can and want to provide to the user. 
> Even if you don't handle them, they > provide information 
> useful for debugging.

Not gonna disagree there.

>>> It doesn't really guarantee the functions not annotated as 
>>> throwing won't > crash
>>
>> Combined with other guarantees (such as immutability, thread
>> local storage, safe memory management, side-effect free code, 
>> no
>> recursion, etc), you can make a reasonable guarantee about the
>> safety of your code.
>
> And a superhero cape, combined with an airplane, airplane fuel 
> and flight school, allow you to fly in the air.

Not really sure how to parse this...Doesn't seem like you have 
any good argument against what I said. Again I said you can make 
a *reasonable* guarantee. And I am not alone here. If you look at 
Rust, it really does illustrate a trend that functional 
programming has been pushing for a long time. Provable 
guarantees. Problems are very rarely unique. There are a core set 
of things that happen frequently that cause problems. And these 
things are easily recognizable by compilers. You can't prevent 
everything, but you can prevent a good deal of the obvious stuff. 
This is just an extension of that mindset. So it is not really 
that outlandish.

> It is the other restrictions(without getting into a discussion 
> about each and every restriction in the list) that make the 
> code safer - nothrow doesn't really contribute IMO.

Without the nothrow, you cannot guarantee it won't cause problems
with unhandled errors ;) Seems like a nice guarantee to me. I
would at least like this option, because library writers often
try to write in an idiomatic way (and I tend to use the most 
reputable libraries I can find), which gives you some guarantees. 
The guarantee would be better served by default IMHO though.

Having a 'throw' keyword is also useful for IDE's. Anybody that
has used Visual Studio and C# will tell you a nice feature is
that Visual Studio can tell you what exceptions get thrown when 
calling a
method (very useful). C# does it in a different way, but a 
'throw' keyword would actually help scanners figure this out very 
trivially as well as programmers just reading the header of a 
function.

> Scala and Rust seem to maintain both paradigms just fine. It's 
> actually beneficial to have both - you have to acknowledge 
> return-type-based exceptions, and you can always bypass them by 
> turning them to exceptions, which are good for logging and 
> debugging.

I do not believe Rust has exceptions.

I don't mind a language having multiple ways to handle errors.
Seeing how its a topic no one ever is on the same page about,
it's actually a wise design decision. But you don't often see
library writers mixing them for consistency purposes. It's just
easier for people to learn your library when you have one error
handling scheme. It's usually encountered only where two
libraries written by different vendors have to interact in
application code.

> If exception handling is enforced, they can only be bypassed by 
> converting them to errors or crashes, which are much less nice 
> than exceptions when it comes to debugging, logging and cleanup.

Exceptions have many benefits. They have many disadvantages too.
They are often very slow on the exceptional path, which occur
more frequently than most admit.

> Writing code that acknowledges that this code can fail due to 
> an exception somewhere else does not count as ignoring it.

You could not handle it all the way up the chain (at the cost of
adding something to a definition, not much trade-off there). That
would essentially be ignoring it. From a design perspective you
could also have some mechanism (be it a keyword or whatever) that
you use to explicitly 'suppress' them for code that needs to be
faster, or code that you literally don't care. In application
code, you care. It's a good default to force people to handle
errors as they occur (which is what I am talking about,
defaults). If they wish to not handle them there, it's not at all
hard to imagine ways to allow people to 'suppress' them or 'pass
them up' when the situation calls for it. Force people to deal
with them by default, let them explicitly handle it in another
way. Or they can just use return types.


More information about the Digitalmars-d mailing list