7 ms·
The error model of Microsoft's new language
- skrebbel 13y agoI'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 13y agoifs-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 13y agodo 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 13y agoyes 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 );
- adandy 13y agoIt is possible to write your own contract abbreviators with Code Contracts so I would hope such functionality gets added to the new language. The post does mention however that object invariants are not supported so I do wonder how much Code Contracts are actually influencing it.
- taspeotis 13y agoI 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
- InclinedPlane 13y agoI'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 13y agoBy 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 13y agoSure, 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 13y agoI'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.
- jeremiep 13y agoSeems 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 13y agoIt'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"?
- edmccard 13y ago>Is the D scope + unrecoverable error different from Go's "defer" and "panic"? D's scope guard is similar to "defer", but it has three forms: "scope(exit)", "scope(failure)", and "scope(success)". So instead of a deferred function that tests "if r := recover(); r != nil {...}" you just do "scope(failure) {...}" D's unrecoverable error is just a matter of having an exception hierarchy where "Exception" and "Error" are separate subclasses of "Throwable", and by convention you prefer not to write "catch (Throwable t)" or "catch (Error e)".
- jeremiep 13y agoD 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.
- frik 13y agoAleks 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.
- scott_s 13y agoDeeming 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.
- usea 13y agoHere's a link to a video [0](2009) where Joe Duffy talks about some features he's exploring adding to C#. Mostly, he describes a method of organizing code into distinct object graphs to make concurrency easier to reason about. [0] http://channel9.msdn.com/Shows/Going+Deep/Joe-Duffy-Perspectives-on-Concurrent-Programming-and-Parallelism http://channel9.msdn.com/Shows/Going+Deep/Joe-Duffy-Perspect...
- RogerL 13y agoBut 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.
- twotwotwo 13y agoAn example would be a Web request in a concurrent app server: if one request has an error accessing the database, maybe it can't continue, but the server process should keep handling other requests. Generally, I think a "component" would be a piece such that if there's an unplanned-for, fatal failure in it, other components need to continue running.
- scott_s 13y ago
- luckydude 13y agoOld 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 13y agoYes, 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 13y agoSeems 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 13y agoIntroducing 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.
- mcguire 13y agoThat's how Erlang OTP does it, IIUC.
- drsim 13y agoA 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-doesn-t-c-have-checked-exceptions.aspx http://blogs.msdn.com/b/csharpfaq/archive/2004/03/12/why-doe...
- option_greek 13y agoWow, those are some interesting reads.
- iaskwhy 13y agoWould love to see some code examples. Has any surfaced yet?