February 19, 2012
Are you sure about that?

My understanding is java works the same way in terms of re-evaluating stack
traces, except that it has
'throw;' which keeps the original intact, specifically for rethrowing.

"Jose Armando Garcia" <jsancio@gmail.com> wrote in message news:mailman.601.1329663665.20196.digitalmars-d@puremagic.com... On Sun, Feb 19, 2012 at 12:44 PM, Alex Rønne Petersen <xtzgzorex@gmail.com> wrote:
> On 19-02-2012 15:41, Andrei Alexandrescu wrote:
>>
>> On 2/19/12 7:31 AM, Timon Gehr wrote:
>>>
>>> On 02/19/2012 09:26 AM, H. S. Teoh wrote:
>>>>
>>>> On Sat, Feb 18, 2012 at 11:52:00PM -0800, Jonathan M Davis wrote: [...]
>>>>>
>>>>> So, while at first glance, it seems like a good idea, I think that it has too many issues as-is to work. It might be possible to adjust the idea to make it workable though. Right now, it's possible to do it via mixins or calling a function inside the catch, but doing something similar to this would certainly be nice, assuming that we could sort out the kinks.
>>>>
>>>> [...]
>>>>
>>>> I have an idea. What about "signature constraints" for catch, ala template signature constraints? Something like this:
>>>>
>>>> try {
>>>> ...
>>>> } catch(IOException e)
>>>> if (e.errno in subsetYouWantToHandle)
>>>> {
>>>> ...
>>>> }
>>>>
>>>> Just using IOException as an example. The idea is to allow arbitrary
>>>> expressions in the constraint so whatever doesn't satisfy the
>>>> constraint
>>>> will be regarded as "not caught", even if the base type matches.
>>>>
>>>>
>>>> T
>>>>
>>>
>>> Nice.
>>
>>
>> That helps. This quite nicely illustrates that types don't necessarily need to proliferate. Something not much more constraining can be done today:
>>
>> try {
>> ...
>> } catch(IOException e)
>> {
>> if (e.errno !in subsetYouWantToHandle) throw e;
>> ...
>> }
>>
>>
>> Andrei
>
>
> As I pointed out on the pull request, this is *evil*. It resets the stack trace.
>

What? Is there a technical reason why throw resets the stack? Java doesn't work this way. In java the stack is created when the object Throwable is created:

"A throwable contains a snapshot of the execution stack of its thread at the time it was created. It can also contain a message string that gives more information about the error. Finally, it can contain a cause: another throwable that caused this throwable to get thrown. The cause facility is new in release 1.4. It is also known as the chained exception facility, as the cause can, itself, have a cause, and so on, leading to a "chain" of exceptions, each caused by another. "

We should consider changing this to work more like Java. This allows for patterns like:

// Log the stack but don't throw
auto e = new Exception();
writefln(e.stack);

Thanks,
-Jose

> --
> - Alex


February 19, 2012
On Sun, Feb 19, 2012 at 12:51 PM, Alex Rønne Petersen <xtzgzorex@gmail.com> wrote:
> On 19-02-2012 15:46, Andrei Alexandrescu wrote:
>>
>> On 2/19/12 8:44 AM, Alex Rønne Petersen wrote:
>>>
>>> On 19-02-2012 15:41, Andrei Alexandrescu wrote:
>>>>
>>>> That helps. This quite nicely illustrates that types don't necessarily need to proliferate. Something not much more constraining can be done today:
>>>>
>>>> try {
>>>> ...
>>>> } catch(IOException e)
>>>> {
>>>> if (e.errno !in subsetYouWantToHandle) throw e;
>>>> ...
>>>> }
>>>>
>>>>
>>>> Andrei
>>>
>>>
>>> As I pointed out on the pull request, this is *evil*. It resets the stack trace.
>>
>>
>> I understand, that's a good point. Could the matter be considered an implementation issue?
>>
>> Andrei
>
>
> Unfortunately, I don't think so. As far as I am aware, there is no good way to solve the problem; you can't know whether the user intended to rethrow (and thus continue the stack trace) as opposed to doing a clean throw.
>
> You could say that if the throw statement is "throw new T();", then a new stack trace is created, and in all other cases, the stack trace is continued, however, this doesn't work universally (think: creating and returning an exception object in a function and then throwing it).
>

