DCI Language for .NET

45 views
Skip to first unread message

Rune Funch Søltoft

unread,
Nov 2, 2011, 8:34:43 PM11/2/11
to dci-ev...@googlegroups.com
Hi group
I've been talking about it for almost two years now, and I've restarted my project to create a language that supports DCI numerous times. I have now a prealpha compiler but I have compiled the first fe programs.

There's a lot of things i'd like to improve. First and foremost the roles are currently dynamically typed and I want to support dynamically typed as well as statically typed. I know how I want to do it but I have an error in that part at the moment.

I'm looking for comments on the syntax especially the syntax for defining a role. The general syntax is C#. The money transfer would look like:

public class MoneyTransferContext{

    //Declare the destination role
    role Destination{
    }

    

    //Declare the source role including one role method 'Transfer'
    role Source{

          //I want to replace self with this to denote the role the method belongs to
          //but that will take a bit more work to do.
          void Transfer(decimal amount){
                 self.DecreaseBalance(amount);
                 self.Log("Decreased balance with " + amount);
                 Destination.IncreaseBalance(amount);
                 Destination.Log("Increased balance with " + amount);
         }
    }

   public void Act(){
      Source.Transfer(0m);
   }

   public MoneyTransferContext(dynamic source, dynamic destination){
       Destination = destination;
       Source = source;
   }
}

public class program{

   public static void Main(string[] args){
          var source = new Account();
          var destination = new Account();
          new MoneyTransferContext(source,destination).Act();
    }
}

public class Account{
     public void DecreaseBalance(decimal amount){
          Console.WriteLine("Decrease");
     }

    public void Log(string message){ Console.WriteLine(message);}

    public void IncreaseBalance(decimal amount){
        Console.WriteLine("Increase");
    }  
}


Things to note:
The role methods are private to the context and disappears when the object is no longer playing the role
RoleMethods take precedence over instance methods (and over extension methods as well)
It's the plan to support interface based typing of roles as well as structural and dynamic. The syntax will be

contract {
    //what ever is legal in a C# interface

}

each role can have one contract section.


Comments are much appreciated
Rune


Christian Horsdal Gammelgaard

unread,
Nov 3, 2011, 4:03:48 AM11/3/11
to dci-ev...@googlegroups.com
Hi Rune

That is very cool. I really like that roles come *and* go as needed.

My only real comment is about the role assignment. I like that you use the assigment operator - we can it role assignment after all - but maybe it should be the other way around, maybe a more explicit assignment operator than = (because of the time old argument of = being mathematical equality) :
  source := Source
  destination := Destination
because we say that we assign a role to an object, not the other way around.

Regards, Christian

rune funch

unread,
Nov 3, 2011, 4:09:11 AM11/3/11
to dci-ev...@googlegroups.com
Den 03/11/2011 kl. 09.03 skrev Christian Horsdal Gammelgaard <c.ho...@gmail.com>:

Hi Rune

That is very cool. I really like that roles come *and* go as needed.

My only real comment is about the role assignment. I like that you use the assigment operator - we can it role assignment after all - but maybe it should be the other way around, maybe a more explicit assignment operator than = (because of the time old argument of = being mathematical equality) :
  source := Source
  destination := Destination
because we say that we assign a role to an object, not the other way around.
That's a good point and funny as well. Even when modeling DCI I managed to let the programmers mental model shine through (the assignment in IL is as in the code) instead of the users mental model (in this case another programmer) where as you say the role is assigned to the object and since it then becomes an entirely different operation another operator makes sense. I think i'll use <- because it kinda feels like an injection operator to me. Thanks for the comment

-Rune

Christian Horsdal Gammelgaard

unread,
Nov 3, 2011, 4:31:34 AM11/3/11
to dci-ev...@googlegroups.com
Arrow makes sense to me too. Actually thought of <= before suggesting :=

Risto Välimäki

unread,
Nov 3, 2011, 5:10:54 AM11/3/11
to dci-ev...@googlegroups.com
Hi Rune,

I really like your syntax.

There is just one thing that concerns me:

When your Roles are implicitly usable as "objects" (or are they?) such as:

role Destination { ... }

and then:
Destination = destination;

and:
Destination.IncreaseBalance(amount);

...how would you declare Roles (and instances) in special case, when there is for example:

role Teacher {} and role Student {}, but there are an array of Students involved in the use case?

-Risto


2011/11/3 Rune Funch Søltoft <r...@asseco.dk>

Rune Funch Søltoft

unread,
Nov 3, 2011, 5:22:03 AM11/3/11
to dci-ev...@googlegroups.com


2011/11/3 Risto Välimäki <risto.v...@gmail.com>

Hi Rune,

I really like your syntax.

There is just one thing that concerns me:

When your Roles are implicitly usable as "objects" (or are they?) such as:
They are not. I have an idea of what you mean but to be honest in my mentasl model that statement makes little sense. It's like saying "The orle of hamlet is a person because I can assign it to a person". Remember that a role is a name(space) and a RolePlayer is an object.

 
role Destination { ... }

