Source code transformation

89 views
Skip to first unread message

Trygve Reenskaug

unread,
May 15, 2013, 6:31:32 AM5/15/13
to DCI-object-evolution
On 2013.05.12 23:02, Matthew Browne wrote:
I don't see how true DCI can be implemented in PHP without source code transformation or a custom PHP extension written in C. Of these I think source code transformation would be easier to implement and also have fewer potential installation issues. ....

Source code transformation could be a workable solution in many language environments. I realize that nearly all my Squeak compiler extensions are essentially source code transformation. May be a detailed explanation of how DCI is realized in Squeak can give experts on other languages ideas for their own language. Special source code syntax will be needed to recognize role names and messages passed through roles. But it depends on the low level facilities available if it feasible at all. See statements 5 through 8 below.


Squeak DCI code (Roles are TransferMoneySource  and TransferMoneySink ):
    transfer   
       (TransferMoneySource withdraw: Amount)   
                         ifTrue: [TransferMoneySink deposit].

My compiler extensions translate this into this code that is compiled in the usual manner

  transfer
    ((BB1ContextStack playerForRole: #cc)
            to: #TransferMoneySource
            send: #withdraw:
            withArgs: {BB1ContextStack playerForRole: #Amount})
      ifTrue: [(BB1ContextStack playerForRole: #cc)
                to: #TransferMoneySink
                send: #deposit
                withArgs: {}]


ContextStack is a global (actually a class object).
(ContextStack playerForRole: roleName) returns the rolePlayer.
cc is a hidden role that is always bound to the CurrentContext, #cc is its name.
The DCI Execution Model shows that the CurrentContext can map rolenames to rolePlayer objects. Given these transformations, the code is reduced to:   transfer
    (CurrentContext
            to: #TransferMoneySource
            send: #withdraw:
            withArgs: Amount)
      ifTrue: [
CurrentContext
                to: #TransferMoneySink
                send: #deposit
                withArgs: {}]
The next step is the tricky one: to send a message through a role:
1.    to: roleName send: selector withArgs: argCollection 
 2.       | receiver roleClass compiledMethod |
 3.       receiver := roleMap at: roleName.
 4.       roleClass := self class roleClassForRoleName: roleName.
 5.       roleClass ifNotNil: [compiledMethod := roleClass methodDict at: selector ifAbsent: [nil]].
 6.       compiledMethod
 7.             ifNil: [^receiver perform: selector withArguments: argCollection asArray]
 8.             ifNotNil: [^receiver withArgs: argCollection asArray executeMethod: compiledMethod]


Translation of the statements:
1: Method ignature
 2: local variables declaration
 3. Look up in the roleMap to find the RolePlayer object (roleMap is an instance variable in the Context object).
 4. Find the hidden class that holds the dictionary for roleMethods together with the role name and the Context class name
      The role class name is a concatenation of the context name and the role name.
 5. It may not be possible in all languages: to find the binary (compiled) version of a RoleMethod
 6. test if the compiledMethod ..
 7. ... does not exist. If so, just pass the message to the RolePlayer object for normal handling
 8. ... does exist, then  execute it in the context of the RolePlayer object  This may not be possible in all languages.

The complete code is in the BabyIDE Squeak image, of course. (http://fulloo.info/Downloads/baby-downloads.html)

P.S.
Writing this explanation made me see possibilities for simplification. But the critical parts still remain as they are.

Reply all
Reply to author
Forward
0 new messages