On Wed, Aug 21, 2013 at 6:31 AM, Bennie Kloosteman <[email protected]>wrote:

> First, there is absolutely no need to create a new exception object
>> whenever you throw an exception. The exception object can be constructed
>> statically and a reference to it can be thrown. Returning that reference
>> has identical cost to returning an error code. No, you won't get dynamic
>> per-exception information, but you were perfectly willing to give that up
>> by returning error codes, so why is everybody whining about that?
>>
>
> How can this be if its a user created type ? Possibly with a param ?    I
> can see it working for some hand picked excpetions like FastException but
> not MyException (appErrorCode);
>

There are a couple of ways this could work:

   PreallocatedException = new MyException(appErrorCode);
   ...
   fun f() {
      ...
      throw PreallocatedException;
   }

The other option is to stack-allocate the exception. Even if you are
throwing a custom exception, the constructor code for YourException is
known and can be inlined. The thing to remember is that exception objects
don't involve that many fields. Typically the PC at which the exception
occurred and the type tag of the exception object is all you need. In CLR
there seems to be a convention that the exception carries a string-flavored
diagnostic message, but if the string is constant that's just a third
pointer.

Ah. But it does occur to me that I made an unintentional assumption. In
most languages, exceptions are pretty much like any other object, except
that they happen to derive from some standard library Exception class.
These objects are allocated in the usual way. They can be copied, passed
around, and so forth.

But there is another possible design, which is to define Exception as an *
unboxed* type. So when you invoke

   throw MyException(parameters)

you are actually returning a *reference* to a stack-allocated, boxed
object. This is a bit odd, because the object is stack allocated on a part
of the stack that has gone out of scope, but if we're going to preserve
that chunk of stack for later backtrace display, there's no problem with
that.



>
>> Second, there is absolutely no need to copy stack frames when an
>> exception is thrown. It is not a requirement that the stack remain
>> immutable, and it is not a requirement that the stack be preserved from the
>> originally thrown exception. You are only going to perform a backtrace for
>> an exception that is *not caught. *In that case, no code has run that
>> might modify the stack, and the original stack is alive and well. You can
>> then perform a backtrace from there. All that is needed is to preserve the
>> SP and PC from which the original throw occurred. Some of you have been
>> imagining richer mechanisms than this, but once again you all seem
>> perfectly willing to tolerate not getting those mechanisms in the error
>> code style of design.
>>
>
> To me i really want to know what is on the stack where it throws and in
> string format ..eg in release runtime loop throwing out of stack . I can
> see the line of code and work out how the error can happen without
> reporducing all the conditions.
>

Well, no, you don't. Because if you really wanted that, you wouldn't be
interested in error codes, because those don't give you any of that.

But assuming you *do* want that, you still don't need to *copy* the stack
frame. What you need to do is *preserve* the stack frames. As long as the
stack frame is preserved, you can produce a pretty string later if you find
that you need it.

So we need to ask: what might cause the stack fragment *not* to be
preserved. The answer is "procedure calls". That is: newly created stack
frames. But wait! Those stack frame creations involve mandatory stores for
initialization purposes. All we need to do is make sure they don't happen
on the stack we are currently trying to preserve. To do that, all we really
need to do is make them happen somewhere else. Which could be on a newly
allocated stack fragment (note this is only allocated in the handler), or
it could be a new section of the existing stack *below* the exception
frames (i.e. in a stack position that we would normally think of as "newer
than" those frames).

Several people here have said that they don't want *anything* in the stack
frame to change because of debugging. I would hazard to guess that even CLR
doesn't provide that. If handler code modifies a parameter, my guess is
that the backtrace shows the modified value. Somebody should check what
happens with a test case. If you want that level of debugging, the right
way to do it is to run a debugger and put a breakpoint on __raise().



>
>> Unwinding the stack until a catch handler is found is generally *cheaper* 
>> than
>> conventional error return. Both mechanism are doing precisely the same
>> thing; the error return case does it more explicitly, but that doesn't
>> change the cost of it.
>>
>
> There is a coding style here  here .. eg a resource is created cheap and
> now has to be unwound ..  nor do i believe this unwinding is cheaper..im
> compraing it to validation where 90% of the time this is an issue . and
>  failure is this
>
> int Compare  (string str1 , string str2)
> {
> if ( str1.Length !=str2.Length)
>      return -1;
>
> // do rarer validation
> }
>
> Nothing can be anywhere near this speed .. it will be inlined etc..
>

This is a poor example, because this isn't a case that should be handled
with exceptions in the first place. In more realistic code, argument
validation failures would be handled as fatal errors, because they indicate
a structural problem in the program. And we really shouldn't worry about a
small marginal cost in what amounts to an exit() call.

I think you are saying that there are good examples of procedures that *
should* return result codes of various forms. I agree. And having
exceptions in the language doesn't prevent that in any way.

But from a type system they are much rarer than you might think. The
problem is that the procedure *must* return a value of the stated return
type, even if it also returns an error code. There are many cases where we
need to generate an error result without having anything plausible to
return. In those situations, there are only two options that preserve type
safety:

1. Exceptions, because the normal return path is not live and therefore the
absence of a normally returned value doesn't matter - though we need to be
careful about initializers in this case.

2. Using union values as return types.



shap
_______________________________________________
bitc-dev mailing list
[email protected]
http://www.coyotos.org/mailman/listinfo/bitc-dev

Reply via email to