Issue 234: accessor function on SystemException (cxx_revision) Source: (, ) Nature: Uncategorized Severity: LOW Summary: Summary: SystemException has accessor functions minor() and completed() rather than public data members like exceptions normally do. Normal mapping is to make exception data into public data members Resolution: Close with no change. Revised Text: Actions taken: October 14, 1996: received issue June 13, 2000: closed issue Discussion: Close with no change. I agree, the discrepancy between user exceptions and system exceptions is jarring. However, there i too much code out there that would break if we cleaned this up. End of Annotations:===== This is issue # 234 accessor function on SystemException SystemException has accessor functions minor() and completed() rather than public data members like exceptions normally do. Normal mapping is to make exception data into public data members -Juergen Return-Path: X-Authentication-Warning: tigger.dstc.edu.au: michi owned process doing -bs Date: Tue, 8 Sep 1998 09:02:26 +1000 (EST) From: Michi Henning To: cxx_revision@omg.org Subject: Proposal for issues 234, 253, 259, 260, 266 Proposal is based on text in 98-07-12 (C++ RTF 1.4 Results). Change the Exception class on page 20-69 to: // C++ class Exception { public: virtual ~Exception(); virtual void _raise = 0; virtual const char * _id(); } Note the new _id() member. Insert the following text following the third-last paragraph on page 20-69 (following the description of _raise()): The _id() function returns the unqualified name of the exception. If the unqualified name is not available at run time, _id() returns the repository ID of the exception. The return value points at memory internal to the exception and must not be deallocated. Insert the following text at the end of Section 20.17 as a new Section 20.17.1 (immediately before Section 20.17.1, which now becomes 20.17.2): ostream Inserters Conforming implementations shall provide ostream inserters with the following signatures: ostream & operator<<(ostream &, const CORBA::Exception &); ostream & operator<<(ostream &, const CORBA::Exception *); The Exception inserters insert the id of the exception as returned by Exception::_id(). Applications can control the formatting of exceptions by providing overloaded inserters for more derived exception types or by overriding the Exception::id() member function. The proposal deliberately does not require overloading for CORBA::SystemException, even though that looks attractive at first. The reason is that even though we could require an overloaded operator for SystemException to print the name, completion status, and minor member, the formatting may not be what an application wants. (If the mapping were to provide an inserter for SystemException, the application couldn't add one of its own.) In order to get custom formatting, an application can provide its own overloaded operators for more derived exception types. Ambiguities are avoided because if a derived exception is inserted, the "closest" inserter is chosen, that is, either the inserter that precisely matches an exception's type, or the most derived inserter for an exception that is a base type (which will always be the inserter for SystemException or UserException). Because exceptions don't use multiple inheritance, this is unambiguous. Cheers, Michi. -- Michi Henning +61 7 33654310 DSTC Pty Ltd +61 7 33654311 (fax) University of Qld 4072 michi@dstc.edu.au AUSTRALIA http://www.dstc.edu.au/BDU/staff/michi-henning.html Return-Path: Date: Tue, 08 Sep 1998 10:23:04 -0400 From: Paul H Kyzivat Organization: NobleNet To: Michi Henning CC: cxx_revision@omg.org Subject: Re: Proposal for issues 234, 253, 259, 260, 266 References: Michi Henning wrote: > > Proposal is based on text in 98-07-12 (C++ RTF 1.4 Results). > > Change the Exception class on page 20-69 to: > > // C++ > class Exception { > public: > virtual ~Exception(); > virtual void _raise = 0; > virtual const char * _id(); > } > > Note the new _id() member. > > Insert the following text following the third-last paragraph on page > 20-69 > (following the description of _raise()): > > The _id() function returns the unqualified name of the > exception. > If the unqualified name is not available at run time, _id() > returns the repository ID of the exception. The return value > points at memory internal to the exception and must not > be deallocated. This seems like a good idea in general. I have a few concerns about the details: - having the function return either the *unqualified* name OR the repository id seems unnecessarily vague. As defined here, given a reference or pointer to an Exception, there isn't any guaranteed way to get an identifier that is unambiguous. While in some cases printing the unqualified name may be more user friendly, in won't be if the name is ambiguous or doesn't point the user at the module where the problem originates. I believe there should be an accessor that unconditionally returns the repository id. Perhaps there should also be an accessor that returns the *fully qualified* name of the exception. A function for deriving a user friendly name could either be yet another accessor, or just a freestanding function that uses these and edits the result. - The name "_id()" to me doesn't imply the semantics described. - This doesn't deal with Issue 260. That asked for a *static* function that returns a repository id. This is closely related, but serves a somewhat different purpose. This is useful for providing a runtime link between the generated stubs and the Interface Repository. (And, the same would be even more useful interfaces than it is for exceptions. The repository id for interfaces is often needed at runtime.) So, rolling this up, I suggest: 1) A static function on each concrete subclass of Exception that returns the repository id of that exception. (Perhaps call this one _id().) 2) A virtual function on Exception that returns the repository id of the instance. (Perhaps call this one _get_id() - it needs to be a different name than the static function since they have the same signature.) This needs to be overridden in each derived class to return the correct thing. (It can just call _id() on itself for the value to return.) 3) If anybody cares, there could be a similar pair of functions for the fully qualified name. (Personally I don't see the necessity for this, but I could be talked into it.) 4) A function somewhere that takes an exception and returns a "user friendly" name. This need not be a member function. It can call _get_id() and then parse it and return some interesting portion of it if it conforms to IDL respository id syntax or otherwise return the whole thing. If the accessors for fully qualified names are also to be available, it could use those too. Ideally there should be some way for the end user to replace this function. Perhaps it can be a template function that can be specialized. > > Insert the following text at the end of Section 20.17 as a new > Section > 20.17.1 (immediately before Section 20.17.1, which now becomes > 20.17.2): > > ostream Inserters > > Conforming implementations shall provide ostream inserters > with the following signatures: > > ostream & operator<<(ostream &, const CORBA::Exception &); > ostream & operator<<(ostream &, const CORBA::Exception *); > > The Exception inserters insert the id of the exception as > returned by Exception::_id(). > > Applications can control the formatting of exceptions by > providing > overloaded inserters for more derived exception types or > by overriding the Exception::id() member function. Which version of ostream should be supported - the old one or the new one? I don't think there is any good answer to this - whatever choice is made will be unacceptable to some significant set of users either now or in the future. Perhaps we can define something with conditional compilation to deal with this??? > > The proposal deliberately does not require overloading for > CORBA::SystemException, even though that looks attractive at first. > The reason is that even though we could require an overloaded > operator for SystemException to print the name, completion status, > and minor member, the formatting may not be what an application > wants. > (If the mapping were to provide an inserter for SystemException, the > application couldn't add one of its own.) > > In order to get custom formatting, an application can provide its > own > overloaded operators for more derived exception types. Ambiguities > are > avoided because if a derived exception is inserted, the "closest" > inserter > is chosen, that is, either the inserter that precisely matches an > exception's type, or the most derived inserter for an exception that > is > a base type (which will always be the inserter for SystemException > or > UserException). Because exceptions don't use multiple inheritance, > this > is unambiguous. I see the concern, but there is a real convenience issue here. Perhaps we could predefine an include file that would provide a standard behavior, and leave it to the user to include or not include this file. This technique could be extended further - We could define an include file for each standardized module that defines printing for the exceptions declared in that module. Return-Path: X-Authentication-Warning: tigger.dstc.edu.au: michi owned process doing -bs Date: Wed, 9 Sep 1998 01:48:05 +1000 (EST) From: Michi Henning To: Paul H Kyzivat cc: cxx_revision@omg.org Subject: Re: Proposal for issues 234, 253, 259, 260, 266 Content-ID: On Tue, 8 Sep 1998, Paul H Kyzivat wrote: > This seems like a good idea in general. I have a few concerns about the > details: > > - having the function return either the *unqualified* name OR the > repository id seems unnecessarily vague. As defined here, given a > reference or pointer to an Exception, there isn't any guaranteed way to > get an identifier that is unambiguous. While in some cases printing the > unqualified name may be more user friendly, in won't be if the name is > ambiguous or doesn't point the user at the module where the problem > originates. Hmmm... The intent of this is to provide an easy way to get some sort of comprehensible error message out of a generic catch handler: try { fooref->op(); } catch (const FooSpecificException & e) { // It's Foo's user exception } catch (const CORBA::Exception & e) { cerr << "Foo failed: " << e << endl; } > I believe there should be an accessor that unconditionally > returns the repository id. I can already get the repository ID from the exception's typecode. Typically, all I want is some string that identifies the exception. If I care about repository IDs, I will also know about type codes and be able to get the repository ID from the exception's type code. > Perhaps there should also be an accessor that > returns the *fully qualified* name of the exception. That is impossible, because the fully qualified name is not marshaled and cannot be deduced from the repository ID in absence of an IFR. > 1) A static function on each concrete subclass of Exception that returns > the repository id of that exception. (Perhaps call this one _id().) I don't think that's necessary -- the repository ID is available already. > 2) A virtual function on Exception that returns the repository id of the > instance. (Perhaps call this one _get_id() - it needs to be a different > name than the static function since they have the same signature.) This > needs to be overridden in each derived class to return the correct > thing. (It can just call _id() on itself for the value to return.) So, call it _name(). The only problem is that the name of the exception may not be available *at all*. In that case, the repository ID is the *only* thing that is available. When I want to print an error message as I showed above, I don't want an exception or an empty string. So, the way I see it, _name() would still have to fall back on the repository ID if the name of the exception is not available. In other words, _name() would have to behave like the _id() in my proposal. > 3) If anybody cares, there could be a similar pair of functions for the > fully qualified name. (Personally I don't see the necessity for this, > but I could be talked into it.) I don't see how that could be possible. > 4) A function somewhere that takes an exception and returns a "user > friendly" name. This need not be a member function. It can call > _get_id() and then parse it and return some interesting portion of > it if > it conforms to IDL respository id syntax or otherwise return the > whole > thing. If the accessors for fully qualified names are also to be > available, it could use those too. Ideally there should be some way > for > the end user to replace this function. Perhaps it can be a template > function that can be specialized. I think that is too complex just so I can conveniently log an error message. > Which version of ostream should be supported - the old one or the new > one? The same version of ostream that is already support by other functions in the mapping, such as the overloaded << operator for String_var. > I don't think there is any good answer to this - whatever choice is > made will be unacceptable to some significant set of users either > now or > in the future. Perhaps we can define something with conditional > compilation to deal with this??? If a compilation environment supports two iostream packages, the ORB must either already have a policy for chosing one of the two, or it must be always be using the same iostream package. Either way, things will work fine, and we don't have to say anything extra. > > In order to get custom formatting, an application can provide its own > > overloaded operators for more derived exception types. Ambiguities are > > avoided because if a derived exception is inserted, the "closest" > > inserter > > is chosen, that is, either the inserter that precisely matches an > > exception's type, or the most derived inserter for an exception that > > is > > a base type (which will always be the inserter for SystemException or > > UserException). Because exceptions don't use multiple inheritance, > > this > > is unambiguous. > > I see the concern, but there is a real convenience issue here. Perhaps > we could predefine an include file that would provide a standard > behavior, and leave it to the user to include or not include this file. > > This technique could be extended further - We could define an include > file for each standardized module that defines printing for the > exceptions declared in that module. Hmmm... That's strikes me as a lot more complex than necessary. We have gone from two simple overloaded operators to a whole set of standardized include files. I'd rather use two overloaded operators myself... Cheers, Michi. -- Michi Henning +61 7 33654310 DSTC Pty Ltd +61 7 33654311 (fax) University of Qld 4072 michi@dstc.edu.au AUSTRALIA http://www.dstc.edu.au/BDU/staff/michi-henning.html Return-Path: Sender: jon@floorboard.com Date: Tue, 08 Sep 1998 09:40:50 -0700 From: Jonathan Biggar To: Paul H Kyzivat CC: Michi Henning , cxx_revision@omg.org Subject: Re: Proposal for issues 234, 253, 259, 260, 266 References: <35F53DC8.B4ADE38C@noblenet.com> Paul H Kyzivat wrote: > > Michi Henning wrote: > > > > Proposal is based on text in 98-07-12 (C++ RTF 1.4 Results). > > > > Change the Exception class on page 20-69 to: > > > > // C++ > > class Exception { > > public: > > virtual ~Exception(); > > virtual void _raise = 0; > > virtual const char * _id(); > > } > > > > Note the new _id() member. > > > > Insert the following text following the third-last paragraph on > page > > 20-69 > > (following the description of _raise()): > > > > The _id() function returns the unqualified name of the > > exception. > > If the unqualified name is not available at run time, > _id() > > returns the repository ID of the exception. The return > value > > points at memory internal to the exception and must not > > be deallocated. > > This seems like a good idea in general. I have a few concerns about > the > details: > > - having the function return either the *unqualified* name OR the > repository id seems unnecessarily vague. As defined here, given a > reference or pointer to an Exception, there isn't any guaranteed way > to > get an identifier that is unambiguous. While in some cases printing > the > unqualified name may be more user friendly, in won't be if the name > is > ambiguous or doesn't point the user at the module where the problem > originates. I believe there should be an accessor that > unconditionally > returns the repository id. Perhaps there should also be an accessor > that > returns the *fully qualified* name of the exception. A function for > deriving a user friendly name could either be yet another accessor, > or > just a freestanding function that uses these and edits the result. I agree with Paul here. You are trying to mix two semantics into a single function, which isn't a very good design. Since we have the repository id of the exception available (this is guaranteed), we should make sure that there is a virtual function defined to return it. However, I don't believe we need the static function that Paul suggests below, since the programmer can always get the repository id from the exceptions TypeCode. > > Insert the following text at the end of Section 20.17 as a new Section > > 20.17.1 (immediately before Section 20.17.1, which now becomes > > 20.17.2): > > > > ostream Inserters > > > > Conforming implementations shall provide ostream inserters > > with the following signatures: > > > > ostream & operator<<(ostream &, const CORBA::Exception &); > > ostream & operator<<(ostream &, const CORBA::Exception *); > > > > The Exception inserters insert the id of the exception as > > returned by Exception::_id(). > > > > Applications can control the formatting of exceptions by > > providing > > overloaded inserters for more derived exception types or > > by overriding the Exception::id() member function. > > Which version of ostream should be supported - the old one or the new > one? I don't think there is any good answer to this - whatever choice is > made will be unacceptable to some significant set of users either now or > in the future. Perhaps we can define something with conditional > compilation to deal with this??? This is a quality of implementation issue, and shouldn't be addressed by the C++ language mapping. At most, we should add text to state that the appropriate ostream class for the environment is the one that is used. > > > > The proposal deliberately does not require overloading for > > CORBA::SystemException, even though that looks attractive at > first. > > The reason is that even though we could require an overloaded > > operator for SystemException to print the name, completion status, > > and minor member, the formatting may not be what an application > wants. > > (If the mapping were to provide an inserter for SystemException, > the > > application couldn't add one of its own.) > > > > In order to get custom formatting, an application can provide its > own > > overloaded operators for more derived exception types. Ambiguities > are > > avoided because if a derived exception is inserted, the "closest" > > inserter > > is chosen, that is, either the inserter that precisely matches an > > exception's type, or the most derived inserter for an exception > that > > is > > a base type (which will always be the inserter for SystemException > or > > UserException). Because exceptions don't use multiple inheritance, > > this > > is unambiguous. > > I see the concern, but there is a real convenience issue > here. Perhaps > we could predefine an include file that would provide a standard > behavior, and leave it to the user to include or not include this > file. > > This technique could be extended further - We could define an > include > file for each standardized module that defines printing for the > exceptions declared in that module. I don't think that the include file idea is portable across all C++ implementations, since it would require that the function be defined as an inline in the include file. A better idea: define virtual member functions in each insert class: class Exception { public: ... void insert(ostream &); ... }; Then, if the programmer wants to use the "standard" behavior, he just defines the following overloaded operators: ostream &operator <<(ostream &o, CORBA::Exception &e) { e.insert(o); return o; } ostream &operator <<(ostream &o, CORBA::Exception *e) { e->insert(o); return o; } Otherwise, he can define his own insertion and extraction operators. -- Jon Biggar Floorboard Software jon@floorboard.com jon@biggar.org Return-Path: Date: Tue, 08 Sep 1998 19:54:35 -0400 From: Paul H Kyzivat Organization: NobleNet To: Michi Henning CC: cxx_revision@omg.org Subject: Re: Proposal for issues 234, 253, 259, 260, 266 References: Michi Henning wrote: > > On Tue, 8 Sep 1998, Paul H Kyzivat wrote: > > > This seems like a good idea in general. I have a few concerns > about > the > > details: > > > > - having the function return either the *unqualified* name OR the > > repository id seems unnecessarily vague. As defined here, given a > > reference or pointer to an Exception, there isn't any guaranteed > way > to > > get an identifier that is unambiguous. While in some cases > printing > the > > unqualified name may be more user friendly, in won't be if the > name > is > > ambiguous or doesn't point the user at the module where the > problem > > originates. > > Hmmm... The intent of this is to provide an easy way to get some > sort > of > comprehensible error message out of a generic catch handler: > > try { > fooref->op(); > } > catch (const FooSpecificException & e) { > // It's Foo's user exception > } > catch (const CORBA::Exception & e) { > cerr << "Foo failed: " << e << endl; > } I understand the intent. But the unqualified name of the exception isn't necessarily distinct. For instance, there is CosNaming::NotFound. I expect that there could easily be other NotFound exceptions in other scopes. I would like to know which one it is. If the repositoryId is printed then I will know. If the unqualified name is printed I won't. > > > I believe there should be an accessor that unconditionally > > returns the repository id. > > I can already get the repository ID from the exception's typecode. > Typically, all I want is some string that identifies the exception. > If I care about repository IDs, I will also know about type codes > and > be able to get the repository ID from the exception's type code. I was trying to kill another bird with the same stone here. While getting the repId from the typecode is possible it isn't convenient. I don't mind forgetting it if nobody else sees the value. (The real value is for interfaces where the repository id is often needed, in order to create object references. I guess I should submit an issue regarding that.) > > > Perhaps there should also be an accessor that > > returns the *fully qualified* name of the exception. > > That is impossible, because the fully qualified name is not > marshaled and cannot be deduced from the repository ID in absence of > an IFR. Unless I misunderstand, the fully qualified name is just as accessible as the unqualified name is. It may be available if knowledge of the exception has been compiled into the program. It may not be available if working entirely via DII/DSI. But if anything is available, then a fully qualified name should be available. > > > 1) A static function on each concrete subclass of Exception that > returns > > the repository id of that exception. (Perhaps call this one > _id().) > > I don't think that's necessary -- the repository ID is available > already. > > > 2) A virtual function on Exception that returns the repository id > of > the > > instance. (Perhaps call this one _get_id() - it needs to be a > different > > name than the static function since they have the same signature.) > This > > needs to be overridden in each derived class to return the correct > > thing. (It can just call _id() on itself for the value to return.) > > So, call it _name(). The only problem is that the name of the > exception > may not be available *at all*. In that case, the repository ID is > the > *only* thing that is available. When I want to print an error > message > as I showed above, I don't want an exception or an empty string. > So, the way I see it, _name() would still have to fall back on > the repository ID if the name of the exception is not available. > In other words, _name() would have to behave like the _id() in my > proposal. Yes, I get it. My point is that a repository id is analogous to a fully qualified name. If it happens to be an IDL style repository id then it has a series of nested names that either are scope names or are something similar, and has a final component that is (roughly) an unscoped name. (If the repId is in one of the other formats it can't be interpretted as flexibly.) There is clearly a tradeoff between printing all the available information in order to be precise about the problem, and discarding hopefully redundant information in order to make a more user friendly message. It would be nice to give the user flexibility to make this decision, while providing the raw material to do it with. > > > 3) If anybody cares, there could be a similar pair of functions > for > the > > fully qualified name. (Personally I don't see the necessity for > this, > > but I could be talked into it.) > > I don't see how that could be possible. As mentioned above, if you can get a scoped name you can get a fully qualified name. > > > 4) A function somewhere that takes an exception and returns a > "user > > friendly" name. This need not be a member function. It can call > > _get_id() and then parse it and return some interesting portion of > it if > > it conforms to IDL respository id syntax or otherwise return the > whole > > thing. If the accessors for fully qualified names are also to be > > available, it could use those too. Ideally there should be some > way > for > > the end user to replace this function. Perhaps it can be a > template > > function that can be specialized. > > I think that is too complex just so I can conveniently log an error > message. I haven't got a full answer in mind here. But easily generating error messages that have meaningful content is important, so it is worth getting right. It would be nice if people didn't have to hand-write insertion operators for every exception in the IDL they use in order to get reasonable messages. This would be a good candidate for another kind of policy object, though it isn't clear what to associate it with. > > > Which version of ostream should be supported - the old one or the > new > > one? > > The same version of ostream that is already support by other > functions > in the mapping, such as the overloaded << operator for String_var. > > > I don't think there is any good answer to this - whatever choice > is > > made will be unacceptable to some significant set of users either > now or > > in the future. Perhaps we can define something with conditional > > compilation to deal with this??? > > If a compilation environment supports two iostream packages, the ORB > must either already have a policy for chosing one of the two, or it > must > be always be using the same iostream package. Either way, things > will > work fine, and we don't have to say anything extra. Oops. For a moment I forgot that those operators were already mandated by the spec. I guess that makes it the subject for a new issue. I don't see how this can be a runtime policy. I don't believe the two types can coexist in the same compilation unit, can they? I think this needs to be two distinct versions of a library, and the include of alternative header files in orb.h. But this can wait for another day. > > > > In order to get custom formatting, an application can provide > its > own > > > overloaded operators for more derived exception > types. Ambiguities > are > > > avoided because if a derived exception is inserted, the > "closest" > > > inserter > > > is chosen, that is, either the inserter that precisely matches > an > > > exception's type, or the most derived inserter for an exception > that > > > is > > > a base type (which will always be the inserter for > SystemException > or > > > UserException). Because exceptions don't use multiple > inheritance, > > > this > > > is unambiguous. > > > > I see the concern, but there is a real convenience issue here. > Perhaps > > we could predefine an include file that would provide a standard > > behavior, and leave it to the user to include or not include this > file. > > > > This technique could be extended further - We could define an > include > > file for each standardized module that defines printing for the > > exceptions declared in that module. > > Hmmm... That's strikes me as a lot more complex than necessary. We > have > gone from two simple overloaded operators to a whole set of > standardized > include files. I'd rather use two overloaded operators myself... I wasn't suggesting this just to get the name out for each. Using custom include files would allow the members of the exception to be printed as well, both for SystemException and distinct subclasses of UserException. But it is a bit of a stretch, so I won't push it now. To summarize: - The only guaranteed available name is the repository id. It can be printed if nothing else is available. - If idl defining the exception has been compiled, then a scoped name for the class that represents it can be available. This is probably a better name than the repository id if it is available. - Neither the repositoryId nor the fully scoped name is especially user friendly as an error message. In both cases it may be possible to algorithmically choose a subset of the name that is adequate to describe the exception. The decision of whether to do this reduction or not is ideally left to the programmer to decide. Ideally there should be some simple way to make this decision globally rather than always get it one way or have to declare many operators to get it. - Overriding the insertion operator for specific exceptions only works if the idl has been compiled. Another technique is needed if it is to work uniformly for both compiled and DII/DSI. Once we have defined a particular behavior for operator<<(Exception&) we can't take it back. Better to take longer to get it right than to get it wrong. Return-Path: Date: Tue, 08 Sep 1998 20:20:00 -0400 From: Paul H Kyzivat Organization: NobleNet To: Jonathan Biggar CC: Michi Henning , cxx_revision@omg.org Subject: Re: Proposal for issues 234, 253, 259, 260, 266 References: <35F53DC8.B4ADE38C@noblenet.com> <35F55E12.2E3CED58@floorboard.com> Jonathan Biggar wrote: > > > Which version of ostream should be supported - the old one or the > new > > one? I don't think there is any good answer to this - whatever > choice is > > made will be unacceptable to some significant set of users either > now or > > in the future. Perhaps we can define something with conditional > > compilation to deal with this??? > > This is a quality of implementation issue, and shouldn't be > addressed > by > the C++ language mapping. At most, we should add text to state that > the > appropriate ostream class for the environment is the one that is > used. It is fine with me if this is left as a quality of implementation issue. > I don't think that the include file idea is portable across all C++ > implementations, since it would require that the function be defined > as > an inline in the include file. It was an off-the-cuff suggestion. You are probably right. > > A better idea: define virtual member functions in each insert > class: > > class Exception { > public: > ... > void insert(ostream &); > ... > }; Did you mean virtual? This could go either way depending on how insert is defined. > > Then, if the programmer wants to use the "standard" behavior, he > just > defines the following overloaded operators: > > ostream &operator <<(ostream &o, CORBA::Exception &e) > { > e.insert(o); > return o; > } > > ostream &operator <<(ostream &o, CORBA::Exception *e) > { > e->insert(o); > return o; > } > > Otherwise, he can define his own insertion and extraction operators. This like this more. It avoids preempting the insertion operators on Exception, and isn't especially burdensome. There *could* be a standard header file that provides these definitions, or this could be a quality of implementation feature. Return-Path: X-Authentication-Warning: tigger.dstc.edu.au: michi owned process doing -bs Date: Wed, 9 Sep 1998 11:58:53 +1000 (EST) From: Michi Henning Reply-To: Michi Henning To: Paul H Kyzivat cc: cxx_revision@omg.org Subject: Re: Proposal for issues 234, 253, 259, 260, 266 Content-ID: On Tue, 8 Sep 1998, Paul H Kyzivat wrote: > > Hmmm... The intent of this is to provide an easy way to get some sort > > of > > comprehensible error message out of a generic catch handler: > > > > try { > > fooref->op(); > > } > > catch (const FooSpecificException & e) { > > // It's Foo's user exception > > } > > catch (const CORBA::Exception & e) { > > cerr << "Foo failed: " << e << endl; > > } > > I understand the intent. But the unqualified name of the exception isn't > necessarily distinct. For instance, there is CosNaming::NotFound. I > expect that there could easily be other NotFound exceptions in other > scopes. I would like to know which one it is. Sure. However, it is generally *impossible* to print the fully qualified name. It is not marshaled, so the only other place it could come from is the IFR, which is optional. > If the repositoryId is > printed then I will know. If the unqualified name is printed I > won't. I disagree. What is the fully-qualified name of an exception with the repository ID DCE:700dc518-0110-11ce-ac8f-0800090b5d3e:1 ? > > > I believe there should be an accessor that unconditionally > > > returns the repository id. > > > > I can already get the repository ID from the exception's typecode. > > Typically, all I want is some string that identifies the > exception. > > If I care about repository IDs, I will also know about type codes > and > > be able to get the repository ID from the exception's type code. > > I was trying to kill another bird with the same stone here. While > getting the repId from the typecode is possible it isn't convenient. Agreed. > > > Perhaps there should also be an accessor that > > > returns the *fully qualified* name of the exception. > > > > That is impossible, because the fully qualified name is not > > marshaled and cannot be deduced from the repository ID in absence > of > > an IFR. > > Unless I misunderstand, the fully qualified name is just as > accessible > as the unqualified name is. It may be available if knowledge of the > exception has been compiled into the program. Yes, in that case, it is possible to show the fully qualified name. > It may not be available if working entirely via DII/DSI. It is *guaranteed* not to be available when using the DII. That is because the fully-qualified name is not marshaled, only the repository ID. Given the repository ID, it is possible to reconstruct the fully-qualified name only in the presence of an IFR. However, the IFR is optional. This means we cannot add a function to the C++ mapping that requires the fully qualified to be returned. The ambiguity of only showing the name, but not the fully-qualified name is really no problem. You are right, there may be many different NotFound exceptions in different scopes. However, the probability that the *same* operation will return two or more different NotFound exceptions is small. The following is highly unlikely: interface foo { void op() raises(X::NotFound, Y::NotFound, Z::NotFound); }; Furthermore, the fully-qualified name of an exception is *NOT* a unique name. I can have two different exception types with the same fully-qualified name by using #pragma to change the repository IDs. It's filthy, but legal. The *ONLY* unique handle to a type is the repository ID, full stop. > But if anything is available, then a fully > qualified name should be available. Disagree -- GIOP doesn't work that way. > > So, call it _name(). The only problem is that the name of the > > exception > > may not be available *at all*. In that case, the repository ID is > the > > *only* thing that is available. When I want to print an error > message > > as I showed above, I don't want an exception or an empty string. > > So, the way I see it, _name() would still have to fall back on > > the repository ID if the name of the exception is not available. > > In other words, _name() would have to behave like the _id() in my > > proposal. > > Yes, I get it. My point is that a repository id is analogous to a > fully > qualified name. If it happens to be an IDL style repository id then > it > has a series of nested names that either are scope names or are > something similar, and has a final component that is (roughly) an > unscoped name. (If the repId is in one of the other formats it can't > be > interpretted as flexibly.) Exactly. Further, what are you going to show for the following rep ID as the fully qualified name? IDL:xxx/yyy/zzz:1.0 Will you show xxx::yyy::zzz or yyy::zzz or zzz ? All three can be correct, depending on what prefix pragma I have used. It is *impossible* to determine where the prefix ends and the name scopes start inside a rep ID. > There is clearly a tradeoff between printing all the available > information in order to be precise about the problem, and discarding > hopefully redundant information in order to make a more user > friendly > message. It would be nice to give the user flexibility to make this > decision, while providing the raw material to do it with. OK. Modified proposal: Add an _id() member function that returns the repository ID of the exception. This is a convenience function that makes it unnessary to fiddle with the type code of an exception. Add a second function called _name(). It prints the unqualified name of the exception if available, and the repository ID otherwise. Specify that the inserters for CORBA::Exception insert what is returned by _name(). If the application wants something else, like the repository ID always, it can overload the inserters for UserException and SystemException to achieve this. This should give us the best of both worlds. _id() always returns the repository ID, which is guaranteed to be available. _name() returns something suitable for printing error messages. If the exception name is available, it prints that, otherwise it falls back on the rep ID. Printing fully-qualified names is out of the question I'm afraid because it is unimplementable. So, opinions on the _id() and _name() idea? > > I don't see how that could be possible. > > As mentioned above, if you can get a scoped name you can get a fully > qualified name. Disagree -- see above. > > I think that is too complex just so I can conveniently log an error > > message. > > I haven't got a full answer in mind here. But easily generating error > messages that have meaningful content is important, so it is worth > getting right. It would be nice if people didn't have to hand-write > insertion operators for every exception in the IDL they use in order to > get reasonable messages. This would be a good candidate for another kind > of policy object, though it isn't clear what to associate it with. How would you print this exception? union u switch(long) { case 0: sequence aaa; case 1: sequence bbb; case 2: float ccc[100]; }; exception E { u uu; char c; sequence uus; }; I know this sucks -- the point is that there does not appear to be a general way (at least not an easy or meaningful one) to print the contents of arbitrary exceptions. > > If a compilation environment supports two iostream packages, the ORB > > must either already have a policy for chosing one of the two, or it > > must > > be always be using the same iostream package. Either way, things will > > work fine, and we don't have to say anything extra. > > Oops. For a moment I forgot that those operators were already mandated > by the spec. I guess that makes it the subject for a new issue. I don't > see how this can be a runtime policy. I don't believe the two types can > coexist in the same compilation unit, can they? No. But, for example, an ORB could load one of the two dynamically at run time. > I think this needs to > be two distinct versions of a library, and the include of > alternative > header files in orb.h. No. Nothing has to change here at all. This is firmly in the ORB's environment. Whatever I've done to configure the ORB, that's what happens when I call the overloaded operator. > But this can wait for another day. It can wait forever ;-) > > Hmmm... That's strikes me as a lot more complex than necessary. We > > have > > gone from two simple overloaded operators to a whole set of > > standardized > > include files. I'd rather use two overloaded operators myself... > > I wasn't suggesting this just to get the name out for each. Using > custom > include files would allow the members of the exception to be printed > as > well, both for SystemException and distinct subclasses of > UserException. > > But it is a bit of a stretch, so I won't push it now. I'd say this is outside the scope of the issues I was trying to address and I'd be happier if we could leave this alone for now, mainly because it is much larger in scope and ambition. > To summarize: > > - The only guaranteed available name is the repository id. It can be > printed if nothing else is available. Agreed. > - If idl defining the exception has been compiled, then a scoped name > for the class that represents it can be available. This is probably a > better name than the repository id if it is available. I'm not sure about this -- see the NotFound example above. When an exception is raised, it only makes sense to talk about the exception in the context of the operation that raised it anyway. Because operations hardly ever will raise two different exceptions with the same name, I don't think the fully-qualified name is important at all. > - Neither the repositoryId nor the fully scoped name is especially user > friendly as an error message. In both cases it may be possible to > algorithmically choose a subset of the name that is adequate to describe > the exception. The decision of whether to do this reduction or not is > ideally left to the programmer to decide. Ideally there should be some > simple way to make this decision globally rather than always get it one > way or have to declare many operators to get it. If I overload operator<< for UserException, I can implement a global policy there. I can on top of that overload operator<< for specific user exceptions as well, so I get special policies for special exceptions. I think this leaves the choice completely open as far as the application is concerned. > - Overriding the insertion operator for specific exceptions only works > if the idl has been compiled. Another technique is needed if it is to > work uniformly for both compiled and DII/DSI. In that case, the only option is to overload on UserException and SystemException and to then switch on the rep ID at run time. > Once we have defined a > particular behavior for operator<<(Exception&) we can't take it > back. > Better to take longer to get it right than to get it wrong. My point is that overloading operator<<(Exception &) does *not* take anything away from the application, because if it does the wrong thing, I can overload on UserException and SystemException as well to implement whatever I want. I don't think we are closing any doors at all by overloading operator<<(Exception &). So, can you think about the modified proposal please? Use _id() to return the rep ID and use _name() to get the name if possible, and the rep ID otherwise? I think that would address the needs of applications and it doesn't nail down anything that an application might want to do differently. Cheers, Michi. -- Michi Henning +61 7 33654310 DSTC Pty Ltd +61 7 33654311 (fax) University of Qld 4072 michi@dstc.edu.au AUSTRALIA http://www.dstc.edu.au/BDU/staff/michi-henning.html Return-Path: X-Authentication-Warning: tigger.dstc.edu.au: michi owned process doing -bs Date: Wed, 9 Sep 1998 12:40:40 +1000 (EST) From: Michi Henning To: Paul H Kyzivat cc: Jonathan Biggar , cxx_revision@omg.org Subject: Re: Proposal for issues 234, 253, 259, 260, 266 Content-ID: On Tue, 8 Sep 1998, Paul H Kyzivat wrote: > > Then, if the programmer wants to use the "standard" behavior, he just > > defines the following overloaded operators: > > > > ostream &operator <<(ostream &o, CORBA::Exception &e) > > { > > e.insert(o); > > return o; > > } > > > > ostream &operator <<(ostream &o, CORBA::Exception *e) > > { > > e->insert(o); > > return o; > > } > > > > Otherwise, he can define his own insertion and extraction operators. > > This like this more. It avoids preempting the insertion operators on > Exception, and isn't especially burdensome. Hmmm... As I said previously, my proposal suggested to *only* overload operator<< for CORBA::Exception, *not* for UserException, SystemException, or any specific exception. In other words, my proposal would not preempt anything. More to the point though... What should the above insert() function print? The name, the fully-qualified name, or the rep ID? I think we haven't solved the core problem yet... Cheers, Michi. -- Michi Henning +61 7 33654310 DSTC Pty Ltd +61 7 33654311 (fax) University of Qld 4072 michi@dstc.edu.au AUSTRALIA http://www.dstc.edu.au/BDU/staff/michi-henning.html Return-Path: Date: Wed, 09 Sep 1998 08:50:42 -0400 From: Paul H Kyzivat Organization: NobleNet To: Michi Henning CC: Jonathan Biggar , cxx_revision@omg.org Subject: Re: Proposal for issues 234, 253, 259, 260, 266 References: Michi Henning wrote: > > On Tue, 8 Sep 1998, Paul H Kyzivat wrote: > > > > Then, if the programmer wants to use the "standard" behavior, he > just > > > defines the following overloaded operators: > > > > > > ostream &operator <<(ostream &o, CORBA::Exception &e) > > > { > > > e.insert(o); > > > return o; > > > } > > > > > > ostream &operator <<(ostream &o, CORBA::Exception *e) > > > { > > > e->insert(o); > > > return o; > > > } > > > > > > Otherwise, he can define his own insertion and extraction > operators. > > > > This like this more. It avoids preempting the insertion operators > on > > Exception, and isn't especially burdensome. > > Hmmm... As I said previously, my proposal suggested to *only* > overload > operator<< for CORBA::Exception, *not* for UserException, > SystemException, > or any specific exception. In other words, my proposal would not > preempt anything. > > More to the point though... What should the above insert() function > print? > The name, the fully-qualified name, or the rep ID? I think we > haven't > solved the core problem yet... Well, this was Jonathan's proposal, not mine, but I interpretted it as a partial response to you, not a full one. As such, it doesn't stand alone, but needs to be combined with yours. Perhaps this "insert" operation could take the place of the _name operation in your more recent response. (Of course it can't really be called "insert", but we can deal with that after we agree on the functionality.) It would be responsible for inserting some reasonable representation of the exception into a stream, using information available to it. As Jonathan points out, by making this a member function and leaving it to the user to define the insertion operators to call it, we give the user the ultimate freedom to decide whether or not to use it. By making it a function that writes to a stream rather than one that returns a string, we give it a lot more flexibility in what it should print. If it returns a constant string then that string must exist somewhere as a constant or else we have memory management problems. If it returns a dynamically allocated string then the caller has the burden of freeing it, which rules out a one line definition of the insertion operator. I have mixed feelings on how much to standardize this. There are a lot of options for how this might be handled (on an exception by exception basis) when IDL is compiled. It would be nice to allow compilers the freedom to do something nice here. When using the DII/DSI in the absence of any compiled IDL, there are a lot fewer options. But code that is using the DII/DSI is probably a lot more sophisticated and able to deal with this on its own, so it isn't so important that there be an easy and convenient way to get a nice error message in that environment. I am going leave this one here and continue the discussion in reply to your other message. Return-Path: Date: Wed, 09 Sep 1998 12:19:50 -0400 From: Paul H Kyzivat Organization: NobleNet To: Michi Henning CC: cxx_revision@omg.org Subject: Re: Proposal for issues 234, 253, 259, 260, 266 References: Michi Henning wrote: > > Sure. However, it is generally *impossible* to print the fully > qualified > name. It is not marshaled, so the only other place it could come > from > is the IFR, which is optional. I don't think we are understanding each other. My point is not that the name is carried on the wire, but that the name of the class that instantiates the exception in the receiver has a name. In all cases of compiled stubs this will be the case - you can't compile the stub without compiling the raises clause that references all the exceptions that might be raised. Even in the case of the DII, the preferred path is for the exception to be known and instantiated locally. If it is not, then the exception must be marshalled in the receiver as a particular, known, user exception, namely CORBA::UnknownUserException. This exception too has a fully scoped name, though not a very informative one. So, I think it is possible to always print a fully scoped name of the exception, and the only time that the repository id might be preferable is when the exception is UnknownUserException. It would be better to do special case handling of that one. > It is *guaranteed* not to be available when using the DII. That is > because > the fully-qualified name is not marshaled, only the repository ID. > Given the repository ID, it is possible to reconstruct the > fully-qualified > name only in the presence of an IFR. However, the IFR is optional. > This > means we cannot add a function to the C++ mapping that requires the > fully qualified to be returned. See above. > > The ambiguity of only showing the name, but not the fully-qualified > name > is really no problem. You are right, there may be many different > NotFound > exceptions in different scopes. However, the probability that the > *same* > operation will return two or more different NotFound exceptions > is small. The following is highly unlikely: > > interface foo { > void op() raises(X::NotFound, Y::NotFound, > Z::NotFound); > }; While the significance of an exception may only be fully understood in the context of the invocation where it is used (not just operation name, but arguments too), in practice I only rarely deal with them at that granularity. Usually I will wrap a fairly large block of statements in a try/catch and handle them as a group. The bigger the groups of statements can be the easier the code is to write and to read. The number of try and catch statements goes up when it is necessary to handle more cases in an individualized way. The more precise the "standard" error message is, the fewer try and catch statements I have to write. You are correct that it is unlikely that a single operation will raise two different NotFound exceptions. But I might have code that first tries to find and use either a name service or a trader service, where each might raise its own NotFound exception. (Only an example, I don't know if the trader service has a NotFound exception.) > > Furthermore, the fully-qualified name of an exception is *NOT* a > unique > name. I can have two different exception types with the same > fully-qualified > name by using #pragma to change the repository IDs. It's filthy, but > legal. If anybody actually does that, for any reason other than to reorganize a namespace, they should be shot. If they do, there is nothing we can do about it anyway. > > The *ONLY* unique handle to a type is the repository ID, full stop. > See scoped name discussion above. > Exactly. Further, what are you going to show for the following rep ID > as the fully qualified name? > > IDL:xxx/yyy/zzz:1.0 > > Will you show > > xxx::yyy::zzz > or > yyy::zzz > or > zzz ? I am not advocating turning the repository id into a scoped name. If this is all that is available, (only in the case of UnknownUserException), print the whole thing by default, perhaps in the form: CORBA::UnknownUserException(IDL:xxx/yyy/zzz:1.0). *If* the user wants to print an abreviated form then I would probably print the unscoped name for any exception other than UnknownUserException, and just print "zzz" from the repository id, which in this case would be the same name as the unscoped name. I am still thinking about how a user could express a preference for the long or short form. Perhaps an argument on the "insert" operation??? > OK. Modified proposal: > > Add an _id() member function that returns the repository ID > of > the exception. This is a convenience function that makes it > unnessary to fiddle with the type code of an exception. > > Add a second function called _name(). It prints the > unqualified > name of the exception if available, and the repository ID > otherwise. > > Specify that the inserters for CORBA::Exception insert what > is returned by _name(). If the application wants something > else, > like the repository ID always, it can overload the inserters > for UserException and SystemException to achieve this. > > This should give us the best of both worlds. _id() always returns > the > repository ID, which is guaranteed to be available. _name() returns > something suitable for printing error messages. If the exception > name is available, it prints that, otherwise it falls back on the > rep ID. How about this instead: - The following member functions declared on CORBA::Exception: // return the actual repository id of the exception virtual const char* _repository_id() const; // return the scoped name of the exception class virtual const char* _scoped_name() const; // display a representation of the exception on a stream virtual ostream& _display( ostream& stm, Boolean long_form=1) const; - I used _repository_id because the term "id" is heavily overloaded in the orb. This provides a source of information for users to interpret the exception themself. It normally returns the repository id of the exception that the class implements. In the case of UndefinedUserException it returns the repository_id from the typecode in the Any it contains. - The _scoped_name operation always returns a fully scoped name in the usual format with components separated by "::". In principle this name ought to be available from the compiler via type_info, but as far as I know that isn't reliably available and the results are not consistent from compiler to compiler. This is also a source of information for users to interpret an exception themselves. - The _display operation is a renamed version of Jonathan's "insert". The optional long_form argument selects between fully qualified names and concise, user friendly names. Its contract is to display a rendition of the exception on the stream. The default definition on Exception when long_form is true will display the result of _scoped_name() except if the exception is UnknownUserException, in which case it displays the result of _repository_id(). When long_form is false, it will display only the last component of the scoped name; in the case of UnknownUserException it will display the last "component" of an IDL form repository id or otherwise display the whole thing. - Individual orbs can generate custom implementations of _display for subclasses of Exception in order to render more information about the members of the exception. > How would you print this exception? > > union u switch(long) { > case 0: > sequence aaa; > case 1: > sequence bbb; > case 2: > float ccc[100]; > }; > > exception E { > u uu; > char c; > sequence uus; > }; > > I know this sucks -- the point is that there does not appear to be > a general way (at least not an easy or meaningful one) to print > the contents of arbitrary exceptions. It is certainly possible to come up with a canonical form - it is just a form of serialization. But doing it in a way that is reasonable to display to a human being is difficult. I don't advocate trying to come up with a standard way of doing it, but I wouldn't preclude someone trying to come up with something useful as orb added value. Return-Path: X-Authentication-Warning: fatcat.dstc.edu.au: michi owned process doing -bs Date: Wed, 16 Sep 1998 12:19:27 +1000 (EST) From: Michi Henning To: Jonathan Biggar cc: Paul H Kyzivat , cxx_revision@omg.org Subject: Re: Proposal for issues 234, 253, 259, 260, 266 On Tue, 8 Sep 1998, Jonathan Biggar wrote: > A better idea: define virtual member functions in each insert class: > > class Exception { > public: > ... > void insert(ostream &); > ... > }; > > Then, if the programmer wants to use the "standard" behavior, he just > defines the following overloaded operators: > > ostream &operator <<(ostream &o, CORBA::Exception &e) > { > e.insert(o); > return o; > } > > ostream &operator <<(ostream &o, CORBA::Exception *e) > { > e->insert(o); > return o; > } > > Otherwise, he can define his own insertion and extraction operators. Jon, I don't understand how this differs from overriding the overloaded << operator, at least not in principle. What do we gain by not defining operator<< on CORBA::Exception? I still think there should be a way for a programmer to simply insert an exception into an ostream just like a string, and have at least some sort of message come out. What you suggest works of course, but still requires everyone to define their own operator<<. Why force programmers to do this? What am I missing? Cheers, Michi. Return-Path: X-Authentication-Warning: fatcat.dstc.edu.au: michi owned process doing -bs Date: Wed, 16 Sep 1998 12:29:28 +1000 (EST) From: Michi Henning To: Paul H Kyzivat cc: cxx_revision@omg.org Subject: Re: Proposal for issues 234, 253, 259, 260, 266 Content-ID: On Wed, 9 Sep 1998, Paul H Kyzivat wrote: > How about this instead: > > - The following member functions declared on CORBA::Exception: > // return the actual repository id of the exception > virtual const char* _repository_id() const; > // return the scoped name of the exception class > virtual const char* _scoped_name() const; > // display a representation of the exception on a stream > virtual ostream& _display( > ostream& stm, Boolean long_form=1) const; > > - I used _repository_id because the term "id" is heavily overloaded > in > the orb. This provides a source of information for users to > interpret > the exception themself. It normally returns the repository id of the > exception that the class implements. In the case of > UndefinedUserException it returns the repository_id from the > typecode in > the Any it contains. I think that's UnknownUserException. I like the idea of showing the repository ID in this case though -- that is useful. > - The _scoped_name operation always returns a fully scoped name in the > usual format with components separated by "::". In principle this name > ought to be available from the compiler via type_info, but as far as I > know that isn't reliably available and the results are not consistent > from compiler to compiler. This is also a source of information for > users to interpret an exception themselves. Fine. But what does _scoped_name return if the scoped name is not available? This needs to be said. My suggestion is stil that the simple name is the next best thing in this case, and, if even the simple name is not available, it should fall back on the repository ID. > - The _display operation is a renamed version of Jonathan's "insert". > The optional long_form argument selects between fully qualified names > and concise, user friendly names. Its contract is to display a rendition > of the exception on the stream. The default definition on Exception when > long_form is true will display the result of _scoped_name() except if > the exception is UnknownUserException, in which case it displays the > result of _repository_id(). In other words, it does what I suggested should be done by _scoped_name()? I think we have one method too many here -- given _repository_id() and _scoped_name() as I described it above, we don't need _display(). Instead, I still suggest to overload operator<< on CORBA::Exception. This does what _display does, but has the advantage that inserting an exception directly onto an ostream becomes portable (every ORB I know of has this already anyway, as a vendor-specific extension). Cheers, Michi. -- Michi Henning +61 7 33654310 DSTC Pty Ltd +61 7 33654311 (fax) University of Qld 4072 michi@dstc.edu.au AUSTRALIA http://www.dstc.edu.au/BDU/staff/michi-henning.html Return-Path: Sender: jon@floorboard.com Date: Tue, 15 Sep 1998 21:03:14 -0700 From: Jonathan Biggar To: Michi Henning CC: Paul H Kyzivat , cxx_revision@omg.org Subject: Re: Proposal for issues 234, 253, 259, 260, 266 References: Michi Henning wrote: > > On Tue, 8 Sep 1998, Jonathan Biggar wrote: > > > A better idea: define virtual member functions in each insert > class: > > > > class Exception { > > public: > > ... > > void insert(ostream &); > > ... > > }; > > > > Then, if the programmer wants to use the "standard" behavior, he > just > > defines the following overloaded operators: > > > > ostream &operator <<(ostream &o, CORBA::Exception &e) > > { > > e.insert(o); > > return o; > > } > > > > ostream &operator <<(ostream &o, CORBA::Exception *e) > > { > > e->insert(o); > > return o; > > } > > > > Otherwise, he can define his own insertion and extraction > operators. > > Jon, > > I don't understand how this differs from overriding the overloaded > << operator, at least not in principle. > > What do we gain by not defining operator<< on CORBA::Exception? > > I still think there should be a way for a programmer to simply > insert > an exception into an ostream just like a string, and have at least > some > sort of message come out. What you suggest works of course, but > still > requires everyone to define their own operator<<. Why force > programmers > to do this? What am I missing? The reason is to provide standardized behavior (in the insert function) but not prohibit the programmer from being able to provide his own operator << for any given exception class. -- Jon Biggar Floorboard Software jon@floorboard.com jon@biggar.org Return-Path: Sender: jon@floorboard.com Date: Tue, 15 Sep 1998 22:52:49 -0700 From: Jonathan Biggar To: Michi Henning CC: Paul H Kyzivat , cxx_revision@omg.org Subject: Re: Proposal for issues 234, 253, 259, 260, 266 References: Michi Henning wrote: > Sorry, maybe I'm thick, but I still don't get it. I suggested to > define: > > ostream &operator<<(ostream &, const CORBA::Exception &); > ostream &operator<<(ostream &, const CORBA::Exception *); > > Even with this in place, I can *still* provide my own operator<< for > any > exception class: > > ostream &operator<<(ostream &, const CORBA::SystemException > &); > ostream &operator<<(ostream &, const CORBA::SystemException > *); > > I can write these myself and change the formatting for all system > exceptions > at once. I can also further override this for any specific system > exception: > > // Special operators just for BAD_PARAM formatting > ostream &operator<<(ostream &, const CORBA::BAD_PARAM &); > ostream &operator<<(ostream &, const CORBA::BAD_PARAM *); > > The same thing works for user exceptions. > > So, am I missing something here? If we *only* provide operator<< for > the *base* class CORBA::Exception, no doors are closed at all, and I > can > still override anything I like for more specialized formatting. But > the > advantage is that I get to insert any exception at all into an > ostream > without having to write code, because the operator is guaranteed to > be overridden for the base class. > > My apologies if I'm just being dense... I understand your "hack" which works, although I don't consider it overly elegant. :-) What I am suggesting, is that if we want to predefine a "standard" format for inserting an exception into an ostream, then we should do it as a virtual function "insert", not as operator <<. Then if the programmer wants the standard behavior for a given exception class (and its decendents), he just defines operator << to call the insert function. It seems to me that for your global operator << to work right, it needs to call some virtual function defined on CORBA::Exception to achieve the correct polymorphism. All my proposal does is to make that function explicit. -- Jon Biggar Floorboard Software jon@floorboard.com jon@biggar.org Return-Path: X-Authentication-Warning: fatcat.dstc.edu.au: michi owned process doing -bs Date: Wed, 16 Sep 1998 14:19:27 +1000 (EST) From: Michi Henning To: Jonathan Biggar cc: Paul H Kyzivat , cxx_revision@omg.org Subject: Re: Proposal for issues 234, 253, 259, 260, 266 On Tue, 15 Sep 1998, Jonathan Biggar wrote: > > What do we gain by not defining operator<< on CORBA::Exception? > > > > I still think there should be a way for a programmer to simply > insert > > an exception into an ostream just like a string, and have at least > some > > sort of message come out. What you suggest works of course, but > still > > requires everyone to define their own operator<<. Why force > programmers > > to do this? What am I missing? > > The reason is to provide standardized behavior (in the insert > function) > but not prohibit the programmer from being able to provide his own > operator << for any given exception class. Sorry, maybe I'm thick, but I still don't get it. I suggested to define: ostream &operator<<(ostream &, const CORBA::Exception &); ostream &operator<<(ostream &, const CORBA::Exception *); Even with this in place, I can *still* provide my own operator<< for any exception class: ostream &operator<<(ostream &, const CORBA::SystemException &); ostream &operator<<(ostream &, const CORBA::SystemException *); I can write these myself and change the formatting for all system exceptions at once. I can also further override this for any specific system exception: // Special operators just for BAD_PARAM formatting ostream &operator<<(ostream &, const CORBA::BAD_PARAM &); ostream &operator<<(ostream &, const CORBA::BAD_PARAM *); The same thing works for user exceptions. So, am I missing something here? If we *only* provide operator<< for the *base* class CORBA::Exception, no doors are closed at all, and I can still override anything I like for more specialized formatting. But the advantage is that I get to insert any exception at all into an ostream without having to write code, because the operator is guaranteed to be overridden for the base class. My apologies if I'm just being dense... Cheers, Michi. -- Michi Henning +61 7 33654310 DSTC Pty Ltd +61 7 33654311 (fax) University of Qld 4072 michi@dstc.edu.au AUSTRALIA http://www.dstc.edu.au/BDU/staff/michi-henning.html Return-Path: X-Authentication-Warning: fatcat.dstc.edu.au: michi owned process doing -bs Date: Wed, 16 Sep 1998 16:13:44 +1000 (EST) From: Michi Henning To: Jonathan Biggar cc: Paul H Kyzivat , cxx_revision@omg.org Subject: Re: Proposal for issues 234, 253, 259, 260, 266 On Tue, 15 Sep 1998, Jonathan Biggar wrote: > I understand your "hack" which works, although I don't consider it > overly elegant. :-) What I am suggesting, is that if we want to > predefine a "standard" format for inserting an exception into an > ostream, then we should do it as a virtual function "insert", not as > operator <<. Then if the programmer wants the standard behavior for > a > given exception class (and its decendents), he just defines operator > << > to call the insert function. > > It seems to me that for your global operator << to work right, it > needs > to call some virtual function defined on CORBA::Exception to achieve > the > correct polymorphism. All my proposal does is to make that function > explicit. Hey, my original proposal had precisely that virtual function, call _name(). So, the function was explicit all along. Suggestion: Let's add a virtual function that returns some sort of string. Please, let's also overload operator<< for CORBA::Exception *only*. This will enable me to write precisely what you find in a lot of code already, because vendors already have provided this as an extension: try { // ... } catch (CORBA::Exception &e) { cerr << e << endl; } If we do it this way, we can have our cake and it too? ;-) Cheers, Michi. Return-Path: Date: Mon, 21 Sep 1998 11:59:06 -0400 From: Paul H Kyzivat Organization: NobleNet To: Michi Henning CC: cxx_revision@omg.org Subject: Re: Proposal for issues 234, 253, 259, 260, 266 References: Michi Henning wrote: > > On Wed, 9 Sep 1998, Paul H Kyzivat wrote: > > > How about this instead: > > > > - The following member functions declared on CORBA::Exception: > > // return the actual repository id of the exception > > virtual const char* _repository_id() const; > > // return the scoped name of the exception class > > virtual const char* _scoped_name() const; > > // display a representation of the exception on a stream > > virtual ostream& _display( > > ostream& stm, Boolean long_form=1) const; > > > > - I used _repository_id because the term "id" is heavily > overloaded > in > > the orb. This provides a source of information for users to > interpret > > the exception themself. It normally returns the repository id of > the > > exception that the class implements. In the case of > > UndefinedUserException it returns the repository_id from the > typecode in > > the Any it contains. > > I think that's UnknownUserException. Yes, my fingers typed the wrong thing. (But I was pure of thought!) > I like the idea of showing the repository > ID in this case though -- that is useful. This made the most sense to me. It is the same repid as if the exception had been known. > > > - The _scoped_name operation always returns a fully scoped name in > the > > usual format with components separated by "::". In principle this > name > > ought to be available from the compiler via type_info, but as far > as > I > > know that isn't reliably available and the results are not > consistent > > from compiler to compiler. This is also a source of information > for > > users to interpret an exception themselves. > > Fine. But what does _scoped_name return if the scoped name is not > available? This is a generated, compiled, class. It is up to the idl code generator to make the name available in order to support this feature. So how can it not be available? > This needs to be said. My suggestion is stil that the simple name > is the next best thing in this case, and, if even the simple name is > not > available, it should fall back on the repository ID. My point is that these are *different* things, and there should be independent ways of requesting each. In this proposal, both values are always available. > > > - The _display operation is a renamed version of Jonathan's > "insert". > > The optional long_form argument selects between fully qualified > names > > and concise, user friendly names. Its contract is to display a > rendition > > of the exception on the stream. The default definition on > Exception > when > > long_form is true will display the result of _scoped_name() except > if > > the exception is UnknownUserException, in which case it displays > the > > result of _repository_id(). > > In other words, it does what I suggested should be done by > _scoped_name()? > I think we have one method too many here -- given _repository_id() > and > _scoped_name() as I described it above, we don't need _display(). Both the repository id and the scoped name are useful information, and allow a user to construct an error message in a variety of ways. The _display() operation provides additional logic combining these in one or two distinct ways. It has a different contract than do the other two functions. > > Instead, I still suggest to overload operator<< on CORBA::Exception. > This does what _display does, but has the advantage that inserting > an > exception directly onto an ostream becomes portable (every ORB I > know > of has this already anyway, as a vendor-specific extension). I would prefer to put the definitions of operator<< into an optional header file. Then I can omit if I wish to redefine. But I don't feel strongly about this as long as the real logic is delegated to a member function and the various behaviors are factored into distinct functions. Paul P.S. Sorry to be so long responding, but I was at the OMG meeting last week. Return-Path: X-Sender: vinoski@mail.boston.iona.ie Date: Mon, 21 Sep 1998 14:33:44 -0400 To: Paul H Kyzivat From: Steve Vinoski Subject: Re: Proposal for issues 234, 253, 259, 260, 266 Cc: cxx_revision@omg.org References: At 11:59 AM 9/21/98 -0400, Paul H Kyzivat wrote: >I would prefer to put the definitions of operator<< into an optional >header file. Then I can omit if I wish to redefine. But I don't feel >strongly about this as long as the real logic is delegated to a member >function and the various behaviors are factored into distinct functions. Two problems with this: 1) The standard says nothing at all about the presence of header files, let alone their contents. How can we mandate anything related to them? 2) Putting the declaration into a header file won't help unless the definition can be guaranteed to be inlined, which of course is impossible given that inline is just a hint to the C++ compiler. As long as the definition lives in a library somewhere that is linked with the application, defining your own version will cause link-time errors. I don't see how we can standardize such implementation details. --steve Return-Path: Date: Mon, 21 Sep 1998 17:40:29 -0400 From: Paul H Kyzivat Organization: NobleNet To: Steve Vinoski CC: cxx_revision@omg.org Subject: Re: Proposal for issues 234, 253, 259, 260, 266 References: <199809211833.OAA06062@boston.iona.ie> Steve Vinoski wrote: > > At 11:59 AM 9/21/98 -0400, Paul H Kyzivat wrote: > >I would prefer to put the definitions of operator<< into an > optional > >header file. Then I can omit if I wish to redefine. But I don't > feel > >strongly about this as long as the real logic is delegated to a > member > >function and the various behaviors are factored into distinct > functions. > > Two problems with this: > > 1) The standard says nothing at all about the presence of header > files, let > alone their contents. How can we mandate anything related to them? This isn't quite true. There has been recent discussion about the fabled "orb.h". Given that one header file has been mandated, why not another? > > 2) Putting the declaration into a header file won't help unless the > definition can be guaranteed to be inlined, which of course is > impossible > given that inline is just a hint to the C++ compiler. As long as the > definition lives in a library somewhere that is linked with the > application, defining your own version will cause link-time > errors. I > don't > see how we can standardize such implementation details. I checked both the ARM and the Dec 96 Draft 2 of the C++ spec. (I don't have anything newer handy.) According to the ARM (at least back to 92), file scope function definitions that are declared inline are implicitly internal linkage, so there should be no problem with link-time errors. Draft 2 changed that language. In it, an inline function need not be expanded inline but even so it must follow all the other rules for inline functions. It then states: "An inline function shall be defined in every translation unit in which it is used and have the same definition in every case." While the last point is a restriction on usage rather than implementation, it clearly permits the definition in multiple compilation units so long as it is the same definition. All this means is that if an optional header file defining operator<< was provided, it could not be used in some compilation units while using a different definition in other compilation units. That would be the user's problem to enforce, not ours. So, I don't see a problem with this approach. On the other hand I don't consider this a big deal, so I won't be unduely disturbed if the mapping is required for CORBA::Exception, as long as it can be overridden at the SystemException and UserException level. Return-Path: X-Authentication-Warning: fatcat.dstc.edu.au: michi owned process doing -bs Date: Tue, 22 Sep 1998 07:57:43 +1000 (EST) From: Michi Henning To: Paul H Kyzivat cc: Steve Vinoski , cxx_revision@omg.org Subject: Re: Proposal for issues 234, 253, 259, 260, 266 Content-ID: On Mon, 21 Sep 1998, Paul H Kyzivat wrote: > > Two problems with this: > > > > 1) The standard says nothing at all about the presence of header > > files, let > > alone their contents. How can we mandate anything related to them? > > This isn't quite true. There has been recent discussion about the > fabled > "orb.h". Given that one header file has been mandated, why not > another? That's "orb.idl", not "orb.h". What is OK at the IDL level isn't necessarily OK at the C++ level. > All this means > is that if an optional header file defining operator<< was provided, > it > could not be used in some compilation units while using a different > definition in other compilation units. That would be the user's > problem > to enforce, not ours. I still don't understand why operator<< for Exception would have to be optional? > So, I don't see a problem with this approach. On the other hand I don't > consider this a big deal, so I won't be unduely disturbed if the mapping > is required for CORBA::Exception, as long as it can be overridden at the > SystemException and UserException level. Yes, that was the intent all along. operator<< for Exception inserts some sort of message -- if I want different formatting, or whatever, I override operator<< for UserException and SystemException myself. Cheers, Michi. Return-Path: X-Sender: vinoski@mail.boston.iona.ie Date: Mon, 21 Sep 1998 18:40:20 -0400 To: Paul H Kyzivat From: Steve Vinoski Subject: Re: Proposal for issues 234, 253, 259, 260, 266 Cc: cxx_revision@omg.org References: <199809211833.OAA06062@boston.iona.ie> At 05:40 PM 9/21/98 -0400, Paul H Kyzivat wrote: >> 1) The standard says nothing at all about the presence of header >> files, let >> alone their contents. How can we mandate anything related to them? > >This isn't quite true. There has been recent discussion about the >> fabled >"orb.h". Given that one header file has been mandated, why not >> another? That's a C mapping issue concerning something that used to be in the spec and was lost when the BOA was tossed out. It does not apply to the C++ mapping or any other language mapping. The only text the C++ mapping contains that even remotely relates to header files is in section 20.1.4 in a discussion of the CORBA module: "The module is automatically accessible from a C++ compilation unit that includes a header file generated from an OMG IDL specification." At best, this only acknowledges the presence of an unnamed header file which I would argue is not normative. >I checked both the ARM and the Dec 96 Draft 2 of the C++ spec. (I don't >have anything newer handy.) > >According to the ARM (at least back to 92), file scope function >definitions that are declared inline are implicitly internal linkage, so >there should be no problem with link-time errors. > >Draft 2 changed that language. In it, an inline function need not be >expanded inline but even so it must follow all the other rules for >inline functions. It then states: "An inline function shall be defined >in every translation unit in which it is used and have the same >definition in every case." > >While the last point is a restriction on usage rather than >implementation, it clearly permits the definition in multiple >compilation units so long as it is the same definition. All this means >is that if an optional header file defining operator<< was provided, it >could not be used in some compilation units while using a different >definition in other compilation units. That would be the user's problem >to enforce, not ours. Yes, but to conform to the C++ spec, we'd have to standardize the function in the optional header as being inline. I didn't make all of my second point clear in my previous email: in my opinion, requiring an inline implementation is an implementation detail that the C++ mapping should not be trying to enforce or standardize. Combine that with adding, for the first time, a requirement for a particular (even optional) header file, and I don't think we're on very solid ground here. --steve Return-Path: Date: Mon, 21 Sep 1998 19:49:22 -0400 From: Paul H Kyzivat Organization: NobleNet To: Steve Vinoski CC: cxx_revision@omg.org Subject: Re: Proposal for issues 234, 253, 259, 260, 266 References: <199809211833.OAA06062@boston.iona.ie> <199809212240.SAA14389@boston.iona.ie> Michi Henning wrote: > > On Mon, 21 Sep 1998, Paul H Kyzivat wrote: > > > > Two problems with this: > > > > > > 1) The standard says nothing at all about the presence of header > > > files, let > > > alone their contents. How can we mandate anything related to > them? > > > > This isn't quite true. There has been recent discussion about the > fabled > > "orb.h". Given that one header file has been mandated, why not > another? > > That's "orb.idl", not "orb.h". What is OK at the IDL level isn't > necessarily > OK at the C++ level. I guess my memory is getting rusty. Steve Vinoski wrote: > > That's a C mapping issue concerning something that used to be in the > spec > and was lost when the BOA was tossed out. It does not apply to the > C++ > mapping or any other language mapping. The only text the C++ mapping > contains that even remotely relates to header files is in section > 20.1.4 in > a discussion of the CORBA module: > > "The module is automatically accessible from a C++ compilation unit > that > includes a header file generated from an OMG IDL specification." > > At best, this only acknowledges the presence of an unnamed header > file > which I would argue is not normative. OK, I'm tired. Too bad from a portability perspective, but that's perhaps another TF. > > >I checked both the ARM and the Dec 96 Draft 2 of the C++ spec. (I > don't > >have anything newer handy.) > > > >According to the ARM (at least back to 92), file scope function > >definitions that are declared inline are implicitly internal > linkage, > so > >there should be no problem with link-time errors. > > > >Draft 2 changed that language. In it, an inline function need not > be > >expanded inline but even so it must follow all the other rules for > >inline functions. It then states: "An inline function shall be > defined > >in every translation unit in which it is used and have the same > >definition in every case." > > > >While the last point is a restriction on usage rather than > >implementation, it clearly permits the definition in multiple > >compilation units so long as it is the same definition. All this > means > >is that if an optional header file defining operator<< was > provided, > it > >could not be used in some compilation units while using a different > >definition in other compilation units. That would be the user's > problem > >to enforce, not ours. > > Yes, but to conform to the C++ spec, we'd have to standardize the > function > in the optional header as being inline. I didn't make all of my > second > point clear in my previous email: in my opinion, requiring an inline > implementation is an implementation detail that the C++ mapping > should > not > be trying to enforce or standardize. Combine that with adding, for > the > first time, a requirement for a particular (even optional) header > file, and > I don't think we're on very solid ground here. I frankly don't see that an optional header file means that the implementation is required to be inline. (Though it is hard to imagine doing a delegation to a member function another way.) But I am tired and it isn't very important, so I will just forget it.