February 20, 2012
Le 20/02/2012 21:17, Nick Sabalausky a écrit :
> *However*, I think that:
>
> 1. That's an insufficient improvement to justify breaking the ultra-common
> "throw new NameOfException(args)" idiom.
>
> 2. The solution fails to cover the *entire* scope of the *real* problem:
> Classes that need to write boilerplate ctors which merely forward to the
> base class's ctors.  This issue is *not* limited to Exceptions, but Andrei's
> proposes solution *only* covers the case with Exceptions.
>
> A better solution has already been proposed:
>
>      class AcmeException : Exception
>      {
>          mixin inheritCtors!();  // Actual name open for bikeshedding
>      }
>
> Now, yes, this *is* admittedly more boilerplate than:
>
>      class AcmeException : Exception {}
>

On IRC we discussed the following solution : class with no defined ctor get default ctor forwarding argument to parent's ctor. If one is defined, this default behaviour disapear.

People were entusiasts about that. But I think we should discuss that in another thread.
February 20, 2012
On Monday, February 20, 2012 17:31:28 Juan Manuel Cabo wrote:
> > ...
> > Sure. Again, this is not advocating replacement of exception hierarchies
> > with tables! ...
> > 
> > Andrei
> 
> I think that the case of rethrowing an exception with added detail is the
> worst enemy of clean Exception hierarchies.
> The idea of Variant[string] remedies that case without creating a new
> exception class just for the added fields. If that case is solved, then the
> tipical need for creating new exception types that don't really aid
> selecting them for catching and recovery is solved too.

Having derived exceptions with additional information is a _huge_ boon, and I contend that it's vasty better with variant, which would be highly error prone, because it's not properly statically checked. Changes to what's put in the variant could kill code at runtime - code which by its very definiton is not supposed to be the normal code path, so you're less likely to actually run into the problem before you ship your product. Whereas with the information in actual member variables, if they get changed, you get a compilation error, and you know that you have to fix your code.

Rethrowing is a separate issue. And in many cases, the correct thing to do is to chain exceptions. You catch one, do something with it, and then you throw a new one which took the first one as an argument. Then you get both. That functionality is already built into Exception.

- Jonathan M Davis
February 20, 2012
On 2/20/12 1:41 PM, Sean Kelly wrote:
> Localized error messages are typically generated by a localization
> team and placed in some sort of a lookup table, indexed by language
> and error code.  Say the code is roughly like this:
>
> displayLocalizedError(Exception e) { auto t =
> loadTable(e.info["lang"]); // info["lang"] returns "ja" for japanese,
> etc. string m = t.findMessage(typeid(e).toString);
> writeln(buildLocalizedMessage(m, e.info)); }

I'd amend your example a bit as follows:

displayLocalizedError(Exception e) {
    auto t = loadTable(g_lang); // g_lang contains "ja" for japanese, etc.
    string m = t.findMessage(typeid(e).toString);
    writeln(buildLocalizedMessage(m, e.info));
}

I mean the exception has no notion of "lang"uage.

> Where m (in english) may be something like:
>
> "Saving to {LocationType} {!LocationName} failed because the
> destination is full."
>
> The message is parsed and when {LocalizationType} is encountered, the
> parser knows to replace it with another localized string indexed by
> "LocationType".  Then {!LocationName} is replaced by
> e.info["LocationName"], which is specific to the actual error that
> occurred.  In essence, each line that has to be localized has a
> monetary (and time) cost for doing so, so error lines are reused when
> possible.  Then specifics that may or may not themselves be localized
> are potentially pasted in to generate the final message.

Yup, yup, and yup.


Andrei
February 20, 2012
> That's a very interesting angle!
>
> Andrei

Thanks!!

The main point I was making is, that otherwise, a user would be forced
to create a new exception kind and chain the original exception
to it. Now... what about the catch blocks defined upstream in
the call tree?
So this solves that then. The code upstream can still make a
  catch (FileNotFound)  that obviously distinguishes
FileNotFound from other exception types. Otherwise,
if all one does is ie: COMExceptions that chain other exceptions,
the distinction is lost, and rethrows mess everything.

--jm


On 02/20/2012 05:49 PM, Andrei Alexandrescu wrote:
> On 2/20/12 1:32 PM, Juan Manuel Cabo wrote:
>> So, if your boss wants the URL of the request that was made when the standard library threw you a FileNotFoundException, you can do:
>>
>>
>>     try {
>>           ...
>>          } catch (Exception ex) {
>>                  //Rethrow the exception with the added detail:
>>         ex.details["custom_url"] = getenv("URI");
>>                  throw ex;
>>          }
> 
> That's a very interesting angle!
> 
> Andrei
> 
> 

February 20, 2012
On Mon, Feb 20, 2012 at 02:46:52PM -0600, Andrei Alexandrescu wrote:
> On 2/20/12 1:17 PM, Juan Manuel Cabo wrote:
> >I like the idea!
> >
> >Remember please for anyone reading: Use positional arguments in format strings.
> 
> Not positional, but instead Symbolic is the way.
[...]

+1.

Nothing worse than a format string like this:

	"{0}:{1} {2} occurred in {3} {4}: {5}"

Much better is:

	"${srcfile}:${linenum} ${errortype} occurred in ${objecttype}
	${objectname}: ${detailmsg}"


T

-- 
It is the quality rather than the quantity that matters. -- Lucius Annaeus Seneca
February 20, 2012
I meant more that by ignoring the type matching system in favor of our own runtime convention we've prevented the compiler from doing any optimizations (or error checking) that may have been possible.

On Feb 20, 2012, at 12:15 PM, Juan Manuel Cabo wrote:

> I agree to disagree.
> 
> But about your argument for efficiency, any check that you do when examining an exception doesn't need to be lightning fast, after all, if you are looking at an exception object, it means that the stack got unwound, and any nano seconds that you spend doing this:
> 
> 	catch (Exception ex) {
> 		if ("mycustomfield" in ex) {
> 			.. do something ..
> 		}
> 	}
> 
> which is just an "in" check in an associative array, which might never
> have more than 10 elements (so even linear search is appropiate),
> is overshadowed by the time that the runtime took to unwind the stack
> and serve the exception to your catch block.
> 
> --jm
> 
> 
> On 02/20/2012 05:05 PM, Sean Kelly wrote:
>> On Feb 20, 2012, at 11:54 AM, Juan Manuel Cabo wrote:
>> 
>>> About this part:
>>> 
>>>>> What you want is throw a COMException and link it to the original Exception. You have to consider Exception as a linkedlist, one being the cause of another.
>>> 
>>> The Variant[string] is an idea to help avoid people creating new kinds of exception types that don't add nothing.
>> 
>> I don't think this makes sense.  To effectively use whatever's in the table I pretty much have to know what error I'm handling, and this isn't possible if type information is lost.  Unless this determination is moved to a run-time check of some field within the exception, and then I'm making my code that much messier and less efficient by putting in tests of this identifier against a list of constants.  Personally, I don't see any use for this table beyond providing context, much like we already have with file, line, etc.
> 

February 20, 2012
On 2/20/12 1:45 PM, Jonathan M Davis wrote:
> On Monday, February 20, 2012 20:42:28 deadalnix wrote:
>> Le 20/02/2012 20:27, Jonathan M Davis a écrit :
>>> On Monday, February 20, 2012 11:15:08 H. S. Teoh wrote:
>>>> That's why I proposed to use runtime reflection to scan the exception
>>>> object for applicable fields. Then you get the best of both worlds: the
>>>> message formatter doesn't need to know what the fields are, and you get
>>>> full compile-time type checking for catching code that directly accesses
>>>> the fields.
>>>
>>> That would certainly be better.
>>>
>>> - Jonathan M Davis
>>
>> This is way better than Variant[string], but unimplemented ATM.
>
> Yes, but you can use compile-time constructs to generate it. And as you
> pointed out in another post, tupleof should do the trick. Regardless, the
> point is that using reflection of some kind is a much better solution than
> using variant.

Agreed. Ideally adding a sort of mixin to any class would enable it for advanced run-time information:

class DRoxException : Exception
{
    mixin(enableRTTI);
    ... normal implementation ...
}


Andrei


February 20, 2012
Le 20/02/2012 21:49, Andrei Alexandrescu a écrit :
> On 2/20/12 1:32 PM, Juan Manuel Cabo wrote:
>> So, if your boss wants the URL of the request that was made
>> when the standard library threw you a FileNotFoundException,
>> you can do:
>>
>>
>> try {
>> ...
>> } catch (Exception ex) {
>> //Rethrow the exception with the added detail:
>> ex.details["custom_url"] = getenv("URI");
>> throw ex;
>> }
>
> That's a very interesting angle!
>
> Andrei
>
>

That is terrible. If ones begin to do this, then you cannot rely on what you'll find in the Exception infos.

And if people start to do that before any code is writen, It is very bad sign.
February 20, 2012
On 2/20/12 2:01 PM, foobar wrote:
> Seconded. Reflection seems a much better solution for this.

Absolutely.

> The i18n table would map (exception type) -> (language, format string)
> and the i18n formatter would use reflection to map field values to the
> format string.
> a format string would be e.g. "File {filename} not found" and the
> formatter would replace {filename} with e.class.getField("filename").
>
> This does not require any modifications to the exception mechanism.

Yah, but the reflection engine would have to present RTTI in a uniform manner... such as, Variant[string]. Bane of my life: I'm always right :o).


Andrei
February 20, 2012
On 2/20/12 2:10 PM, Juan Manuel Cabo wrote:
> With all due respect, I don't see module exception categories
> as something good for the categorization of exceptions.

Yah, that's been since destroyed. Bane of my life: I'm never right :o).

Andrei