Bennie, are you aware that you have replied to me only?

On Fri May 25 06:28:01 2012, Bennie Kloosteman wrote:
>> 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.

Well, they could be managed (i.e. if you call JS, you receive a jsval,
etc.), but I believe that's food for another thread.

> Speaking of which we can handle C errors in calls but what about C++
> exception ? Does any C++ code we hook need exception wrappers ?
> Also any error system rust should work when called from C  ( unlike
> C++ exceptions) .

It was my understanding that direct interaction with C++ was out of the
scope of Rust for the time being.

>>>> * Issues _must_ not be restricted to integers (or to one single type).
>> 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 .

Well, one of the main objectives of Rust is Servo. This does not mean
that Rust should be restricted to Servo but, if we attempt to make Rust
custom-tailored to too many things at start, increase the risk of ending
up with a clumsy package.

> 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.

>>>> * 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,

I actually meant "should not", sorry :)
More comments at the end of this message.

>> 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 ?

Not sure I understand. Do you mean to handle a case in which the task is
in such a bad shape (e.g. out of memory) that regular
communication/failure semantics cannot be executed?

>>>> * 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 }


What's so wrong with the first snippet (assuming that we *can* have good
performance even)?

Note that it might be possible to come up with a mechanism that does
both. Say, something along the lines of

// Case 1: Just kill the task if we can't parse
let i: int = Int32::parse(string, if_you_cant_do_it_just_fail);

// Case 2: Let me check with errno
let i: int = Int32::parse(string, if_you_cant_do_it_set_errno);
if (errno) {
 ...
}

// Case 3: Variant of case 2
let i: int;
alt (Int32.Parse(string, return_sum_type)) {
  {ok} {i = ok;}
  {ko} { // Handle case
  }
}

Now, I place this as an argument (giving it a nice type might be
difficult) but this could of course be part of the language. I believe
Graydon had something along these lines in mind.

I'll try and rewrite that |move| function with this kind of parametric
issue checking to see what it looks like.

>> 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.

>> 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 ,

Well, that isn't decided yet :)

From the top of my head:
- errorno is fast and crosses rings nicely, as you mentioned – but it is
quite difficult to extend and it is easy to forget checking it;
- pointer to error is easier to extend, but more complicated wrt memory
management, doesn't cross rings as nicely – and it is just as easy to
forget checking it.

My hope is that we can think of a better mechanism with a large subset
of the advantages of:
- ML-style exceptions;
- Erlang-style faults;
- libc-style errno.

> 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 .

I don't get that last sentence.

>>> * 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 …

Sorry about the confusion, I meant "not 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 .

Well, this has two problems:
- potentially awful performance;
- insane amount of logs.

In Gecko, until recently, the policy was to log every error at every
step of the stack. This policy was changed a few months ago, because of
log pollution. So that's an issue we need to consider.


> 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.

Sounds like you need an error monad :)

> 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

So you are advocating a style in which functions always (or almost
always) return a status rather than a functional result, is that it?
This is what we have in Gecko, but I tend to consider it more readable when:
- the function returns its functional value;
- errors are propagated by default.

I like a lot the idea of attaching logging/tracing hooks to error types,
though.

> 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

Thanks for the pointer.

Cheers,
 David


-- 
David Rajchenbach-Teller, PhD
 Performance Team, Mozilla

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to