February 21, 2012
Well... then why did this mistakes exist?:

In dot NET:

	ComException - Exception encapsulating COM HRESULT information
        SEHException	Exception encapsulating Win32 structured exception handling information.z

	http://msdn.microsoft.com/en-us/library/z4c5tckx%28v=VS.71%29.aspx

And why do you think that a thing like standardizing DatabaseException never survives users, and that each database manager library defines its own top *DatabaseException base class?

This is a universal problem with transversal traits of exceptions.

--jm



On 02/20/2012 10:22 PM, H. S. Teoh wrote:
> On Mon, Feb 20, 2012 at 10:01:03PM -0300, Juan Manuel Cabo wrote: [...]
>> Back to the nasty argument. I think that the example that everyone wants is this one. If anyone solves this one without Variant[string] then it's a better solution than Variant[string]. (I repaste it from an above reply I gave):
>>
>>   [..]
>>   For instance: a C library wrapper, which gets the library errors encoded
>>   as some error code and throws them as exceptions. Shouldn't the library
>>   throw a FileNotFoundException when that's the error, instead of throwing
>>   a LibraryException that has the error code in a field?
>>
>>   So the correct thing to do is: after a library call, the wrapper
>>   checks the last error code number with a switch statement, and deciding
>>   which standard exception type to throw (defaulting to whatever you like
>>   if the error code doesn't map to a standard D exception). Then you
>>   add the error code to the Variant[string], and any other extra info.
> 
> But why bother with the error code at all? If you get a FileNotFoundException, you already know all there is to know about the problem, adding errno to it is redundant and only encourages code that's bound to a specific implementation.
> 
> Instead, Phobos should present a self-consistent API that's independent
> of what it uses to implement it, be it C stdio (errno) or C++ iostreams
> or Oracle driver (Oracle-specific error codes) or Postgresql driver
> (Postgresql-specific error codes), or what have you.
> 
> For error codes that *don't* have a direct mapping to standard exceptions, you can just encapsulate the errno (or whatever) inside a specific catch-all exception type dedicated to catch these sorts of unmapped cases, so that code that *does* know what errno can just catch this exception and interpret what happened. General, platform-independent code need not know what this exception is at all, they can just treat it as a general problem and react accordingly.  We don't (and shouldn't) expect every app out there to know or care about the errno of a failed operation, especially if it doesn't map to one of the standard exception types.
> 
> 
>>   That way, exception types can be standard.
>>
>>   So, to keep D exception types standard reusable and respected by
>>   future code, you must follow the Open-Closed design principle
>>   (nicest principle of OO design ever).
>>   [..]
>>
>> Adding the Variant[string] is considered applying the great
>> Open-Closed Design Principle:
>> 	-Open for reuse.
>> 	-Closed for modification.
>>         http://www.objectmentor.com/resources/articles/ocp.pdf
> [...]
> 
> Please bear in mind, I'm not saying that Variant[string] is *completely* useless. I'm just saying that most of the time it's not necessary. Sure there are some cases where it's useful, I've no problem with it being used in those cases. But we shouldn't be using it for all kinds of stuff that can be handled in better ways, e.g., static fields in a derived exception class.
> 
> 
> T
> 

February 21, 2012
On 2/20/12 4:44 PM, Juan Manuel Cabo wrote:
> HAhaha, it sometimes feel as though people are afraid that the Variant[string]
> idea is to never use plain old variables and never use exception subclasses. :-)
>
> On the contrary, the idea is so that plain old variables and exception subclasses
> can be created for the right reasons, and to remove cases where they need
> to be created for the wrong reasons.

Yah, I think there's a lot of confusion and consequent apprehension regarding this. Thanks for attempting to clarify things.

Andrei

February 21, 2012
On 2/20/12 7:02 PM, Juan Manuel Cabo wrote:
> oops, sorry!! I just saw a post by someone named Jose. My thousand apollogies!!

I got confused. It was your argument I meant to refer to - adding info to the exception in flight.

Andrei

February 21, 2012
On Monday, February 20, 2012 17:23:42 Andrei Alexandrescu wrote:
> On 2/20/12 4:44 PM, Juan Manuel Cabo wrote:
> > HAhaha, it sometimes feel as though people are afraid that the Variant[string] idea is to never use plain old variables and never use exception subclasses. :-)
> > 
> > On the contrary, the idea is so that plain old variables and exception subclasses can be created for the right reasons, and to remove cases where they need to be created for the wrong reasons.
> 
> Yah, I think there's a lot of confusion and consequent apprehension regarding this. Thanks for attempting to clarify things.

I think that as long as it makes sense to catch an exception and handle it based on a new type, any information associated with that exception should be member variables in that exception. But if you have extra information which could be useful but where you wouldn't really want to catch a new type, then it makes some sense to use the hashtable. However, I don't recall ever having personally run into a situation where that sort of need arose.

