Morphic

Morphic is the parent class of ProxyService and delegates its identity to its defaultHandler class. A Morphic class object can thus change its state and behavior at runtime by changing the defaultHandler. But Proteus makes use of this class through its ProxyService class.

 

The Morphic class inherits from PreinitObject, and directly defines only those properties necessary to concatenate its ‘self’ identity with that of its defaultHandler, a construct() method to initialize its vocabulary and containment relationships, a defaultHandler property, and a propNotDefined() method to capture all other messages and delegate them to its defaultHandler object.

 

In addition, the proteus.h header defines templates for Morphic similar to those provided for Thing, to facilitate shortcut vocabulary, description, and location properties.

 

Suppose we want to make a bowl of class Container. We could use the usual definition:

 

bowl: Container

{

       ‘bowl’ ‘bowl’ @livingRoom

}

 

This object inherits its states and behaviors from Container class. We can examine the definition returned by the @show metacommand:

 

Object        staticBowl    extends       Container

{

       DynamOrAnon: nil UnnamedInternal: nil Transient: nil

 

       properties directly defined by object staticBowl

              vocabWords_ : TypeSString = 'static bowl'

              location : TypeObject = livingRoom

              name : TypeSString = 'static bowl'

              adjective : TypeList = ['static']

              noun : TypeList = ['bowl']

              objRefTag : TypeSString = 'tads#55c'

              tmpAmbient_ : TypeInt = 0

              tmpAmbientWithin_ : TypeInt = 0

              tmpAmbientFill_ : TypeNil = nil

              tmpTrans_ : TypeEnum = transparent

              tmpTransWithin_ : TypeEnum = opaque

              tmpObstructor_ : TypeNil = nil

              tmpObstructorWithin_ : TypeNil = nil

              tmpFillMedium_ : TypeNil = nil

              explicitVisualSenseInfo : TypeNil = nil

}

 

Alternatively, we could define our bowl using the Morphic class, as follows:

 

bowl: Morphic

{

    'bowl' 'bowl' @livingRoom

   

    defaultHandler = Container

}

 

Let’s examine the Morphic bowl using the @show command:

 

Object        morphicBowl   extends       Morphic, tads#64f (Container)

{

       DynamOrAnon: nil UnnamedInternal: nil Transient: nil

 

       properties directly defined by object morphicBowl

              vocabWords_ : TypeSString = 'morphic bowl'

              location : TypeObject = livingRoom

              name : TypeSString = 'morphic bowl'

              defaultHandler : TypeObject = tads#64f (Container)

              isDoingExec_ : TypeNil = nil

              isExecuted_ : TypeTrue = true

              objRefTag : TypeSString = 'tads#577'

              adjective : TypeList = ['morphic']

              noun : TypeList = ['bowl']

              tmpAmbient_ : TypeInt = 0

              tmpAmbientWithin_ : TypeInt = 0

              tmpAmbientFill_ : TypeNil = nil

              tmpTrans_ : TypeEnum = transparent

              tmpTransWithin_ : TypeEnum = opaque

              tmpObstructor_ : TypeNil = nil

              tmpObstructorWithin_ : TypeNil = nil

              tmpFillMedium_ : TypeNil = nil

              explicitVisualSenseInfo : TypeNil = nil

}

 

From this we can see that the Morphic bowl defines a few extra properties: &isDoingExec_ and &isExecuted_. These belong to the PreinitObject class and were generated when the object was constructed.

 

But notice that the Morphic bowl extends an instance of Container, rather than Container class itself. The reason for this is to perform a subtle piece of trickery with the propDefined() method. Consider the following:

 

propDefined(&isOpen)

morphicBowl

staticBowl

PropDefAny

true

true

PropDefDirectly

nil

nil

PropDefInherits

true

true

PropDefGetClass

Container

Container

 

 

By delegating to an instance of the handler class, instead of the class itself we maintain the same relationships of the propDefined() intrinsic method for morphicBowl as for staticBowl. It also allows getPropList() and getPropParams() to remain consistent with that of staticBowl.

 

The states and behaviors of the object are roughly the same as though it inherited from Container, but it still has some differences, due to the structures of their inheritance trees.

 

But the biggest difference is that the Morphic object can change its class structure during runtime. For instance, suppose we want the bowl to change from Container to Surface class when something is put into it. We can code this as  follows:

 

morphicBowl: Morphic

{

    'morphic bowl' 'morphic bowl' @livingRoom

   

    defaultHandler = Container

 

    iobjFor(PutIn)

    {

        action()

        {

            delegated (getHandler())();

            setHandler(Surface);

        }

    }

}

 

Notice that we can’t use the inherited() keyword to pass control down the inheritance tree, we must use the delegated() keyword (the same command that is used by propNotDefined()). Now when an object is put into the bowl it is converted into a Surface. Examining the object definition with the @show metacommand gives us the following:

 

Object        morphicBowl   extends       Morphic, tads#6bd (Surface)

{

       DynamOrAnon: nil UnnamedInternal: nil Transient: nil

 

       properties directly defined by object morphicBowl

              vocabWords_ : TypeSString = 'morphic bowl'

              location : TypeObject = livingRoom

              name : TypeSString = 'morphic bowl'

              actionIobjPutIn(0, 0, nil) : TypeCode

              defaultHandler : TypeObject = tads#6bd (Surface)

              isDoingExec_ : TypeNil = nil

              isExecuted_ : TypeTrue = true

              objRefTag : TypeSString = 'tads#577'

              adjective : TypeList = ['morphic']

              noun : TypeList = ['bowl']

              tmpAmbient_ : TypeInt = 0

              tmpAmbientWithin_ : TypeInt = 0

              tmpAmbientFill_ : TypeNil = nil

              tmpTrans_ : TypeEnum = transparent

              tmpTransWithin_ : TypeEnum = opaque

              tmpObstructor_ : TypeNil = nil

              tmpObstructorWithin_ : TypeNil = nil

              tmpFillMedium_ : TypeNil = nil

              explicitVisualSenseInfo : TypeNil = nil

              contents : TypeList = [brassKey]

              described : TypeTrue = true

}

 

And now the command <<examine bowl>> produces the following display:

 

>x morphic bowl

On the morphic bowl is a brass key.

 

Of course we would probably want to change the vocabulary and name of the bowl to represent its new structure.

 

This file is part of the TADS 3 Proteus Library Extension

Copyright © 2001-2004 Kevin Forchione. All rights reserved.