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

Re: dynamic vs. static typing

 --- Pascal Costanza <costanza@iai.uni-bonn.de>
> Ken Shan wrote:
> > On 2003-11-24T23:02:07+0100, Pascal Costanza
> wrote:
> > 
> >>>As Anton van Straaten explained beautifully, all
> the objects in this
> >>>case respond to some message like "turn off if
> you can", or "can you
> >>>turn off?".
> >>
> >>...but that's a pretty bad idea in general. When
> you say this...
> >>if (object.turnOffSupported()) {
> >>  object.turnOff();
> >>}
> >>...there is a chance that the object is replaced
> in another thread 
> >>between the check and the actual call.
> > 
> > 
> > That wasn't what I had in mind.  A more reasonable
> design of
> > turnOffSupported(), within a relatively
> impoverished type system like
> > Java's, would return a (possibly null) reference
> to an interface that
> > supports turnOff().
> > 
> >     if (TurnOffable object2 =
> object.turnOffable()) {
> > 	object2.turnOff();
> > 	// object.turnOff() should be a type error
> >     }
> > 
> > After all, turnOffable should return a witness for
> its claim that the
> > object can be turned off, and that witness is an
> interface that supports
> > turnOff.
Ok, someone correct me if I'm wrong, but it wouldn't
something like (unchecked Haskell):

tryTo :: (Monad m) => (a -> m ()) -> Dynamic -> m ()
tryTo doIt obj = tryTo' (fromDynamic obj)
    where tryTo' Nothing = return ()
          tryTo' Just a = doIt a

turnOff :: TurnOffable -> IO ()

turnOffAll :: [Dynamic] -> IO ()
turnOffAll things = mapM_ (tryTo turnOff) things

AFAICT the only thing ST "forces" you to do is being
explicit when you want to do something that may fail.
"tryTo" is the primitive function/method call in DTLs.

> ...but you still have a two-step protocol.
> Even
> worse, you can't change 
> the object into one that cannot be turned off
> anymore as long as you 
> have the object2 reference.

In "pure" languages this isn't a problem, because you
don't change objects. If the language is "impure" then
this isn't a problem too because "turnOff" is an
operation with default (e.g. do nothing, throw and
error) semantics, so the system will fall back to the
default one when the object removes his turnOff (e.g.
a Self object with a parent traits slot containing the
default "turnOff", "doesNotUnderstand"), so the object
will maintain the interface and just update the
behaviour of "turnOff" (pseudo-code, block-syntax like
Smalltalk, assuming a "tryAll" method with similar
definition to "mapM_ . tryTo", "--" starts a line

type TurnOffable {
    turnOff : Void

makeDoNothing(some : TurnOffable):Void {
    some.turnOff := [];
makeThrowError(some : TurnOffable):Void {
    some.turnOff := [throw("Doesn't understant

main {
    a : TurnOffable := {turnOff := [print("Turning a
    b : TurnOffable := {turnOff := [print("Turning b
    c : Object := {};
    things : List(Object) := a, b, c;

-- prints both messages
-- changes a
-- prints just b's message
-- changes c type
    c.turnOff := [print("Hello World!")]; 
-- prints b and c messages
-- goes to exception handler somewhere

Again the main difference between STLs and DTLs is
that with STLs you have to explicitly say what will
happen when some message is received (if you want to
support the interface). Also you can't just take away
a method once you have it in the interface, but in
these situations you would accept "Doesn't understand"
exceptions somewhere anyway, so changing the
definition to throw exceptions is probably ok.

Best regards,
Daniel Yokomiso.

"I hope that by having this open dialogue we can live
in harmony. Or failing in that, I'll live in harmony
by myself."
 - Dogbert


Yahoo! Mail: 6MB, anti-spam e antivírus gratuito! Crie sua conta agora: