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

Reply via email to