Thread View: comp.std.c++
1 messages
1 total messages
Started by Desmond Dsouza
Tue, 19 Mar 1991 04:35
Dynamic Type checking and Exception Handling (was: Re: type/member tags)
Author: Desmond Dsouza
Date: Tue, 19 Mar 1991 04:35
Date: Tue, 19 Mar 1991 04:35
145 lines
5742 bytes
5742 bytes
This came up in the context of arguing that explicit dynamic type
checking is sometimes needed. In a previous posting I described three
cases where such dynamic type checks were "indispensible" :), the third
being exception handling.
Come to think of it, as I understand exception handling:
The C++ exception handling scheme REQUIRES a limited form
of dynamic type checking, including identifying derived classes.
Objects *may not* need access to their types, but type-IDs are
needed by the run-time system, as are checks of the sort:
"is class X derived from class Y".
Do I understand this correctly ? See the detailed discussion below.
Reid Ellis <rae@utcs.toronto.edu> writes:
> Desmond Dsouza <dsouza@optima.cad.mcc.com> writes:
> >Consider the proposed (now accepted) Exception Handling scheme for
> >C++. The statement:
> > catch (ErrorClass& o) {
> > ....
> > }
> >is supposed to 'catch' a deeply nested call to:
> > throw ErrorClass("someError");
> >
> >Any implementation of this involves a run-time type check, including
> >class derivation, on the object being thrown. Can you say 'Meta-class'?
>
> This is simply overloading based on argument type. Just like having
> methods named "foo(Tbase &)" and "foo(Tderived &)". No "Meta-class"
> required.
>
> Reid
Sorry, but it is *not* simply static overloading. The exception model is:
- you CATCH a CLASS of objects (including derived class instances)
- you THROW an OBJECT ( whose class is determined statically ?? )
The run-time exception handler searches the stack for the first catch
(handler) which can handle the object you are throwing and transfers
control there.
Consider:
--------------------------------------------------
class Error {
virtual msg() {printf ("Error\n");}
};
class File_Error : public Error {
virtual msg() {printf ("File_Error\n");} };
};
main (){
try { read_in_file ("non_existent_file"); } // [1]
catch (File_Error fe) { ... } // [2]
}
// in another compilation unit:
class Permission_Error : public File_Error {
virtual msg() {printf ("Permission_Error\n");} };
};
read_in_file (char* file) {
throw ( Permission_Error (file)); // [3]
}
--------------------------------------------------
Line [2] establishes a handler for the *class* File_Error, and hence
for ALL classes derived from it.
Line [3] raises an exception, by creating and THROWing an *object* of
class Permission_Error. This should transfer control to line [2]
The combined compile-time and run-time system MUST establish, at line
[3], that the class of the thrown object is derived from File_Error.
QUESTION: Is it true that that only the static type of the thrown
object is used in selecting a handler ?
a. If so, we statically know the type being thrown, and at run-time
merely need a derived-class check. Line [3] can pass information
like "Permission_Error:File_Error:Error" to the run-time system,
line [2] encodes "File_Error", and so we transfer to line [2].
We do not need run-time access to the dynamic class of an object.
But what of pointers? Use the statically declared pointer type?
If so, the example below prints: "Error::Permission_Error", and not
"File_Error::Permission_Error", since the static return type is
an Error*, which should not be caught by the File_Error handler.
main () {
try { read_in_file ("non_existent_file"); }
catch (File_Error* fe) { printf("File_error::"); fe->msg(); }
catch (Error* e) { printf("Error::"); e->msg(); }
}
Error* perm_error ();
read_in_file (char* file) { throw ( perm_error() ); }
Error* perm_errror() { return new Permission_Error ; }
b. If not, it appears we need run-time access to the type of an object:
The run-time object would be of dynamic type Permission_Error*, which
would be caught by the File_Error Handler.
The example above would then print: "File_Error::Permission_Error"
I suspect [a] is right. The ARM hints at [a], but is not explicit.
ARM, p 356:
A 'throw-expression' initializes a temporary of the static
type of the operand of 'throw' and uses that temporary to
initialize the appropriately typed variable named in the
handler.
In either case, we need a representation of the class Permission_Error
and its base classes in line [3]. The compiler also encodes into line
[2] some representation of the class File_Error.
Lets call this representation, just for grins :), an 'object'. This
'object' needs to encode a class and its base classes, at least by
name, and needs to know something about initializations (e.g. for
variable 'fe' on line [2]).
The class of this 'object' thus has instances which themselves
represent (some aspects of) classes.
Sounds a lot like a "meta-class" to me.
Desmond D'Souza
--
-------------------------------------------------------------------------------
Desmond D'Souza, MCC CAD Program | ARPA: dsouza@mcc.com | Phone: [512] 338-3324
Box 200195, Austin, TX 78720 | UUCP: {uunet,harvard,gatech,pyramid}!cs.utexas.edu!milano!cadillac!dsouza
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads