February 20, 2012
On 2/20/12 11:55 AM, deadalnix wrote:
> Le 20/02/2012 18:11, Andrei Alexandrescu a écrit :
>> On 2/20/12 11:05 AM, foobar wrote:
>>> On Monday, 20 February 2012 at 16:37:28 UTC, Andrei Alexandrescu wrote:
>>>> On 2/20/12 10:16 AM, Nick Sabalausky wrote:
>>>>> "Andrei Alexandrescu"<SeeWebsiteForEmail@erdani.org> wrote in message
>>>>> news:jhtq31$u8q$1@digitalmars.com...
>>>>>>
>>>>>> Again, I think this thread clarified we need the "Variant[string]
>>>>>> info;"
>>>>>> member however we define the hierarchy.
>>>>>>
>>>>>
>>>>> I disagree. I don't see a need for that.
>>>>
>>>> How would we address custom formatting of e.g. error messages?
>>>>
>>>> Andrei
>>>
>>> Separation of concerns - exceptions are meant to notify the *developer*
>>> of errors. User facing error messages is a separate concern that
>>> exceptions should not be responsible for. it's not just outsourcing the
>>> translation strings, it's the developer's job to determine what if at
>>> all should be done with the exception.
>>
>> At the end of the day, a human-readable error message must be properly
>> formatted given some exception that signaled an error. So I disagree
>> that exceptions are meant for the developer. They are mechanism, a means
>> to an end.
>>
>>> Trivial example: My mom enters a misspelled URL (e.g. goggle.com) in her
>>> browser, she does not know or care what 404 means. instead she gets a
>>> formated page suggesting her to check her spelling and probably a
>>> suggestion to try google.com instead.
>>
>> Sure, and the question is how the message gets created.
>>
>>> the exception notifies the developer of the error, the developer does
>>> extra processing (e.g. to suggest similar valid websites) and the user
>>> get a friendly notification. clearly it doesn't make sense to put all
>>> this into the exception.
>>
>> That extra processing must format the message given the information
>> passed by the exception. _Definitely_ it doesn't make sense to put the
>> formatting processing in the exception. That's why shipping the
>> information outside the exception in a generic format is necessary,
>> hence the Variant[string].
>>
>>
>> Andrei
>
> And so variant is the way to go ?
>
> Clearly, this is a very strong arguement in favor of typed Exception,
> that provide usefull information about what went wrong. This is a safe
> approach.

This does not pit typed exceptions against uniform interfaces. The hash simply provides information in a uniform format across exception types. That way, code that needs to extract and format information in a generic manner can be written in one place.

> Because this Variant stuff is going to require massive ducktyping of
> Exceptions, with all possible errors involved. The keys in the
> Variant[string] will depend on the Exception the dev is facing. This
> should be avoided and should warn us about the requirement of typed
> Exceptions.

I agree. Again, this is not one against the other.


Andrei
February 20, 2012
On Mon, Feb 20, 2012 at 06:55:13PM +0100, deadalnix wrote:
> Le 20/02/2012 18:11, Andrei Alexandrescu a écrit :
[...]
> >That extra processing must format the message given the information passed by the exception. _Definitely_ it doesn't make sense to put the formatting processing in the exception. That's why shipping the information outside the exception in a generic format is necessary, hence the Variant[string].
> >
> >
> >Andrei
> 
> And so variant is the way to go ?
> 
> Clearly, this is a very strong arguement in favor of typed Exception, that provide usefull information about what went wrong.  This is a safe approach.
> 
> Because this Variant stuff is going to require massive ducktyping of Exceptions, with all possible errors involved. The keys in the Variant[string] will depend on the Exception the dev is facing. This should be avoided and should warn us about the requirement of typed Exceptions.

Exactly! Just because you use a Variant doesn't magically free you from needing to know what exactly is that exception that you caught in the first place. To make any sense of what's stored in the Variant, you still have to know what is the exception type, and based on the type interpret the Variant. So you end up with:

	catch(Exception e) {
		switch(e.type) {
			case BlahException:
				handleBlahException(e.data.blah_info);
				break;
			case BlehException:
				handleBlehException(e.data.bleh_info);
				break;
			case BluhException:
				handleBluhException(e.data.bluh_info);
				break;
			...
		}
	}

which is exactly the kind of ugliness that class hierarchies were invented to solve.


T

