On Tue, Jan 01, 2002 at 10:34:25AM -0600, Richard Cobbe wrote: | Lo, on Tuesday, January 1, dman did write: | | > On Mon, Dec 31, 2001 at 09:27:36PM -0500, William T Wilson wrote: | > | > | Casting you can't really get away from nor do you really need to. In fact | > | the more strongly typed the language is, the more casting you have to do. | > | > This statement is incorrect. | | Agreed. | | > The strength and staticness of typing are two independent properties. | | Also agreed.
Cool, I'm glad you know this stuff too! | However, I think that the flexibility of a type system is more important | than its `strength' for removing the need for casts. This sounds like a reasonable statement. | When do people use typecasts in C/C++? In my experience, they tend to | happen in the following situations: | 2) downcasts in a class hierarchy, as in Java. (Note that `upcasts' | aren't really casts: if B is a subclass of A, then an instance of B | *is* an instance of A, no cast needed.) This is only needed with unintelligent compiler. *You* know you have a B at runtime, but the compiler doesn't so it whines and complains. Thus you must "cast" the pointer/reference to appease the compiler. The cast in java doesn't do anything else (aside from a runtime verification as well)[1]. | 3) Accessing external data in a callback function. Callbacks in C and | C++ often take a void* parameter that points to data supplied by | the programmer when he registers the callback; to access this data, | it is necessary to cast it back to the original type. I don't know about C++ frameworks that do this, but C's type system certainly requires this. In Java the callback is a class instance anyways (since functions are not objects, nor can you take the address of one). | How do more flexible type systems handle these? | 2) As several people have pointed out, too many downcasts indicate a | design flaw. I agree here. | They are, however, useful in some situations, so (I | believe) many advanced languages with a static type system support | these. However, as in Java, there's a run-time check that goes | with it. C++'s dynamic_cast gets this right. Take CORBA for example. With python, you just have an object with the given methods. No problem, no difficulty. With java you have to use a special "narrow" method to create an instance of a class that implements the interface, but does so in terms of corba calls. With the inflexible type system java uses, the downcast-wannabe is necessary (ugh!). | 3) There are a variety of strategies here. My personal favorite is | to use first-class closures to implement callbacks; the external | data is no longer supplied as a parameter but is simply available | to the callback function due to normal scoping rules. This sounds good to me :-). | If you're using a language without closures, like C++ or Java, | you can hack it up: In java you _have_ to hack it up like this (for example, java.lang.Runnable). | template<typename T> | void register_callback(void (* cb)(T), T data); That's not so bad, if you can stand the bloat this creates (C++ templates are expanded at compile time, thus you get one copy of this function for each type it needs to work with). | > I've heard that haskell has an even better type system, but I haven't | > had time to learn it yet. | | Most of my experience with advanced programming languages has been in | Scheme, which (despite what many people believe) *is* strongly-typed and | type-safe, but it checks all types at runtime rather than compile time. | As a result, I'm not really up on languages with compile-time type | verifications systems, though I've been meaning to investigate them for | a while now. At any rate: I've heard that ML's type system is easier to | learn than Haskell's; you may want to start there first. Ok, I might do that. I've heard a lot about various languages on comp.lang.python, and one particular guru (he's a C++ guru also) frequently mentions Haskell's typeclasses in flamewars regarding type systems. -D [1] with "primitive" types, I think java may do some conversion (certainly with float->int it must), but I'm not totally sure (I think with int->byte it doesn't, just truncates) -- The Lord detests all the proud of heart. Be sure of this: They will not go unpunished. Proverbs 16:7