- Jonathan M Davis
February 21, 2012
On 2/20/12 7:08 PM, H. S. Teoh wrote:
> On Mon, Feb 20, 2012 at 06:38:08PM -0600, Andrei Alexandrescu wrote:
> [...]
>>> We shouldn't be using Variant[string] for this, because there's
>>> another problem associated with it: suppose MyException sometimes
>>> gets "extra_info1" and "extra_info2" tacked onto it, on its way up
>>> the call stack, and sometimes not. Now what should the catcher do?
>>
>> Use a central loop to render the information.
>
> Then it's useless for i18n, unless you can magically translate a
> sequence of unknown values into a different language in a consistent
> way.
>
> It sounds like all this is good for is to print a list of "name=value"
> pairs. Which is useful, I'll admit, for development/debugging purposes.
> I don't see how such a thing is useful in i18n.

As I said, string templates in conjunction with name/value bindings is all that's needed for i18n.

> [...]
>>> This is what I mean by not being able to depend on whether some data
>>> is there. Ultimately, to do anything useful with the info in the
>>> object, you need to know what's there.
>>
>> No. You do realize you are positioning yourself straight against every
>> OO principle there is? The entire OO world is predicated on the
>> assumption you _can_ do useful stuff with an object WITHOUT knowing
>> what's there.
>
> And the way OO does this is by having the *derived classes* do useful
> stuff behind a polymorphic interface.

Exactly, and with this you just destroyed your own design. For it does not build any polymorphic interface, no abstraction. It forever forces code to toil in the concrete (_fileName, _ipAddress, _userName) and fails to elevate any common interface that would foster reusable code.

> What the Variant[string] does is,
> as you have said previously, to replace the need for many derived
> classes save a few, thereby throwing away the polymorphism and
> presenting what amounts to an array of void* to the catch block.

On the contrary. This builds abstraction:

class Exception
{
    bool transient();
    Variant[string] info();
    ...
}

because it allows client code to treat different types, even types that haven't even been defined yet, uniformly.

This does not build anything:

class Exception {}
class UserNameException : Exception { string _userName; }
class NetException : Exception { string _ipAddress; }
...

> For you to now accuse me of going against OO principles is a really
> strange argument, I must say. I was in fact *advocating* the use of OO
> by putting the useful information in the derived classes, where they
> belong.

I'm not accusing of anything, merely noting that your design does not stand the scrutiny of your own principles (which are correct). Both can't be sustained simultaneously. Try a fresh run of your principles over your design. It'll get totaled.

>> I think you are misunderstanding the mechanisms involved. There is no
>> combinatorial code, just simple iteration and such. Dealing with
>> distinct exceptions with distinct code IS combinatorial, repetitive,
>> and non-scalable.
>
> Then pray tell how "simple iteration" will achieve the translation of
> the data in Variant[string] into a localized string, when there is no
> guarantee any field will be in the hash at all. Format strings obviously
> won't work, since you can't have a format string unless you already know
> what arguments are present.

There's no guarantee. That'll be a runtime check in the formatting engine.


Andrei

February 21, 2012
On Mon, 20 Feb 2012 15:21:56 -0600, H. S. Teoh <hsteoh@quickfur.ath.cx> wrote:
> On Mon, Feb 20, 2012 at 02:57:08PM -0600, Andrei Alexandrescu wrote:
>> 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 ...
>> }
> [...]
>
> Doesn't this need compiler/language support?

Nope. See (https://jshare.johnshopkins.edu/rjacque2/public_html/ )

Variant e = new MyException();
writeln( e.filename, e.line, e.column);

Aren't __traits and opDispatch fun?
February 21, 2012
On 2/20/12 6:51 PM, H. S. Teoh wrote:
> On Mon, Feb 20, 2012 at 06:19:32PM -0600, Andrei Alexandrescu wrote:
>> On 2/20/12 5:46 PM, Nick Sabalausky wrote:
> [...]
>>> You've suggested adding "Variant[string] info" to Exception for the
>>> sake of i18n. I think that's what he's referring to. You *could*
>>> argue that's not technically i18n, but so far i18n seems to be the
>>> only real use-case for it (although even that much has been disputed
>>> in light of reflection).
>>
>> All formatting and rendering of the exception information is helped.
>> And I think that's great because that's the most common activity one
>> would do with exceptions.
> [...]
>
> Then, obviously, different development environments are leading to
> vastly different conclusions, because I can't for the life of me imagine
> that the most common activity you would do with an exception is to print
> it.

Different strokes for different folks I'd say. I think I could claim a little authority on diversity. I've worked on an extremely diverse range of applications; in fact I've made a point to acquire broad specialization.

In virtually all systems I've worked on, rendering meaningful error messages out of exception information has been a major concern, and in most of them the problem has been poorly addressed. It is very exciting to have an opportunity to improve on the state of affairs.


Andrei


February 21, 2012
On Mon, Feb 20, 2012 at 10:32:48PM -0300, Juan Manuel Cabo wrote:
> Well... then why did this mistakes exist?:
> 
> In dot NET:
> 
> 	ComException - Exception encapsulating COM HRESULT information
>         SEHException	Exception encapsulating Win32 structured exception handling information.z
> 
> 	http://msdn.microsoft.com/en-us/library/z4c5tckx%28v=VS.71%29.aspx

I couldn't tell you, I didn't design this.


> And why do you think that a thing like standardizing DatabaseException never survives users, and that each database manager library defines its own top *DatabaseException base class?

Perhaps because when users chose to use the Oracle engine, they want to deal with Oracle-specific features including Oracle error codes directly? So a generalized SQL exception designed under some idealized database framework would only get in their way?


> This is a universal problem with transversal traits of exceptions.
[...]

True, so now we're trying to fix this by having *both* an exception class hierarchy *and* what amounts to a generic varbind that stores transversal information?

If Oracle error codes are what the user wants, then giving them a pretty exception class hierarchy is sorta pointless. They just want an OracleException containing the Oracle error code. They couldn't care less if there was a SQLParseErrorException or a SQLCannotAcquireLockException. It would be a waste of effort to build a pretty hierarchy for them if they're just going to ignore it and use Oracle error codes anyway.

If we're really trying to solve transversal problems, then I have the feeling that this will require something more than just slapping a Variant[string] onto the Exception class. We need to re-examine the entire model of what exceptions are and what's the best way to deal with them.

In the case of Phobos, we're not really dealing with the same kind of situation (not yet, anyway). Phobos modules, in general, aren't merely thin wrappers around a self-contained external module the same way an Oracle API is just a thin wrapper over an independent Oracle driver built by an independent party.  So we get to define our own game, in a sense.  There's no Oracle error code to map, and we can enforce the proper use of an exception class hierarchy. If someone wants direct access to errno, say, they could just call the C API directly -- D was designed not to require wrappers in that case.

But still, I concede that class hierarchies don't solve everything. Sometimes we do need something more. But slapping on a Variant[string] onto the existing system seems like merely a workaround, not a real solution.


T

-- 
Study gravitation, it's a field with a lot of potential.
February 21, 2012
On 2/20/12 7:07 PM, Jonathan M Davis wrote:
> On Monday, February 20, 2012 18:38:08 Andrei Alexandrescu wrote:
>> On 2/20/12 6:25 PM, H. S. Teoh wrote:
>>> This is what I mean by not being able to depend on whether some data is
>>> there. Ultimately, to do anything useful with the info in the object,
>>> you need to know what's there.
>>
>> No. You do realize you are positioning yourself straight against every
>> OO principle there is? The entire OO world is predicated on the
>> assumption you _can_ do useful stuff with an object WITHOUT knowing
>> what's there.
>
> Exceptions aren't very OO really. Aside from getting a string out of them, you
> generally don't have any polymorphism involved, and even with the string,
> there's a good chance that you don't. For instance, the message field which
> toString uses to generate its string is passed as an argument to Exception's
> constructor.

(Cloning and comparison are also essential polymorphic methods to implement.) But then again the view "exceptions are wildebeests" is coming straight from inside the box. We want to improve on that.

> With exceptions, it's the types that matter. It's not a case of changing
> behavior based on implementation. With OO, you try _not_ to care about what
> the type is. With exceptions, on the other hand, you care a great deal. It's
> inverted from OO. Exceptions hold data but not much behavior. The behavior
> goes in the catch blocks.
>
> If we had a construct which allowed inheritance but not polymorphism (which we
> don't, since for better or wors, inheritance is conflated with polymorphism in
> D), then that would make a lot of sense for exceptions.

I don't think inheritance without subtyping would help any. C++ has it (non-public inheritance) but that didn't improve exceptions one bit.

> It doesn't really hurt us that exceptions have polymorphism, but it doesn't
> generally help them do their job at all. If you're going to do anything beyond
> simply print an error message, you need to know what the exception type is and
> what data it has. And that's not OO at all.

Or you need to implement a key-value interface that allows printing of an elaborate error message.


Andrei
February 21, 2012
On 2/20/12 7:09 PM, Piotr Szturmaj wrote:
> Andrei Alexandrescu wrote:
>> On 2/20/12 4:25 PM, Jonathan M Davis wrote:
>>> I definitely think that we should favor putting data in member
>>> variables, not
>>> in a hashtable of Variants.
>
> +1
>
>> Whenever you put data in member variables you set yourself up for code
>> bloat. Do you agree?
>
> It's a problem of classes as a whole, not just exceptions. I'm afraid
> such 'pressure' will limit the use of classes in Phobos.

The problem is solved by pushing interface up, i.e. defining good methods in the base classes.

Andrei