[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: OT: Language War (Re: "C" Manual)



Lo, on Tuesday, January 1, dman did write:

> On Tue, Jan 01, 2002 at 10:34:25AM -0600, Richard Cobbe wrote:
> | Lo, on Tuesday, January 1, dman did write:
> | 
> | > The strength and staticness of typing are two independent properties.
> | 
> | Also agreed.
> 
> Cool, I'm glad you know this stuff too!

Oh yeah.  I've got *way* too much Scheme/LISP experience to think that
static typing and `strong' typing are the same thing.

> |   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].

Well, in some cases, a sufficiently sophisticated compiler could
determine at compile time that what it thinks is an A will, in fact,
always be a B, thus removing the need for a downcast.  However, I don't
think this sort of proof is possible in the general case.

And you're quite right, the downcast simply appeases the compiler by
telling it, `No, this really is a B.'  The important thing is that you
have the runtime check to verify this.  Without that, nasty things
happen.

> [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)

Yes, Java's casts between primitive types are conversions (as are C's).
Those aren't downcasts, though, as there's no type hierarchy involved
(it is not the case that an int IS-A byte, even though an int can
represent all possible values that a byte can).

> |      [Downcasts] 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.  

I've not worked with Python very much.  Does it do compile-time type
analysis like C++ or Java?  I know that if there were CORBA bindings for
a language like LISP or Scheme, you wouldn't have to worry about
casts---the methods you expect are automatically there.  Presumably the
same applies to Smalltalk, but I'm not sure.

> 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!).

This is one instance, I believe, where there's a very visible tradeoff
between the flexibility of run-time typechecks and the early error
detection provided by compile-time typechecks.  Let's take OCaml
(another language that I'm really not all *that* familiar with).  It has
an object system and checks types at compile time, but it also has a
much more flexible type system than Java's.  Instead of saying than an
object is of type Foo, you instead say that the object has type
    < a : int -> int, b : ('a -> bool) -> 'a list, ... >
which means that the object has *at least* methods a and b, and that a
and b have the indicated types.

However, if you know full well that the object in question *also* has a
method c (of whatever type), you won't be able to invoke it, because the
compiler hasn't been able to prove that the object will always have such
a method.  I would imagine there's some sort of checked downcast
operation to handle this situation.

In short: downcasts are perfectly safe if and only if there's a runtime
check involved.  

> |         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).

Mph.  Don't write off polymorphism (which is what C++ templates
approximate) just because most C++ compilers do a really bad job of
implementing it.  It's a useful concept, and there are better strategies
out there; ML compilers tend to use these instead.  (To be fair, these
strategies have their own costs associated with them, but the code size
doesn't go through the roof.)

(Note, btw, that in the previous paragraph, `polymorphism' does NOT
refer to the OO concept.)

Richard



Reply to: