
The error model of Microsoft's new language - thomasz
https://plus.google.com/+AleksBromfield/posts/SnwtcXUdoyZ
======
scott_s
Deeming certain errors to be unrecoverable _in a component_ means that
software will be designed such that "components" will be bundles of
functionality with tight dependencies. This is interesting, and forces a
separation across component boundaries that we should do anyway.

Consider a web server. If we tried to make the entire web server one
component, then hitting an out-of-bounds error when handling a request would
take down the entire web server. That is bad. But if the main event loop of
the web server is a component that depends on a separate component that
handles requests, then the main event loop could recover from the out-of-
bounds error in the page request component. This is what we should always do,
of course, but it's being forced (or, heavily encouraged) by the programming
model itself.

I'd like to see how "components" are defined to understand this better - or
any code, really.

~~~
RogerL
But do we really want to be forced to design components based on whether
errors are unrecoverable or not? It seems to conflate two orthogonal concepts.
I say that without seeing any code or examples, of course.

~~~
bunderbunder
It's a yoke I'd be pretty happy to accept as an application developer. No,
it's not necessary to couple the two concepts. But nine tenths of good
language design is coming up with good abstractions, and good abstractions
always involve some conflation. And from a software engineering perspective I
can see some good reasons for this choice.

One is that it creates some predictability around how errors will be handled.
As a producer of components, I know that within this component I have to
accept that certain classes of error will always cause a fast failure, and
other classes of error should be handled as immediately and gracefully as
possible. Compared to the mishmash of different error handling philosophies
that I currently encounter when working on different components, this seems
like it might be a welcome improvement even if it isn't a complete solution.

As a consumer of components, I think it's even better because it enforces
still stronger predictability. I get a couple nice guarantees out of this. One
is that critical failures bringing the whole component down means I encounter
fewer situations where I'm unsure whether the overall application is in a
consistent state, because 3rd-party component developers have fewer
opportunities to do weird things with exceptions. The other is that I can
always defend against critical failures in 3rd-party components bringing down
the whole application. That isn't always easy to do in vanilla C#, where
FailFast exceptions always bring down the house and the best defense against
that is to resort to the hassle of process-level isolation. For systems
programming I imagine such measures are even more irritating, since process-
level isolation creates performance overhead.

~~~
RogerL
As I replied below, my argument is not that reasoning and controlling error
handling is not important (I spent a long time in real-time, critical systems
such as avionics). It is that components doesn't strike me as the most
commodious way to express my decisions on error handling (I may be wrong, I
haven't seen the code).

------
drsim
A few years ago I was debating with a colleague on the de/merits of checked
exceptions. I was pro, but after reading through these gems about why
Microsoft didn't put them into c# I changed my mind:
[http://blogs.msdn.com/b/csharpfaq/archive/2004/03/12/why-
doe...](http://blogs.msdn.com/b/csharpfaq/archive/2004/03/12/why-doesn-t-c-
have-checked-exceptions.aspx)

~~~
option_greek
Wow, those are some interesting reads.

------
jeremiep
Seems to have a lot in common with the error handling in D.

They both make the distinction between recoverable and unrecoverable errors. I
feel D to be more flexible however since it doesn't prevent the handling of
unrecoverable errors. It simply discourage it, which is what you want in a
systems programming language.

One exceptional feature of D related to error handling are scope statements.
They easily and elegantly make the nested try/catch/finally blocks go away. I
wonder if Microsoft is going to use this.

~~~
beagle3
It's been a while since I looked at D (10 years or so)... Is the D scope +
unrecoverable error different from Go's "defer" and "panic"?

~~~
jeremiep
D changed a _LOT_ in 10 years, especially since D2.0 has superseded D1.0 and
added tons of fantastic features. It's definitely worth a look!

Did a quick lookup on Go's defer and panic, it does indeed have similarities
with D's scope. Go's defer looks like the equivalent of scope(exit) in D.

The big difference is that error handling in Go uses error codes while D uses
a Throwable base class subclassed into Exception and Error for recoverable and
unrecoverable errors respectively.

D also has scope(success) and scope(failure) to execute code blocks depending
on whether a Throwable is raised or not.

------
skrebbel
I'm very happy to see that contracts play such a central role in this
language. I hope that this will mean that contracts will finally gain more
popularity, if Microsoft manages to push this language well enough.

I feel that 70% of what I write in unit tests and ifs-at-the-start-of-a-method
should be in contracts, and the only reason they're expressed so cumbersome is
because the languages I use don't support any better.

~~~
stinos
_ifs-at-the-start-of-a-method_

Even for a simple if: DRY! You should have put those in reusable functions
with nice understandable names ages ago :]

~~~
octo_t
do you know what contracts _are_?

Typical contracts are 'assert (arg != null)' or 'assert(arg1.length ==
arg2.length)' or 'assert (hour >= 0 and hour <= 23)'

~~~
stinos
yes I know what they are. Use them all the time. But since the post is about
if I imagine it's about things like

    
    
      if( x < 0 || x > 5 )
        throw new ArgumentOutOfRange();
      if( y == nullptr )
        thwrow new NullRefException();
    

which should imo be something like

    
    
      Contract.AssertInRange( x, 0, 5 );
      Contract.AssertNotNull( y );

~~~
taspeotis
I imagine you could do even better with something like PostSharp or Fody.

    
    
        public void MyFunction([InRange(0, 5)] int x, [NotNull] object y)
        {
            // ...
        }
    

I just checked, and in fact Fody can do something just like this [1].

The only downside I see is contracts like this would be hard to write
concisely:

    
    
        if (useFirstObject == true)
            Contract.AssertNotNull(firstObject);
        else
            Contract.AssertNotNull(secondObject);
    

[1] [https://github.com/Fody/NullGuard](https://github.com/Fody/NullGuard)

------
frik
Aleks replied about contracts (in the comments below the article):

    
    
      We definitely tried to learn from Eiffel. Our contract 
      system really isn't revolutionary at all; we just tried
      to take the simplest and best parts of Eiffel, and 
      distill them down into a format that would feel familiar
      and comfortable for C# developers.

------
luckydude
Old school C hacker here. Can someone explain to me like I'm five how this is
different from

assert(p != NULL); // unrecoverable error

if (p == NULL) {

    
    
        // no buffer for you but we'll continue
    
        perror("malloc");
    
        return (0);
    
    }

~~~
scott_s
Yes, see my top-level comment in this thread. The key notion is that such
errors are unrecoverable _in a component_ , but you can recover from outside
that component. So, if you are in component A, and you make a call to
component B, and B has an unrecoverable error, B dies, but A can still
recover.

Without code, though, it's hard to see how this will actually work.

~~~
luckydude
Seems like if you used processes to implement components and had a master
process to respawn when a "component" dies then it is just assert() vs
perror().

That's hand waving past any shared state but if you need that I suppose you
use threads (I'm not a thread fan but I have to believe there is a
thread_assert() that kills just that thread).

~~~
asveikau
Introducing threads and multiple processes seems slightly crazy. Remember that
ideally the most common case is no failure at all and you don't want to
introduce cost for that. Why not just have the point of failure unwind the
stack until it sees a component boundary? Without multiple address spaces
certain types of failure would blow up the whole process but that's life.

------
InclinedPlane
I'm a bit dubious without seeing some concrete code. What I see is a lot of
strong assumptions being made and usually when that happens the result is
leaky abstractions. We already have extremely leaky abstractions in every
other error model out there, so I'm concerned this model is merely shifting
the complexity around.

~~~
bunderbunder
By your own admission, all the existing error models are janky.

I'd think that should be a reason to encourage people who are trying new
things in an effort to come up with one that works well, not a reason to
offhandedly poo-poo anyone who isn't satisfied with the acknowledgedly crummy
status quo.

~~~
InclinedPlane
Sure, but there's a lot of handwaving about this new error model. If there
were code examples it would be a lot easier to form a solid opinion one way or
the other.

~~~
bunderbunder
I'm not sure we should expect anything but handwaving. This language hasn't
been released to the world; it may be that it's not even a fully-functional
language yet. All we've got to go on is a couple sentences from a blog post
that clearly wasn't intended as a detailed exposition, a G+ post from someone
who is no longer involved in the project, and a whole lot of Reddit. Mostly
the Reddit.

More details will hopefully be coming soon, but until then we might as well
stay calm and try not to confuse cocktail napkins with something that's ready
for peer review.

------
iaskwhy
Would love to see some code examples. Has any surfaced yet?