In general that is fine because in most cases you will use it as:

throw createException(... data ...);

What you can't do is cache exceptions:

immutable _IOExceptionCache = new IOException(...);

void someFunction(...) {
  throw _IOExceptionCache;
}

I think the best way to abstract exception creation is:

throwException(... data ...) {
 throw new Exception(...);
}

Thanks,
-Jose

> --
> - Alex
February 19, 2012
On 19-02-2012 16:00, Jose Armando Garcia wrote:
> On Sun, Feb 19, 2012 at 12:44 PM, Alex Rønne Petersen
> <xtzgzorex@gmail.com>  wrote:
>> On 19-02-2012 15:41, Andrei Alexandrescu wrote:
>>>
>>> On 2/19/12 7:31 AM, Timon Gehr wrote:
>>>>
>>>> On 02/19/2012 09:26 AM, H. S. Teoh wrote:
>>>>>
>>>>> On Sat, Feb 18, 2012 at 11:52:00PM -0800, Jonathan M Davis wrote:
>>>>> [...]
>>>>>>
>>>>>> So, while at first glance, it seems like a good idea, I think that it
>>>>>> has too many issues as-is to work. It might be possible to adjust the
>>>>>> idea to make it workable though. Right now, it's possible to do it via
>>>>>> mixins or calling a function inside the catch, but doing something
>>>>>> similar to this would certainly be nice, assuming that we could sort
>>>>>> out the kinks.
>>>>>
>>>>> [...]
>>>>>
>>>>> I have an idea. What about "signature constraints" for catch, ala
>>>>> template signature constraints? Something like this:
>>>>>
>>>>> try {
>>>>> ...
>>>>> } catch(IOException e)
>>>>> if (e.errno in subsetYouWantToHandle)
>>>>> {
>>>>> ...
>>>>> }
>>>>>
>>>>> Just using IOException as an example. The idea is to allow arbitrary
>>>>> expressions in the constraint so whatever doesn't satisfy the constraint
>>>>> will be regarded as "not caught", even if the base type matches.
>>>>>
>>>>>
>>>>> T
>>>>>
>>>>
>>>> Nice.
>>>
>>>
>>> That helps. This quite nicely illustrates that types don't necessarily
>>> need to proliferate. Something not much more constraining can be done
>>> today:
>>>
>>> try {
>>> ...
>>> } catch(IOException e)
>>> {
>>> if (e.errno !in subsetYouWantToHandle) throw e;
>>> ...
>>> }
>>>
>>>
>>> Andrei
>>
>>
>> As I pointed out on the pull request, this is *evil*. It resets the stack
>> trace.
>>
>
> What? Is there a technical reason why throw resets the stack? Java
> doesn't work this way. In java the stack is created when the object
> Throwable is created:
>
> "A throwable contains a snapshot of the execution stack of its thread
> at the time it was created. It can also contain a message string that
> gives more information about the error. Finally, it can contain a
> cause: another throwable that caused this throwable to get thrown. The
> cause facility is new in release 1.4. It is also known as the chained
> exception facility, as the cause can, itself, have a cause, and so on,
> leading to a "chain" of exceptions, each caused by another. "
>
> We should consider changing this to work more like Java. This allows
> for patterns like:
>
> // Log the stack but don't throw
> auto e = new Exception();
> writefln(e.stack);
>
> Thanks,
> -Jose
>
>> --
>> - Alex

If Java really works that way, I'm sorry, but that just makes me think even worse of the language/VM.

If you create an exception object in some utility function (or chain of such), you don't want those in your stack trace. You want the stack trace to start from where you throw the object, not where you created it. Anything else is just confusing (and perhaps explains the several hundred lines long stack traces Java programs sometimes spit out...).

-- 
- Alex
February 19, 2012
Le 19/02/2012 15:41, Andrei Alexandrescu a écrit :
> On 2/19/12 7:31 AM, Timon Gehr wrote:
>> On 02/19/2012 09:26 AM, H. S. Teoh wrote:
>>> On Sat, Feb 18, 2012 at 11:52:00PM -0800, Jonathan M Davis wrote:
>>> [...]
>>>> So, while at first glance, it seems like a good idea, I think that it
>>>> has too many issues as-is to work. It might be possible to adjust the
>>>> idea to make it workable though. Right now, it's possible to do it via
>>>> mixins or calling a function inside the catch, but doing something
>>>> similar to this would certainly be nice, assuming that we could sort
>>>> out the kinks.
>>> [...]
>>>
>>> I have an idea. What about "signature constraints" for catch, ala
>>> template signature constraints? Something like this:
>>>
>>> try {
>>> ...
>>> } catch(IOException e)
>>> if (e.errno in subsetYouWantToHandle)
>>> {
>>> ...
>>> }
>>>
>>> Just using IOException as an example. The idea is to allow arbitrary
>>> expressions in the constraint so whatever doesn't satisfy the constraint
>>> will be regarded as "not caught", even if the base type matches.
>>>
>>>
>>> T
>>>
>>
>> Nice.
>
> That helps. This quite nicely illustrates that types don't necessarily
> need to proliferate. Something not much more constraining can be done
> today:
>
> try {
> ...
> } catch(IOException e)
> {
> if (e.errno !in subsetYouWantToHandle) throw e;
> ...
> }
>
>
> Andrei

This wouldn't work because you'll erase teh stack trace.

An alternative is to create a new exception and chain with e. You discussed that in TDPL already. But It is worse than creating new types of Exception IMO, because now, you ends up creating 2 Exceptions. And you introduce the risk of someone silenting Exception, something that you don't want !
February 19, 2012
On Sun, Feb 19, 2012 at 1:08 PM, Daniel Murphy <yebblies@nospamgmail.com> wrote:
> Are you sure about that?
>
> My understanding is java works the same way in terms of re-evaluating stack
> traces, except that it has
> 'throw;' which keeps the original intact, specifically for rethrowing.
>

Quoting the source of all Java truth ;): http://docs.oracle.com/javase/6/docs/api/java/lang/Throwable.html

I can't keep all this language semantic straight but it is my understanding that throw vs throw e is C++ and C# thing.

In Java if you want to reset the stack you need to create a new exception and chain the old one:

try {
  ...
} catch (Exception e) {
  throw new Exception(e);
}

> "Jose Armando Garcia" <jsancio@gmail.com> wrote in message news:mailman.601.1329663665.20196.digitalmars-d@puremagic.com... On Sun, Feb 19, 2012 at 12:44 PM, Alex Rønne Petersen <xtzgzorex@gmail.com> wrote:
>> On 19-02-2012 15:41, Andrei Alexandrescu wrote:
>>>
>>> On 2/19/12 7:31 AM, Timon Gehr wrote:
>>>>
>>>> On 02/19/2012 09:26 AM, H. S. Teoh wrote:
>>>>>
>>>>> On Sat, Feb 18, 2012 at 11:52:00PM -0800, Jonathan M Davis wrote: [...]
>>>>>>
>>>>>> So, while at first glance, it seems like a good idea, I think that it has too many issues as-is to work. It might be possible to adjust the idea to make it workable though. Right now, it's possible to do it via mixins or calling a function inside the catch, but doing something similar to this would certainly be nice, assuming that we could sort out the kinks.
>>>>>
>>>>> [...]
>>>>>
>>>>> I have an idea. What about "signature constraints" for catch, ala template signature constraints? Something like this:
>>>>>
>>>>> try {
>>>>> ...
>>>>> } catch(IOException e)
>>>>> if (e.errno in subsetYouWantToHandle)
>>>>> {
>>>>> ...
>>>>> }
>>>>>
>>>>> Just using IOException as an example. The idea is to allow arbitrary
>>>>> expressions in the constraint so whatever doesn't satisfy the
>>>>> constraint
>>>>> will be regarded as "not caught", even if the base type matches.
>>>>>
>>>>>
>>>>> T
>>>>>
>>>>
>>>> Nice.
>>>
>>>
>>> That helps. This quite nicely illustrates that types don't necessarily need to proliferate. Something not much more constraining can be done today:
>>>
>>> try {
>>> ...
>>> } catch(IOException e)
>>> {
>>> if (e.errno !in subsetYouWantToHandle) throw e;
>>> ...
>>> }
>>>
>>>
>>> Andrei
>>
>>
>> As I pointed out on the pull request, this is *evil*. It resets the stack trace.
>>
>
> What? Is there a technical reason why throw resets the stack? Java doesn't work this way. In java the stack is created when the object Throwable is created:
>
> "A throwable contains a snapshot of the execution stack of its thread at the time it was created. It can also contain a message string that gives more information about the error. Finally, it can contain a cause: another throwable that caused this throwable to get thrown. The cause facility is new in release 1.4. It is also known as the chained exception facility, as the cause can, itself, have a cause, and so on, leading to a "chain" of exceptions, each caused by another. "
>
> We should consider changing this to work more like Java. This allows for patterns like:
>
> // Log the stack but don't throw
> auto e = new Exception();
> writefln(e.stack);
>
> Thanks,
> -Jose
>
>> --
>> - Alex
>
>
February 19, 2012
On Sun, Feb 19, 2012 at 1:11 PM, Alex Rønne Petersen <xtzgzorex@gmail.com> wrote:
> On 19-02-2012 16:00, Jose Armando Garcia wrote:
>>
>> On Sun, Feb 19, 2012 at 12:44 PM, Alex Rønne Petersen <xtzgzorex@gmail.com>  wrote:
>>>
>>> On 19-02-2012 15:41, Andrei Alexandrescu wrote:
>>>>
>>>>
>>>> On 2/19/12 7:31 AM, Timon Gehr wrote:
>>>>>
>>>>>
>>>>> On 02/19/2012 09:26 AM, H. S. Teoh wrote:
>>>>>>
>>>>>>
>>>>>> On Sat, Feb 18, 2012 at 11:52:00PM -0800, Jonathan M Davis wrote: [...]
>>>>>>>
>>>>>>>
>>>>>>> So, while at first glance, it seems like a good idea, I think that it
>>>>>>> has too many issues as-is to work. It might be possible to adjust the
>>>>>>> idea to make it workable though. Right now, it's possible to do it
>>>>>>> via
>>>>>>> mixins or calling a function inside the catch, but doing something
>>>>>>> similar to this would certainly be nice, assuming that we could sort
>>>>>>> out the kinks.
>>>>>>
>>>>>>
>>>>>> [...]
>>>>>>
>>>>>> I have an idea. What about "signature constraints" for catch, ala template signature constraints? Something like this:
>>>>>>
>>>>>> try {
>>>>>> ...
>>>>>> } catch(IOException e)
>>>>>> if (e.errno in subsetYouWantToHandle)
>>>>>> {
>>>>>> ...
>>>>>> }
>>>>>>
>>>>>> Just using IOException as an example. The idea is to allow arbitrary
>>>>>> expressions in the constraint so whatever doesn't satisfy the
>>>>>> constraint
>>>>>> will be regarded as "not caught", even if the base type matches.
>>>>>>
>>>>>>
>>>>>> T
>>>>>>
>>>>>
>>>>> Nice.
>>>>
>>>>
>>>>
>>>> That helps. This quite nicely illustrates that types don't necessarily need to proliferate. Something not much more constraining can be done today:
>>>>
>>>> try {
>>>> ...
>>>> } catch(IOException e)
>>>> {
>>>> if (e.errno !in subsetYouWantToHandle) throw e;
>>>> ...
>>>> }
>>>>
>>>>
>>>> Andrei
>>>
>>>
>>>
>>> As I pointed out on the pull request, this is *evil*. It resets the stack trace.
>>>
>>
>> What? Is there a technical reason why throw resets the stack? Java doesn't work this way. In java the stack is created when the object Throwable is created:
>>
>> "A throwable contains a snapshot of the execution stack of its thread at the time it was created. It can also contain a message string that gives more information about the error. Finally, it can contain a cause: another throwable that caused this throwable to get thrown. The cause facility is new in release 1.4. It is also known as the chained exception facility, as the cause can, itself, have a cause, and so on, leading to a "chain" of exceptions, each caused by another. "
>>
>> We should consider changing this to work more like Java. This allows for patterns like:
>>
>> // Log the stack but don't throw
>> auto e = new Exception();
>> writefln(e.stack);
>>
>> Thanks,
>> -Jose
>>
>>> --
>>> - Alex
>
>
> If Java really works that way, I'm sorry, but that just makes me think even worse of the language/VM.
>
> If you create an exception object in some utility function (or chain of such), you don't want those in your stack trace. You want the stack trace to start from where you throw the object, not where you created it. Anything else is just confusing (and perhaps explains the several hundred lines long stack traces Java programs sometimes spit out...).
>

Proof is in the code:

public final class TextException {

	public static void main(String[] args) {
       try {
    	   throwException();
       } catch (Exception e) {
    	   e.printStackTrace();
       }
	}

	private static void throwException() {
		throw pushStack(3);
	}

	private static RuntimeException pushStack(int i) {
		if (i > 0) return pushStack(i-1);
		else return new RuntimeException();
	}
}

Output:
java.lang.RuntimeException
	at TextException.pushStack(TextException.java:18)
	at TextException.pushStack(TextException.java:17)
	at TextException.pushStack(TextException.java:17)
	at TextException.pushStack(TextException.java:17)
	at TextException.throwException(TextException.java:13)
	at TextException.main(TextException.java:6)

> --
> - Alex
February 19, 2012
Ah, I was probably thinking of C#


February 19, 2012
On Sun, Feb 19, 2012 at 1:11 PM, Alex Rønne Petersen <xtzgzorex@gmail.com> wrote:
> On 19-02-2012 16:00, Jose Armando Garcia wrote:
>>
>> On Sun, Feb 19, 2012 at 12:44 PM, Alex Rønne Petersen <xtzgzorex@gmail.com>  wrote:
>>>
>>> On 19-02-2012 15:41, Andrei Alexandrescu wrote:
>>>>
>>>>
>>>> On 2/19/12 7:31 AM, Timon Gehr wrote:
>>>>>
>>>>>
>>>>> On 02/19/2012 09:26 AM, H. S. Teoh wrote:
>>>>>>
>>>>>>
>>>>>> On Sat, Feb 18, 2012 at 11:52:00PM -0800, Jonathan M Davis wrote: [...]
>>>>>>>
>>>>>>>
>>>>>>> So, while at first glance, it seems like a good idea, I think that it
>>>>>>> has too many issues as-is to work. It might be possible to adjust the
>>>>>>> idea to make it workable though. Right now, it's possible to do it
>>>>>>> via
>>>>>>> mixins or calling a function inside the catch, but doing something
>>>>>>> similar to this would certainly be nice, assuming that we could sort
>>>>>>> out the kinks.
>>>>>>
>>>>>>
>>>>>> [...]
>>>>>>
>>>>>> I have an idea. What about "signature constraints" for catch, ala template signature constraints? Something like this:
>>>>>>
>>>>>> try {
>>>>>> ...
>>>>>> } catch(IOException e)
>>>>>> if (e.errno in subsetYouWantToHandle)
>>>>>> {
>>>>>> ...
>>>>>> }
>>>>>>
>>>>>> Just using IOException as an example. The idea is to allow arbitrary
>>>>>> expressions in the constraint so whatever doesn't satisfy the
>>>>>> constraint
>>>>>> will be regarded as "not caught", even if the base type matches.
>>>>>>
>>>>>>
>>>>>> T
>>>>>>
>>>>>
>>>>> Nice.
>>>>
>>>>
>>>>
>>>> That helps. This quite nicely illustrates that types don't necessarily need to proliferate. Something not much more constraining can be done today:
>>>>
>>>> try {
>>>> ...
>>>> } catch(IOException e)
>>>> {
>>>> if (e.errno !in subsetYouWantToHandle) throw e;
>>>> ...
>>>> }
>>>>
>>>>
>>>> Andrei
>>>
>>>
>>>
>>> As I pointed out on the pull request, this is *evil*. It resets the stack trace.
>>>
>>
>> What? Is there a technical reason why throw resets the stack? Java doesn't work this way. In java the stack is created when the object Throwable is created:
>>
>> "A throwable contains a snapshot of the execution stack of its thread at the time it was created. It can also contain a message string that gives more information about the error. Finally, it can contain a cause: another throwable that caused this throwable to get thrown. The cause facility is new in release 1.4. It is also known as the chained exception facility, as the cause can, itself, have a cause, and so on, leading to a "chain" of exceptions, each caused by another. "
>>
>> We should consider changing this to work more like Java. This allows for patterns like:
>>
>> // Log the stack but don't throw
>> auto e = new Exception();
>> writefln(e.stack);
>>
>> Thanks,
>> -Jose
>>
>>> --
>>> - Alex
>
>
> If Java really works that way, I'm sorry, but that just makes me think even worse of the language/VM.
>
> If you create an exception object in some utility function (or chain of such), you don't want those in your stack trace. You want the stack trace to start from where you throw the object, not where you created it. Anything else is just confusing (and perhaps explains the several hundred lines long stack traces Java programs sometimes spit out...).
>

Unless you want the Exception object to be immutable which I think it should be.

> --
> - Alex
February 19, 2012
Well, since keys would be string, you can define them at the base class.
So, FileException can define a few detail names that you know are used in its derived classes. And so, Exception can define detail names that are standard for all classes.

So it would look like:

class FileException {
    [..]
    static immutable details_filename = "filename";
    static immutable details_ispipe = "ispipe";
    [..]
}

class Exception {
    [..]
    static immutable details_transient = "transient";
    static immutable details_i18n_name = "i18n_name";
    [..]
}


So, you *know* that a portion of the tree supports certain details in the associative array, when you type the dot after the exception class name in an IDE with autocomplete, (or ctrl-N in Vim with the definition open ;-) ).
And you can document with ddoc those static variables. So the example would be now:

For instance:

 ...
 catch (Exception ex) {
     if (Exception.details_i18n_name in ex.details) {
         log(translate(ex.details[Exception.details_i18n_name]));
     }
     if (FileException.details_filename in ex.details) {
         log("This file is trouble: "
             ~ ex.details[FileException.details_filename]);
     }
     if (Exception.details_transient in ex.details) {
         repeatOneMoreTime();
     }
 }
 ...




On Sunday, 19 February 2012 at 14:54:29 UTC, Jacob Carlborg wrote:
> On 2012-02-19 13:27, Juan Manuel Cabo wrote:
>> How about adding a string[string] or a variant[string] to the Exception
>> class, so one can know details about the subclassed exception without
>> downcasting? How ugly would that be?
>>
>> For instance:
>>
>> ...
>> catch (Exception ex) {
>> if ("transient" in ex.details) {
>> repeatOneMoreTime();
>> }
>> if ("i18n_code" in ex.details) {
>> log(translate(ex.details["i18n_code"]));
>> }
>> }
>> ...
>>
>> Details can be standard by convention or otherwise custom.
>> (I can see that this can lead to messy proliferation of details, but at
>> least solves most of the issues).
>
> How would you know which keys are available in "ex.details", documentation?


February 19, 2012
On 2/19/12 8:54 AM, Jacob Carlborg wrote:
> On 2012-02-19 13:27, Juan Manuel Cabo wrote:
>> How about adding a string[string] or a variant[string] to the Exception
>> class, so one can know details about the subclassed exception without
>> downcasting? How ugly would that be?
>>
>> For instance:
>>
>> ...
>> catch (Exception ex) {
>> if ("transient" in ex.details) {
>> repeatOneMoreTime();
>> }
>> if ("i18n_code" in ex.details) {
>> log(translate(ex.details["i18n_code"]));
>> }
>> }
>> ...
>>
>> Details can be standard by convention or otherwise custom.
>> (I can see that this can lead to messy proliferation of details, but at
>> least solves most of the issues).
>
> How would you know which keys are available in "ex.details", documentation?

Programmatically, too. A string templating engine would take the table and format it for the appropriate language.

Andrei