This conversation reminds me of Alexandrescu's talk about D's scope keyword: http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2012/Three-Unlikely-Successful-Features-of-D
It looks like a graceful syntax for handling all sorts of nested error and failure cleanup... On May 25, 2012 3:00 AM, "Bennie Kloosteman" <[email protected]> wrote: > On Thu, May 24, 2012 at 9:16 PM, David Rajchenbach-Teller > <[email protected]> wrote: > > On 5/24/12 12:40 PM, Bennie Kloosteman wrote: > >>> * The system _must_ not prevent developers from calling C code from > Rust. > >>> * The system _must_ not prevent developers from passing a pointer to a > >>> Rust function to C code that will call back to it. > >>> * The system _must_ not prevent, some day, developers from calling Rust > >>> from JavaScript. > >>> * The system _must_ not prevent, some day, developers from calling > >>> JavaScript from Rust. > >> > >> These should be unsafe - I believe this is the case with rust. > > > > I am not sure if you mean this in relation with all four points or with > > the last one. So, indeed, I see no reason to change the fact that calls > > to C are considered unsafe. > > > > For calls to JavaScript, I have not given it much thought. I suppose > > that they could be either unsafe or somehow managed. > > externals calls either must work 100% ( including type conversions) or > be marked unsafe... if it breaks type or memory safety you need to say > that. > > Speaking of which we can handle C errors in calls but what about C++ > exceptions ? Does any C++ code we hook need exception wrappers ? > Also any error system rust should work when called from C ( unlike > C++ exceptions) . > > > > > >>> * Issues _must_ not be restricted to integers (or to one single type). > >> > >> Yes but returning error codes and then looking up further issue > >> detail separately is quite useful since your passing around little > >> information it gives the highest chance in a partially unsafe > >> environment of working out what happened . eg if the stack is > >> corrupted or you have major issues its useful that the error is memory > >> logged ( eg in ring 0 in a rust based kernel ) and then retrieved . > >> A simple integer return value has a much better chance.. > > > > Interesting point. > > Are we talking about implementing Servo with a ring-like mechanism? > > > > If so, I suspect that we may simply not want this kind of issues to > > cross ring boundaries. Otherwise, if we let high-level issues cross > > boundaries, we could be sending closures, for instance, which sounds > > like a bad idea. > > > > For the moment, I believe that we should assume that the issue mechanism > > will not be used for crossing ring boundaries. > > Is rust or this error handling solely for Servo ? What about writing > say a kernel or Linux kernel modules in rust ? To me system > programming is where Rust should be. If its all working that's fine > but I was showing some horrible worst cases and its still nice to get > some error information rather than a horrible crash . > > A similar thing can occur with any external call to C or asm. But the > concept is the same try to get at least an error code returned even if > the most abysmal circumstances. > > > > >> This could be a 64 bit value with the low 32 bits the error and the > >> upper 32 bit some sort of hash code. > >> > >> A more detailed but not guaranteed representation should be a detailed > >> structure. with time stamps etc I would even say this detail should > >> be created asynchronously via a new task while the actual error is > >> returned immediately . > >> > >> errno is a pain , but not because it returns an int but because all > >> the information you can retrieve on it is a error string. > >> > >> Actually you could log all the detail and just reference an index to > >> the log , Though this would require recent log entries to be > >> recallable and have more detail in the log fields eg error category > >> and level ( which are useful in a log anyway) > > > > All these are interesting points, although perhaps they arrive a little > > too early in the thread :) > > > > Im not so young anymore so when I train of thoughts I like to get it > on E-paper ;-) > > >>> * The default behavior in case of untreated issue _should_ be to > >>> gracefully kill the task or the application. > >> > >> If its integrated with tracing and logging the default behaviour > >> depends on the error type > >> > >> eg Trace , Log, Warning or Error continue , Critical = halt. > > > > A tracer/logger with this kind of semantics could certainly be built on > > top of the issue mechanism. I tend to believe that that they should be > > integrated from the start, though. > > Agree, > > > >>> * Whenever an untreated issue kills a task/application, it _should_ > >>> produces a report usable by the developer for fixing the issue. > >>> * It _should_ be possible to deactivate that killing behavior. There > >>> _may_ be limitations. > >>> * It _should_ be possible to deactivate that killing behavior > >>> conditionally (i.e. only for some errors). > >> > >> also a task can monitor child tasks for errors ( I don't think Rust > >> has events but something like that) and choose on error to abort or > >> continue depending on the error condition. . > > > > Sounds interesting. I suspect (but I am not sure) that this is something > > that could/should be built on top of a more elementary issue mechanism. > > Could you provide a scenario that we could use as a working base? > > > Yes it probably should be built on top ..but I really like the model > where items received from a pipe/channel are broken out and fired as > events ( which multiple callers can hook). > > Note an interesting issue here , if the task is in a bad error state > it possibly may not use the "pipe/channel" for communication to the > parent .. How is this handled ? SIgnals ? > > > > > > >>> * The system _should_ eventually have a low runtime cost – in > >>> particular, the case in which no killing happens should be very fast. > >> > >> I don't think the performance of an error system is important at all , > >> its more important to have stack and meta data to resolve the issue > >> especially in debug builds ( and meta data is very slow) . This leads > >> to people using errors to pass/check state which is a bad habit > > > > Could you elaborate on that last sentence? > > int I = 0; > try{ > i = Int32.Parse( string) > } > catch (Exception ex) > { > // handle cant convert > } > > > vs > > int I = 0 ; > if ( Int32.TryParse ( &I , string) > { // handle cant convert } > > > > > > I am starting to believe that collecting [meta]data might be something > > that we want to configure on a usage basis. For instance, in function > > |move|, introduced a few e-mails ago (I just reposted it at > > https://gist.github.com/2781413 for convenience), we may be interested > > in the metadata of calls to lines 10 and 12, but gathering metadata for > > the calls in lines 2 and 6 is generally a waste of resources. > > Yes it should be optional eg you don't always want it on traces and > logs , most of the time on errors ( always on debug) and always on > critical errors. > > > > > If we think of this as exceptions, it could be that we want several the > > ability to specify if/when we want to gather metadata at the level of an > > equivalent of |try|. I believe that this fits nicely with what Graydon > > had in mind, by the way. > > > >> I would add > >> * Tasks are the error scope / unit > >> > >> * should we have an exception like syntax that automatically creates a > >> sub task for the embedded statements ( and hence means those > >> statements cannot result in failure of the parent tasks) . Since > >> errors are scoped to the task , the easy way is a new task . > > > > This looks quite heavyweight to me. So, if you don't care about > > performance, sure. But I'm clinging to the hope that we can make > > something faster, so I disagree for the moment :) > > It is heavy weight but most Rust errors will not have exception > scopes... just functions that return an errorno or pointerto an Error > object , The concept of exception scope is useful though eg a single > threaded message pump is normally > > foreach ( var message in buffer) > { > try { > ProcessMessage( message); > } > catch (ThreadAbortException ex) { // handle } > catch (Exception ex) { // handle and continue to next message } > } > > We want every possible error handled so the loop never stops ..no > matter what happens . eg an out of bounds array , null pointer or core > dump in an external call should kill the message but not the message > pump. Obviously the unsafe / external core dump is difficult and may > not be possible but it is desirable. > > So these are a counterpoint to fail , we could say failscope and fail . > > > > >> * It should be integrated with tracing and logging. > > > > Looks like two distinct things to me. Why couldn't you build a tracing + > > logging tool on top of it? > > Above you say it should be integrated … Yes it can be built in the > standard libs but It should still be integrated and more importantly > the logging and tracing considered in the design not in isolation , > look how hard it is in C , in theory every time you return a null or > non zero return code you should be logging / tracing . > > ie ptr = malloc(N); > if ( ptr == NULL) > { > //get error no > // log / trace > // return to user > } > > Why does the caller need to do the logging ? You may have 1000s of > calls so you need to make wrappers just for the logging . malloc > should do it ( depending on app configuration) especially when logging > is built into the language. Since the standard lib doesn't the > caller has to do it … The best place to log errors is the one that > generated the error and by integrating the error system with logging > it can be done automatically. > > > I have written a ton of code over the years ( when I bother in > quality programs) like catch (exception) { if blah blah / log / > trace ; if severity is < n rethrow } and the c style error code way > is abysmal here if you want to log . Yet 99% of the time all you want > is some sort of log everything if the severity is > N in a config > file concept without writing the code. > > Maybe something like : > > 1. Fail returns a ref to Error type it creates > 2. Stdlib Errors Return a ref to Error type ( which can be the > Error.Success so you can go if ( function() != Error.Success) > 3. When error type is created , error type has a hook for logging / > tracing on construction. by default this should log depending on a > configurable level. > 4. Most errors should be statically defined and allow strongly typed > checking > > BTW this is an interesting article it covers .NET /C++ Exceptions vs > ErrorCodes vs COM HRESULT / IErrorInfo at the end > > http://blogs.msdn.com/b/cbrumme/archive/2003/10/01/51524.aspx > > > Ben > _______________________________________________ > Rust-dev mailing list > [email protected] > https://mail.mozilla.org/listinfo/rust-dev >
_______________________________________________ Rust-dev mailing list [email protected] https://mail.mozilla.org/listinfo/rust-dev