-- 
ASCII stupid question, getty stupid ANSI.
February 20, 2012
On 2/20/12 11:28 AM, Jose Armando Garcia wrote:
> On Mon, Feb 20, 2012 at 2:37 PM, Andrei Alexandrescu
> <SeeWebsiteForEmail@erdani.org <mailto:SeeWebsiteForEmail@erdani.org>>
> wrote:
>
>     On 2/20/12 10:16 AM, Nick Sabalausky wrote:
>
>         "Andrei Alexandrescu"<SeeWebsiteForEma__il@erdani.org
>         <mailto:SeeWebsiteForEmail@erdani.org>>  wrote in message
>         news:jhtq31$u8q$1@digitalmars.__com...
>
>
>             Again, I think this thread clarified we need the
>             "Variant[string] info;"
>             member however we define the hierarchy.
>
>
>         I disagree. I don't see a need for that.
>
>
>     How would we address custom formatting of e.g. error messages?
>
>
> This may not be D. Gettext says to solve it as follow:
>
> throw new Exception(gettext("Cool English message at
> %s.").format(DateTime.now()))
>
> The gettext "compiler" goes through the code an generates all the
> strings that need to be localized. The translation teams modifies those
> string and you store them in file/map for that language. At runtime the
> i18n library turns gettext(...) into a query into that map and returns
> the actual localized string. There is a map for the entire process.
>
> Localization can also be disable at compile time by making gettext a
> template and generating a "noop" for that operation.

So this moves formatting from the catch point to the throw point. That's fine, but it forces the formatting effort upfront even when the message is not actually used and leads to duplication because each call site would need to provide the message entirely. I think it's worth investigating formatting at the catch site.

> I have been thinking of making a module for i18n model after gettext but
> taking advantage of D's language features. Is there some interest in this?

Yah, this would be of interest.


Andrei
February 20, 2012
Am 20.02.2012 17:36, schrieb Andrei Alexandrescu:
> I understand this seems loose, but again, when you want to do custom
> formatting or i18n this is the way to go. The job of rendering the
> exception as a string must be outsourced (heh) outside the exception,
> and Variant[string] is a simple mechanism to do so.
>
> Andrei
>
>

it is loose and Variant[string] is a simple mechanism for data transport, but evil in form of compile-time checks, the complete signature of your information is then (per se) only runtime-checked, how to prevent difference in the info[] filling and info[] usage over time? i just mistyped my key, removed a key, used a different, etc... multiply that by the amount of needed Exceptions and their info-key-variants ... hell on earth

in the end you will have a bunch of modules wich const-string-keys for the exception creation and rendering, and then i don't see any real difference to a specialize exception
February 20, 2012
Le 20/02/2012 19:02, Andrei Alexandrescu a écrit :
> On 2/20/12 11:28 AM, Jose Armando Garcia wrote:
>> On Mon, Feb 20, 2012 at 2:37 PM, Andrei Alexandrescu
>> <SeeWebsiteForEmail@erdani.org <mailto:SeeWebsiteForEmail@erdani.org>>
>> wrote:
>>
>> On 2/20/12 10:16 AM, Nick Sabalausky wrote:
>>
>> "Andrei Alexandrescu"<SeeWebsiteForEma__il@erdani.org
>> <mailto:SeeWebsiteForEmail@erdani.org>> wrote in message
>> news:jhtq31$u8q$1@digitalmars.__com...
>>
>>
>> Again, I think this thread clarified we need the
>> "Variant[string] info;"
>> member however we define the hierarchy.
>>
>>
>> I disagree. I don't see a need for that.
>>
>>
>> How would we address custom formatting of e.g. error messages?
>>
>>
>> This may not be D. Gettext says to solve it as follow:
>>
>> throw new Exception(gettext("Cool English message at
>> %s.").format(DateTime.now()))
>>
>> The gettext "compiler" goes through the code an generates all the
>> strings that need to be localized. The translation teams modifies those
>> string and you store them in file/map for that language. At runtime the
>> i18n library turns gettext(...) into a query into that map and returns
>> the actual localized string. There is a map for the entire process.
>>
>> Localization can also be disable at compile time by making gettext a
>> template and generating a "noop" for that operation.
>
> So this moves formatting from the catch point to the throw point. That's
> fine, but it forces the formatting effort upfront even when the message
> is not actually used and leads to duplication because each call site
> would need to provide the message entirely. I think it's worth
> investigating formatting at the catch site.
>

This is not the way we want to go. You have a piece of code to describe what the problem is, another to descide what to do with that problem and again another to do something that may go wrong.

Formatting is an error handling problem, and so formatting at the throw point is a bad separation of concerns.

Plus, the way you want to format stuff is likely to depend on the application.
February 20, 2012
Am 20.02.2012 19:02, schrieb H. S. Teoh:
> Exactly! Just because you use a Variant doesn't magically free you from
> needing to know what exactly is that exception that you caught in the
> first place. To make any sense of what's stored in the Variant, you
> still have to know what is the exception type, and based on the type
> interpret the Variant. So you end up with:
>
> 	catch(Exception e) {
> 		switch(e.type) {
> 			case BlahException:
> 				handleBlahException(e.data.blah_info);
> 				break;
> 			case BlehException:
> 				handleBlehException(e.data.bleh_info);
> 				break;
> 			case BluhException:
> 				handleBluhException(e.data.bluh_info);
> 				break;
> 			...
> 		}
> 	}

Thx Teoh - i also don't know how Andreis Variant[string] would help here in any way
February 20, 2012
On Mon, Feb 20, 2012 at 12:02:21PM -0600, Andrei Alexandrescu wrote:
> On 2/20/12 11:28 AM, Jose Armando Garcia wrote:
[...]
> >This may not be D. Gettext says to solve it as follow:
> >
> >throw new Exception(gettext("Cool English message at
> >%s.").format(DateTime.now()))
> >
> >The gettext "compiler" goes through the code an generates all the strings that need to be localized. The translation teams modifies those string and you store them in file/map for that language. At runtime the i18n library turns gettext(...) into a query into that map and returns the actual localized string. There is a map for the entire process.
> >
> >Localization can also be disable at compile time by making gettext a template and generating a "noop" for that operation.
> 
> So this moves formatting from the catch point to the throw point. That's fine, but it forces the formatting effort upfront even when the message is not actually used and leads to duplication because each call site would need to provide the message entirely. I think it's worth investigating formatting at the catch site.

Ah, I see what you're getting at. What about this then:

	class MyException : Exception {
		int info1;
		string info2;
		...

		// class Exception would provide a default formatMsg()
		// that simply prints Exception.msg, perhaps also with
		// translation.
		override string formatMsg(LocaleInfo li) {
			return formatI18n(li, "...", info1, info2, ...);
		}
	}

This way, the catcher doesn't have to know anything about info1, info2, ..., unless it specifically wants to catch MyException and do error recovery based on info1, info2, ... etc.. And the formatting isn't actually done until it's needed. The thrower only sets info1, info2, ..., only when the catcher wants a human-readable message out of it, it will call formatMsg().


> >I have been thinking of making a module for i18n model after gettext but taking advantage of D's language features. Is there some interest in this?
> 
> Yah, this would be of interest.
[...]

Seconded.


T

-- 
I'm still trying to find a pun for "punishment"...
February 20, 2012
On 2/20/12 11:56 AM, H. S. Teoh wrote:
> On Mon, Feb 20, 2012 at 11:11:08AM -0600, Andrei Alexandrescu wrote:
>> On 2/20/12 11:05 AM, foobar wrote:
> [...]
>>> Separation of concerns - exceptions are meant to notify the
>>> *developer* of errors. User facing error messages is a separate
>>> concern that exceptions should not be responsible for. it's not just
>>> outsourcing the translation strings, it's the developer's job to
>>> determine what if at all should be done with the exception.
>>
>> At the end of the day, a human-readable error message must be properly
>> formatted given some exception that signaled an error. So I disagree
>> that exceptions are meant for the developer. They are mechanism, a
>> means to an end.
>
> No, exceptions *are* meant for the developer, because it's the developer
> who decides whether and how to to display it to the user.

And when she does decide so, isn't it desirable that the exception hierarchy provides good means to do so?

>>> Trivial example: My mom enters a misspelled URL (e.g. goggle.com) in
>>> her browser, she does not know or care what 404 means. instead she
>>> gets a formated page suggesting her to check her spelling and
>>> probably a suggestion to try google.com instead.
>>
>> Sure, and the question is how the message gets created.
>
> By encoding *useful* information in the exception, not just some generic
> stuff lacking in semantic meaning, so that the code that catches the
> exception knows what the problem is, and can make a sensible decision as
> to how to display it (or not display it, but react in some other way).

Sure. But to the extent the exception hierarchy can serve a helpful interface, that would only help.

> Again, this brings us back to class hierarchies. In order to react
> sensibly to an exception, the code that catches it *has* to know what it
> is.

Often code has a generic response to all exceptions or categories thereof.

> There's simply no way around this. Just saying "a problem happened"
> is unhelpful.

Of course. That's why it's worth looking into enhancing the functionality of the exception hierarchy. It's a classic of OO design: if you want reuse, push policy up.

> Code cannot divine the right course of action just by
> being told that a problem happened. It *needs* to know *what* happened.
> And the details of what happened depends entirely on the context in
> which it happened, so the most sensible solution is to use a class
> hierarchy where you add information to the bottom levels -- that's
> because that's where the information is!!

I don't think the details depend entirely on the context. Some aspects depend on the origin of the error, and some others depend on the context in which the error occurred. Both are needed.

> At the end of the day, using a Variant is no better than using a deep
> class hierarchy.

It is better because it pushes policy up and replaces formatting code duplicated across catch sites, with reusable table-based code.

> You're just encoding the exact same structure of
> information in a different way.

Yes. It's a way that is uniform, which makes it possible to push in the base class.

> You *still* have to know what kind of
> information is available in the Variant, just like you need to know
> which exception subclass to catch so that you can access the member
> variable that tells you what went wrong.

Yes. That's where the formatting template comes together with the concrete information.

> For user-facing code, you *need* the catching code to understand what
> kinds of exceptions can happen so that it can decide whether/how to
> display it to the user.

That doesn't contradict, prevent, or preclude designing class hierarchies for uniform interfaces.

> In this light, it doesn't make sense to have a fully generic,
> full-fledged i18n system encoded into Exception (i.e., into every single
> error the system might encounter).

Of course not. I'm just discussing adding interface to enable that possibility (and others).

> Only a tiny subset of exceptions even
> *need* to see the light of day, and require i18n.

Agreed.

> You're just reinventing class hierarchies using variants. To what end?

I don't think so. What happens here is simple OO design - pushing interface up so as to allow manipulation of bases instead of duplicating code dealing with concrete classes.

Maybe this is all a misunderstanding. Allow me to explain what the intent is. I suggest we add a method (better than a member, upon further thinking):

class Exception : Error
{
    Variant[string] info()
    {
        return null; // no extra info here
    }
    ...
}

Classes that inherit Exception may override info:

class GetOptException : Exception
{
    Variant[string] info()
    {
        return [ "flag" : _flag ];
    }
    ...
    string _flag;
}

Now code that wants to handle GetOptException specifically can definitely do so. The advantage of defining info() is that now we get to write code that does not need duplication across all concrete types, but instead gets to use Exception.info in conjunction with various formatting and rendering engines. Again, it's simple OO design.


Andrei
February 20, 2012
On Monday, February 20, 2012 18:05:38 foobar wrote:
> Separation of concerns - exceptions are meant to notify the *developer* of errors. User facing error messages is a separate concern that exceptions should not be responsible for. it's not just outsourcing the translation strings, it's the developer's job to determine what if at all should be done with the exception.

Agreed. Users shouldn't be seeing exception messages. They are intended for the developer. Users don't know or care about them. You don't display error codes to users when something goes wrong do you?

The point of exceptions is to allow the _program_ to react appropriately. In some cases, that means printing out a message to the user or popping up a dialogue. In many, it doesn't. We need exceptions to give the program the information that it needs to programmatically react to what went wrong, not print a nice, internationalized error message. And adding an internationalization mechanism would actually make things _worse_, because it complicates exceptions for something that they don't generally need, and it makes debugging harder, because you can't see the message as easily in the debugger.

The fields and functions that exceptions have should be geared towards facilitating the program processing and recovering from the exception, not printing out error messages. And a big part of that is giving them fields which can be processed programmatically, not ways to print internationalized strings.

- Jonathan M Davis
February 20, 2012
On 2/20/12 12:02 PM, H. S. Teoh wrote:
> On Mon, Feb 20, 2012 at 06:55:13PM +0100, deadalnix wrote:
>> Le 20/02/2012 18:11, Andrei Alexandrescu a écrit :
> [...]
>>> That extra processing must format the message given the information
>>> passed by the exception. _Definitely_ it doesn't make sense to put
>>> the formatting processing in the exception. That's why shipping the
>>> information outside the exception in a generic format is necessary,
>>> hence the Variant[string].
>>>
>>>
>>> Andrei
>>
>> And so variant is the way to go ?
>>
>> Clearly, this is a very strong arguement in favor of typed Exception,
>> that provide usefull information about what went wrong.  This is a
>> safe approach.
>>
>> Because this Variant stuff is going to require massive ducktyping of
>> Exceptions, with all possible errors involved. The keys in the
>> Variant[string] will depend on the Exception the dev is facing. This
>> should be avoided and should warn us about the requirement of typed
>> Exceptions.
>
> Exactly! Just because you use a Variant doesn't magically free you from
> needing to know what exactly is that exception that you caught in the
> first place.

I think this is a confusion. You seem to advocate that exceptions are somehow exempt from class hierarchy design.

> To make any sense of what's stored in the Variant, you
> still have to know what is the exception type, and based on the type
> interpret the Variant. So you end up with:
>
> 	catch(Exception e) {
> 		switch(e.type) {
> 			case BlahException:
> 				handleBlahException(e.data.blah_info);
> 				break;
> 			case BlehException:
> 				handleBlehException(e.data.bleh_info);
> 				break;
> 			case BluhException:
> 				handleBluhException(e.data.bluh_info);
> 				break;
> 			...
> 		}
> 	}
>
> which is exactly the kind of ugliness that class hierarchies were
> invented to solve.

No, you don't end up with that at all. In fact it's your code that "knows exactly" the concrete type that suffers from duplication. I'm sorry, I think this is a complete confusion. Hopefully my post of a minute ago will help it.


Andrei