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

RE: the forward method [dynamic vs. static typing]



On 26 Nov 2003, at 8:25 AM, Steve Dekorte wrote:
>>> 1. forwarding is a very flexible and powerful mechanism
>>
>> For what purposes?  You haven't made any case for it yet.
> Ah, every conversation I've ever had with a ST-er

One problem: I'm not an ST-er.  To the extent that I have a preference for
anything other than "both", I'd say I'm more of a DT-er with an appreciation
for the possibilities of statically-checked types.  My favorite language is
Scheme, although I wish it supported type annotations.

I simply don't accept most of the usual arguments that DT-ers like to put
forth for DT, which often don't take into account what's actually possible
in ST systems, and are commonly based on conflating low-level features of
languages like C/C++ with the fact that those languages are statically
typed.

IOW, I'm saying static typing has been found guilty of crimes in the same
way as the witch in the Monty Python skit: "If she weighs the same as a
duck, she's made of wood.  And therefore, a witch!"

> [...] has always involved them scratching their head at some point
> and saying "but why would you want to do that?". :-) I'd suggest
> looking into how much easier it is to implement distributed objects
> in a language with forwarding.

I've worked on distributed object systems in both dynamically- and
statically- typed languages - sometimes in the same system, using COM or
CORBA.  A dynamically-typed OO language extension product which I developed
supported forwarding via its meta-object protocol, using a design based on
Smalltalk metaclasses.

I don't see any of this as an argument for DT.  In a language like C++, you
can declare proxy classes to implement the interfaces you're interested in
forwarding, and in the implementation of that proxy, the methods invoke the
remoting code.  That proxy implementation can be generated via macros, based
on the same interface definition that the actual classes use.

Java makes this easier by providing a Proxy class to create dynamic
proxies[*].  But if it didn't do that, you could implement it yourself using
Java's reflection capabilities.  The idea that these sorts of dynamic
capabilities are incompatible with static typing is simply outdated.

This isn't a case of asking "why would you want to do that?", but rather
asking "what's the problem?"  And certainly, the problems you seem to
perceive don't appear to have anything to do with static typing per se.

> Either the language supports it, or you end up implementing a runtime on
> top of the language that supports it (which is a big mess).

I think this is an example of confusing what's involved with implementing
forwarding in the presence of static typing, vs. what's involved with
implementing any such system in machine-oriented languages like C or C++.
Again, Java offers a better story here: static typing with features like
reflection and dynamic class loading.

> Which reminds me of Greenspun's Tenth Rule of Programming:
>
> "any sufficiently complicated C or Fortran program contains an ad hoc
> informally-specified bug-ridden slow implementation of half of Common
> Lisp."
>
> Which in our case might be:
>
> "any sufficiently complicated program written in a static system
> contains an ad hoc informally-specified bug-ridden slow implementation
> of half of a dynamic system"

...except that systems like CORBA, Microsoft's COM, and Mozilla's XPCOM can
hardly be characterized that way, and they form the backbone of a lot of
real, working systems.  Again, any buggy aspects of those systems tend to
have much more to do with pointer errors in the C language family, which
can't all be statically prevented, and aren't the fault of the type system.
Repeating myself, Java has a well-specified, bug-free, high-performance
implementation of all the dynamic features I think you've mentioned.

> >> 2. you agree that a type system is useless with forwarding
> >
> >  it's possible to have certain kinds of objects which support
> > forwarding and others which don't.  In previous posts, I described
> > approaches in languages like C++ that actually do that sort of
> > thing in practice.
>
> Are you saying C++ supports forwarding? Btw, I don't mean "can it be
> implemented?". This isn't a question of Turing completeness. The
> question is if it's a natural part of the language. For example, C++
> doesn't even compile the method names into the executable, so
> forwarding is impossible at the level of native C++ message calls.

I'm not talking about Turing completeness.  An interface definition macro
which defines a proxy can let you write client code to access proxy objects
that's perfectly natural C++.  I wouldn't claim that C++ is the ultimate in
this regard, but again, this doesn't have much to do with its static type
system.

> The more dynamic the system, the fewer assumptions you can make at
> compile time and the less useful compile-time checks become. (for
> example, in systems where any object can forward messages, all compile
> time bets are off)
>
>   The more static the system, the more assumptions you can make at
> compile time and the more useful compile-time checks become.
>
> So the two are a bit at odds. Now the problem for real-world
> programming is how to build good systems quickly and easily. Does the
> ideal system lean heavily or completely toward static or dynamic
> systems or off in some other direction entirely?

The real disagreement we have is that I don't believe that even very dynamic
systems, in practice, are as free of assumptions about types as you seem to
imagine.  Aside from these system-level examples of proxies and the like,
can you think of common cases where you're sending messages to objects where
you don't know, even conceptually, which interface those messages belong to?
(Even if your language doesn't have an explicit notion of interface.)  I'm
saying the ideal system is one in which you can tell the system that you
expect a variable will be holding a particular type of value, and ask it to
check that you've done that correctly, along with its consequences, where
they can be determined.  But in cases where you don't want to commit, it
should be possible to remain flexible.  That has some decidability costs,
but that's OK in many cases, and much better than nothing.

> Btw, I'm not entirely against the notion of any form of type checking.
> I just suspect that the ideal system is highly dynamic and so ST is
> unlikely to contribute enough to be worth focusing on at this point.

I assume you're making a claim about some subset of systems, of the type
that you're interested in.  Or do you really mean "the ideal system is
highly dynamic" to apply to all possible systems?

> I'd guess the reason it's still given so much attention has to do with
> the fact that historically, weakly typed systems preceded strongly
> typed ones. Static typing is extremely useful in weakly typed systems
> as a type error that writes on the wrong memory can result in very
> difficult to trace bugs.

Rephrase that more generally to say "Static typing [would be] extremely
useful in dynamically typed systems, as a type error that writes the wrong
kind of value can result in very difficult to trace bugs", and it's still
just as true.

> It seems to be unconsciously assumed that this value extends
> to strongly typed systems despite the fact that strong
> typing eliminates this class of problems.

Oh sure, this whole type theory fad can be explained by an unconscious
assumption.  Lucky you're here to point it out!  OTOH, you seem to be
assuming that just because the errors being experienced are no longer memory
corruption, but are simply type corruption instead, that it's no longer
important to catch them early.  You're recognizing the value of static type
systems for catching type errors involving certain kinds of values, but
denying its value for catching errors involving other kinds of values.  Are
you sure you've analyzed that correctly?

Anton