and then:
Destination = destination;

and:
Destination.IncreaseBalance(amount);

...how would you declare Roles (and instances) in special case, when there is for example:

role Teacher {} and role Student {}, but there are an array of Students involved in the use case?
I like this question and to be honest I have given it any thought at all. My mental model of use cases does not allow for an unknown number of actors, an array of Students seems to imply an unknown number of actors. When I think of an array of students is usually when that system plays the role of class. for each subject they are taught they might interact with another role. Usually called Teacher. I'm interested in whether my beliefs that a use case will always have a know number of actors should be challenged or whether it's sound.

Wonderful comments, thanks
Rune 

Trygve Reenskaug

unread,
Nov 3, 2011, 6:25:37 AM11/3/11
to dci-ev...@googlegroups.com
Hi Rune,
This is good news indeed. An uncompromising DCI language that is based on a reasonably mainstream language will move DCI towards becoming mainstream.

You have to be careful with your role assignments.  Objects cannot be assigned to roles independently, they must be assigned an bloc. This is the only way you can maintain synergy effects; i.e., having a particular configuration of objects with a value exceeding the sum value of its parts. The language should, therefore, not permit the assignment of isolated roles. Role assignments could, for example, be declared in a special language block:
    roleAssignmernts begin { role assignment methods  }
or in any other way that maintains role cohesion.
----
Even worse, I have tried permitting role methods to assign objects to roles. The result was frightening. The Interaction algorithm became utterly unreadable.

As a curiosity, I have also tried letting letting roles be functions. Every reference to a role caused a fresh evaluation of the function. This was even worse than the above.  An example:
    n := Counter + Counter

was not the same as
    n := 2*Counter.
Never dream of doing anything as convoluted as my two disastrous experiments.

Cheers
--Trygve
--

Trygve Reenskaug       mailto: try...@ifi.uio.no

Morgedalsvn. 5A         http://folk.uio.no/trygver/

N-0378 Oslo               Tel: (+47) 22 49 57 27

Norway

Rune Funch Søltoft

unread,
Nov 3, 2011, 6:45:35 AM11/3/11
to dci-ev...@googlegroups.com


2011/11/3 Trygve Reenskaug <try...@ifi.uio.no>

Hi Rune,
This is good news indeed. An uncompromising DCI language that is based on a reasonably mainstream language will move DCI towards becoming mainstream.

You have to be careful with your role assignments.  Objects cannot be assigned to roles independently, they must be assigned an bloc. This is the only way you can maintain synergy effects; i.e., having a particular configuration of objects with a value exceeding the sum value of its parts. The language should, therefore, not permit the assignment of isolated roles. Role assignments could, for example, be declared in a special language block:
    roleAssignmernts begin { role assignment methods  }
or in any other way that maintains role cohesion. 
Indeed and Christians suggestion to change the operator will make it rather easy to verify that the assignment only occurs in a given scope since that operator can be made illegal outside of the assignment block that then leaves the check to ensure that all roles _has_ been assigned when leaving the assignment block

Keep those comments coming :)

-Rune

Trygve Reenskaug

unread,
Nov 5, 2011, 4:53:46 AM11/5/11
to dci-ev...@googlegroups.com
Hi Rune,
I am totally in agreement with you about type checking. I listened  to Black's talk and found him a very agile and insightful person (since I agree with him.) The details:

On the occasion of the opening of the new Ole Johan Dahl building at the University of Oslo on August 22 this year,  Andrew P. Black gave an interesting talk on "Object-oriented programming, challenges for the next fifty years."  His slides are here:
    http://www.cs.pdx.edu/~black/presentations/O-J%20Dahl%20Talk.pdf

For me, the real fun started on slide 48. Object orientation vs. class orientation. Types can be harmful. Three approaches to type-checking.

My preference:
"The “Proceed with caution”, or Edward R. Murrow, interpretation The checker has been unable to prove that there are no type errors in your program. It may work; it may give you a run-time error. Good night, and good luck."

VisualWorks (a Smalltalk dialect) improved on this variant. The checker found some of the type errors, but not all. The programmer could help the checker to find more by including typing information in the class comment. The body of the code remained uncluttered by typing info. (Compact code = easy to overview and few semantic errors).

Cheers
--Trygve

On 2011.11.03 01:34, Rune Funch Søltoft wrote:
...

Trygve Reenskaug

unread,
Nov 13, 2011, 5:11:43 AM11/13/11
to dci-ev...@googlegroups.com
Hi Rune,
Re: the code you posted on 2011.11.03 01:34. Some of my DCI/Squeak
examples may pose special challenges to your compiler. The Dijkstra
example is one of them.

One possible challenge is that both Jim's Ruby and my DCI/Squeak codes
are recursive. This means that all of the three important roles;
CurrentIntersection, EastNeighbor, and SouthNeighbor; can be mapped to
the same object at the same time. Only one of them is active. The other
two are hidden in the recursion stack, waiting to be re-activated during
the unwinding of the stack.

Another possible challenge is unique to my implementation. Two roles,
EastNeighbor and southNeighbor, are mapped to different instances of the
same class. They both respond to the same message,
recomputeTentativeDistance, while the corresponding role methods are
different. This lead to name collision in the implementation with
injection, but the problem is solved (imperfectly) with my
injection-free compiler.

I have tried to transcribe my injection-free role methods to C#, using
your sample code as a pattern. Do you see a problem here? (Bear with my
faulty code; it is my first attempt at C#)

I look forward to the first alpha of your compiler. I will then
translate my examples to your language.

Cheers
--Trygve

====================

public class BB7CalculateShortestPathCTX
{
//Declare the roles
role EastNeighbor
{
}
role SouthNeighbor
{
}
role DistanceDict
{
}
role CurrentContext
{
}
role Map
{
}
role Unvisited
{
}
role CurrentIntersection
{
void computeDistances
{
//This method computes the final distance for the node named
the CurrentIntersection.
if (EastNeighbor !nil)
{
EastNeighbor.recomputeTentativeDistance
};
if (SouthNeighbor !nil)
{
SouthNeighbor.recomputeTentativeDistance
};
Unvisited.remove (self);
if (Unvisited.!empty)
{
CurrentContext..recur
}
}
}
role EastNeighbor
{
void recomputeTentativeDistance
{
// oldDistance, newDistance; local variables
oldDistance := (DistanceDict [self]).distance.
newDistance := (DistanceDict [CurrentIntersection])
distance + (CurrentIntersection.distanceTo (self));
if (newDistance < oldDistance)
{
DistanceDict.Add(self, (new BB7TentativeDistance
(newDistance , CurrentIntersection)
};
Console.WriteLine("EastNeighbor");
}
}
role SouthNeighbor
{
void recomputeTentativeDistance
{
// oldDistance, newDistance; local variables
oldDistance := (DistanceDict [self]).distance.
newDistance := (DistanceDict [CurrentIntersection])
distance + (CurrentIntersection.distanceTo (self));
if (newDistance < oldDistance)
{
DistanceDict.Add(self, (new BB7TentativeDistance
(newDistance , CurrentIntersection)
};
Console.WriteLine("SouthNeighbor");
}
}

public BB7CalculateShortestPathCTX (dynamic geometry, dynamic
originName, dynamic destinationName)
{
.....
}
}



Rune Funch Søltoft

unread,
Nov 14, 2011, 2:41:14 AM11/14/11
to dci-ev...@googlegroups.com
Hi Trygve,
This is great, when times permit I will try to compile (with modifications) your code and give it a run. There's a few inline comments

2011/11/13 Trygve Reenskaug <try...@ifi.uio.no>

Hi Rune,
Re: the code you posted on 2011.11.03 01:34. Some of my DCI/Squeak examples may pose special challenges to your compiler. The Dijkstra example is one of them.

One possible challenge is that both Jim's Ruby and my DCI/Squeak codes are recursive. This means that all of the three important roles; CurrentIntersection, EastNeighbor, and SouthNeighbor; can be mapped to the same object at the same time. Only one of them is active. The other two are hidden in the recursion stack, waiting to be re-activated during the unwinding of the stack.
It's designed to work for this scenario UNLESS two roles each has a method with same signature (name and argument type and order) in that case the code won't even compile. If the consensus is that that's a problem. To roles should be able to have methods with same signatures. Then I might have a problem with the above code.

Another possible challenge is unique to my implementation. Two roles, EastNeighbor and southNeighbor, are mapped to different instances of the same class. They both respond to the same message, recomputeTentativeDistance, while the corresponding role methods are different. This lead to name collision in the implementation with injection, but the problem is solved (imperfectly) with my injection-free compiler.
I don't have injections but rewrites so I'll have to see if I can fix the problems unique to not having injection. So far I'm confident

Trygve Reenskaug

unread,
Nov 16, 2011, 1:45:01 AM11/16/11
to dci-ev...@googlegroups.com
Hi Rune,
Some time ago, you said that some of the DCI logic needs to be moved to runtime. I thought about it when I woke up this morning, and I am confident you are right. I'll do an experiment as soon as I have posted my examples. (Surprise. the posting is more work than I expected.)

Squeak has many classes that have special runtime support. Array is one, CompiledMethod is another. I'll try RTRole, subclass of  nil. I can probably find hints for its specification in the "DCI Execution model" report.

But first, post the examples. And then, the fun starts.

I truly appreciate your innovations and the work you are doing. I'll do my best to support you. Note the word 'support'. You are in the driver's seat.

Cheers
--Trygve

Reply all
Reply to author
Forward
0 new messages