Implemented the Dijkstra algorithm: lessons learned

162 views
Skip to first unread message

Serge Beaumont

unread,
Dec 11, 2011, 5:55:25 PM12/11/11
to dci-ev...@googlegroups.com
I'm actually proud of myself. I'm really crap at algorithms, but I did it :-). I've pushed the new code to https://github.com/sbeaumont/learn-dci/tree/master/dijkstra where you can browse through the files. I've attached them for good measure. Plonk in a directory and execute the test files.

dci.py - the DCI magic
grid.py - implements a Context that knows of nodes and neighbours
dijkstra.py - can use a grid from grid.py and perform the Dijkstra algorithm over it.
testmanhattan1.py and testmanhattan2.py - the two test cases I took out of Cope's ruby implementation

I've split the grid and Dijkstra code intentionally. I felt that this was a correct separation of concerns.

About lessons learned: the Python implementation works really well, but I'll be looking into a DCI implementation my colleague made in Python that he claims is better. There's still some iffiness that pops up with respect to object identity sometimes, you can't use properties in my version, and his code has a nifty cache to reuse dynamically generated subclasses.

My big issue: state and role scope.

I have an issue with "canonical" DCI stating that roles are pure behavior. In the Dijkstra implementation of Cope he struggles with the same issue. In the Dijkstra context you want to annotate objects with state like "visited", "best previous node" and "best weight" that are totally irrelevant outside of the Dijkstra context. However, in canonical DCI I'd have to add these instance variables to my Data objects just in case they get used by the Dijkstra context, or (and this is what Cope did) plonk that data in the context. I really don't like that, it feels like a workaround. I want to attach state when and where I want to, durn it!

Point is, Python is powerful enough that I can attach state when and where I want, but it's not nearly as elegant as the way roles just disappear when they go out of scope. There's also a namespace issue, because if I start attaching state in the context of a Role/Context it might clash with the name another Role or Context used.

So my boat-rocky question is this: shouldn't we have a notion of "PersistentRole", "StateRole", "RoleState", "DynamicData" or whatever you want to call a bunch of dynamically attached state (with appropriate accessors)? This state might have global scope, context scope or role scope.

DCI Heresy Y/N?

Anyway, have a look at the code. Apart from the above questions and issues it works and it's pretty darn clean compared to a ClassOO implementation! It calculates any grid, not just Manhattan form, muhaha :-)

Grtz,

Serge.


----------
Serge Beaumont, Principal Agile Consultant, Xebia BV
Mobile: +31623813925
Office: Utrechtseweg 49, 1213TL Hilversum, NL, +31355381921
Blog: http://blog.xebia.com/author/sbeaumont
dci.py
dijkstra.py
grid.py
testmanhattan1.py
testmanhattan2.py

ant.ku...@gmail.com

unread,
Dec 12, 2011, 1:48:26 AM12/12/11
to dci-ev...@googlegroups.com
I took the algorithm and stuck it into a toy example for training purposes.  Without DCI.  And I had no problems with identity.  I had the ability to add state to nodes too.

It reminded me of a "view model", namely a model of a model, adapted for a specific MVC view, or in this case just a specific algorithm.

Sadly it made me again question the real value of DCI.  

In the mean time I've picked up Groovy, which through its MOP, has out of the box support for adding methods to individual object, much like I was doing to Java in the summer.  You can compile Groovy scripts straight into Java bytecode within a Java project.  It's entirely interoperable, just as I'd hoped.  So you get the entire Java technology stack, which for me makes Groovy a candidate.  You can write a few likes of code to build a framework to support context stacking and removal of roles after a context completes.

But the dynamic nature of Groovy, and specifically the lack of auto complete for dynamic role methods makes it a non starter for me, purely from the productivity point of view.  But it is nearly there.

So James, instead of talking to Java people, may be the Groovy language designers might be more useful.

Ant

Serge Beaumont

unread,
Dec 12, 2011, 2:19:46 AM12/12/11
to dci-ev...@googlegroups.com
Do you have the example posted somewhere?

ant.ku...@gmail.com

unread,
Dec 12, 2011, 3:41:18 AM12/12/11
to dci-ev...@googlegroups.com
No.

Serge Beaumont

unread,
Dec 12, 2011, 3:48:16 AM12/12/11
to dci-ev...@googlegroups.com
From the brevity of the answer I can infer you're also not going to? :-)

ant.ku...@gmail.com

unread,
Dec 12, 2011, 4:35:59 AM12/12/11
to dci-ev...@googlegroups.com
You mean implementing Dijkstra's algorithm using wrappers?  I don't see the point since its been done satisfactorily before.

Or do you mean the Groovy stuff?

Serge Beaumont

unread,
Dec 12, 2011, 5:20:00 AM12/12/11
to dci-ev...@googlegroups.com
Yes, the groovy stuff.

ant.ku...@gmail.com

unread,
Dec 12, 2011, 6:00:12 AM12/12/11
to dci-ev...@googlegroups.com
I'll see when I can spare the time.  But there's nothing truly magical. And like I said, as im not a fan of dynamic calls, I'm not investing lots of time in DCI at this time.

Trygve Reenskaug

unread,
Dec 12, 2011, 9:33:14 AM12/12/11
to dci-ev...@googlegroups.com
On 2011.12.12 07:48, ant.ku...@gmail.com wrote:
I took the algorithm and stuck it into a toy example for training purposes.  Without DCI.  And I had no problems with identity.  I had the ability to add state to nodes too.

It reminded me of a "view model", namely a model of a model, adapted for a specific MVC view, or in this case just a specific algorithm.

Sadly it made me again question the real value of DCI.  

I'm not surprised. Toy examples cannot be expected to show the benefits of DCI, two of them being clean mental models and readable code. Even the "write code first, think later" approach works if the example is sufficiently simple. I got some help from DCI when I wrote my Shapes animation example  I first used POJO, the result was chaotic code. Then DCI, which  was straight forward. May be a new POJO implementation would be OK; I haven't tried it.

The benefits of DCI may easier to see if you ask somebody other than the original coder to read the code and explain how it works. (The reader being familiar with DCI, of course.)

ant.ku...@gmail.com

unread,
Dec 12, 2011, 1:06:55 PM12/12/11
to dci-ev...@googlegroups.com
It's a toy example, because Dijkstra's algorithm is one too ;-)

You seem to be saying the only way to have clear models and readable code is with DCI.  I disagree.  For my solution I have a domain class called train station.  

To get shortest paths I build a secondary model with "nodes" which provides me with a specific view of a train stations and their neighbours.   All the logic is in a service which contains the algorithm.  

I've separated the state and behaviour, and I have readable and reviewable code.  And my mental model does not differ from the one which the business analyst provided me with because we discussed it at length and the analyst agrees that to determine shortest paths between train stations you need to think in terms of nodes and edges and have a service which provides shortest path solutions.



----- Reply message -----
From: "Trygve Reenskaug" <try...@ifi.uio.no>
To: <dci-ev...@googlegroups.com>
Subject: Implemented the Dijkstra algorithm: lessons learned

rune funch

unread,
Dec 12, 2011, 1:44:56 PM12/12/11
to dci-ev...@googlegroups.com
Where in your code do you see which actual objects (stations) are sending messages (trains) to other objects?

Mvh
Rune

ant.ku...@gmail.com

unread,
Dec 12, 2011, 2:28:46 PM12/12/11
to dci-ev...@googlegroups.com
Hi Rune,

That's not part of the algorithm, is it?  Or what do you mean?

Trygve Reenskaug

unread,
Dec 12, 2011, 2:38:54 PM12/12/11
to dci-ev...@googlegroups.com
Communication is hard. What I tried to say, no doubt unsuccessfully, was that it is easy to write readable code if the problem is sufficiently simple. I don't understand why you introduced trains and stations for the Dijkstra algorithm. Both you and I can write much simpler code that implements the Dijkstra algorithm in a perfectly readable way. We can, for example, simply copy the code given in Wikipedia. Jim's code was intended to illustrate some interesting aspects of DCI, not to show superior code. He even changed the problem to illustrate what he wanted to illustrate. Even somewhat more complex problems can be readable, at least to the programmer himself. The acid test is will be when a reader wants to reason about the code or when a maintainer picks up the code some years later.

I confidently expect that many real sized programs can be made more tractable with DCI. I have no proof since I haven't, as yet, written any real sized program using DCI. You have your expectations, I have mine. A likely outcome is that yes, I am right for some problems. And yes, you are right for other problems. DCI is simply a new tool in the programmer's toolbox.
--

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,
Dec 12, 2011, 2:49:15 PM12/12/11
to dci-ev...@googlegroups.com



Hi Rune,

That's not part of the algorithm, is it?  Or what do you mean?
It's an explicit goal of DCI to make communication between objects a visible part of the code (Trygve phrased that better in his paper on execution model), so that when you read the code you also read which objects communicate. I feel that using proxies (or view models) might hide this information since the proxies are the connected objects and you will have to follow from the proxy to the real object to discover the communication or do I have this feeling simply because I haven't seen your code?
 
-Rune

Ant Kutschera

unread,
Dec 12, 2011, 3:39:36 PM12/12/11
to dci-evolution
Hi Trygve & Rune,

I agree, it's hard to communicate, especially on forums, and that
there will be cases where DCI (or similar) helps and others where it
doesn't. I'm not saying DCI won't help - I'm saying I feel there are
other mechanisms / designs / paradigms that help equally well.

On reflection, I think that Jim's requirements were a little far
fetched. While he was trying to show the problems that can happen, I
don't believe that they really do happen that often. I have been
using view models and other such constructs for years, and had never
even heard of object schizophrenia before encountering this forum.

The train stations are simple domain objects related to the bigger
picture, namely timetable software. In the context of figuring out the
shortest (or rather quickest) path, the train stations and the paths
between them are converted to nodes and edges and Dijkstra's algorithm
is applied.

@Rune: There is no communication between any objects. Perhaps that is
the point. I am manipulating data here using, an algorithm. My
domain model is fully anemic. As such, it is hardly object oriented,
and perhaps that is why I don't need DCI in this case, in order to
make my code readable, reviewable and simple. It is sufficient as it
is. Even if it were in a huge system hiding behind 100s of thousands
of lines of code.

Cheers,
Ant


On Dec 12, 8:38 pm, Trygve Reenskaug <tryg...@ifi.uio.no> wrote:
> Communication is hard. What I tried to say, no doubt unsuccessfully, was
> that it is easy to write readable code if the problem is sufficiently
> simple. I don't understand why you introduced trains and stations for
> the Dijkstra algorithm. Both you and I can write much simpler code that
> implements the Dijkstra algorithm in a perfectly readable way. We can,
> for example, simply copy the code given in Wikipedia. Jim's code was
> intended to illustrate some interesting aspects of DCI, not to show
> superior code. He even changed the problem to illustrate what he wanted
> to illustrate. Even somewhat more complex problems can be readable, at
> least to the programmer himself. The acid test is will be when a reader
> wants to reason about the code or when a maintainer picks up the code
> some years later.
>
> I confidently expect that many real sized programs can be made more
> tractable with DCI. I have no proof since I haven't, as yet, written any
> real sized program using DCI. You have your expectations, I have mine. A
> likely outcome is that yes, I am right for some problems. And yes, you
> are right for other problems. DCI is simply a new tool in the
> programmer's toolbox.
>

> On 2011.12.12 19:06, ant.kutsch...@gmail.com wrote:
>
>
>
>
>
>
>
>
>
> > It's a toy example, because Dijkstra's algorithm is one too ;-)
>
> > You seem to be saying the only way to have clear models and readable
> > code is with DCI.  I disagree.  For my solution I have a domain class
> > called train station.
>
> > To get shortest paths I build a secondary model with "nodes" which
> > provides me with a specific view of a train stations and their
> > neighbours.   All the logic is in a service which contains the
> > algorithm.
>
> > I've separated the state and behaviour, and I have readable and
> > reviewable code.  And my mental model does not differ from the one
> > which the business analyst provided me with because we discussed it at
> > length and the analyst agrees that to determine shortest paths between
> > train stations you need to think in terms of nodes and edges and have
> > a service which provides shortest path solutions.
>
> > ----- Reply message -----
> > From: "Trygve Reenskaug" <tryg...@ifi.uio.no>
> > To: <dci-ev...@googlegroups.com>
> > Subject: Implemented the Dijkstra algorithm: lessons learned
> > Date: Mon, Dec 12, 2011 15:33
>

> > On 2011.12.12 07:48, ant.kutsch...@gmail.com wrote:
> >> I took the algorithm and stuck it into a toy example for training
> >> purposes.  Without DCI.  And I had no problems with identity.  I had
> >> the ability to add state to nodes too.
>
> >> It reminded me of a "view model", namely a model of a model, adapted
> >> for a specific MVC view, or in this case just a specific algorithm.
>
> >> Sadly it made me again question the real value of DCI.
>
> > I'm not surprised. Toy examples cannot be expected to show the
> > benefits of DCI, two of them being clean mental models and readable

> > code. Even the "/write code first, think later/" approach works if the


> > example is sufficiently simple. I got some help from DCI when I wrote

> > my /Shapes /animation example  I first used POJO, the result was


> > chaotic code. Then DCI, which  was straight forward. May be a new POJO
> > implementation would be OK; I haven't tried it.
>
> > The benefits of DCI may easier to see if you ask somebody other than
> > the original coder to read the code and explain how it works. (The
> > reader being familiar with DCI, of course.)
>
> --
>

> Trygve Reenskaug       mailto: tryg...@ifi.uio.no

Trygve Reenskaug

unread,
Dec 14, 2011, 7:32:00 AM12/14/11
to dci-ev...@googlegroups.com


On 2011.12.11 23:55, Serge Beaumont wrote:
-----
About lessons learned: the Python implementation works really well, but I'll be looking into a DCI implementation my colleague made in Python that he claims is better. There's still some iffiness that pops up with respect to object identity sometimes, --.
Any solution with dual identity for the same entity can cause trouble in some situation. The smarter the solution, the harder it can be to find an identity-related bug.  "Canonical" DCI does not have this flaw.

In the same vain, "Canonical" DCI does not touch the Data classes, so there is no danger of name conflicts.

Arguments like "I have worked with xxx for years, and have never had problem with dual identities" is not an argument against a better solution. I want the better solution if I can have it.


My big issue: state and role scope.

I have an issue with "canonical" DCI stating that roles are pure behavior. In the Dijkstra implementation of Cope he struggles with the same issue. In the Dijkstra context you want to annotate objects with state like "visited", "best previous node" and "best weight" that are totally irrelevant outside of the Dijkstra context. However, in canonical DCI I'd have to add these instance variables to my Data objects just in case they get used by the Dijkstra context, or (and this is what Cope did) plonk that data in the context. I really don't like that, it feels like a workaround. I want to attach state when and where I want to, durn it!
In "canonical" DCI, system state belongs in the Data objects. State owned by an interaction belongs in the Context object. In this way, state belonging to a particular interaction does not get confused with state belonging to other interactions.

Jim found a way to give state to the roles in his first  Dijstra/Ruby program. It was an experiment, and he has removed this feature in his later implementations.


Point is, Python is powerful enough that I can attach state when and where I want, but it's not nearly as elegant as the way roles just disappear when they go out of scope. There's also a namespace issue, because if I start attaching state in the context of a Role/Context it might clash with the name another Role or Context used.

So my boat-rocky question is this: shouldn't we have a notion of "PersistentRole", "StateRole", "RoleState", "DynamicData" or whatever you want to call a bunch of dynamically attached state (with appropriate accessors)? This state might have global scope, context scope or role scope.
"Persistent role" is meaningless since a role only exists during an interaction.
DCI Heresy Y/N?
Y

Anyway, have a look at the code. Apart from the above questions and issues it works and it's pretty darn clean compared to a ClassOO implementation! It calculates any grid, not just Manhattan form, muhaha :-)

The Manhattan grid complicates the algorithm, but introduces two roles that essentially do exactly the same: SouthNeighbor and EastNeighbor. A name conflict surfaces if the two role methods have the same name and are injected into the same class. In my latest implementation, the selector is:recomputeTentativeDistance, but the role methods are distinct. The bodies of these two methods may or may not be the same. In my case, they are different in a version where all role methods writes a trace.

I want to stress that I am not belittling other DCI implementations. On the contrary, they are very valuable for making the DCI paradigm available for programming here and now. They may be less than ideal, but never forget Voltaire: "the best is the enemy of the good".

Cheers
--Trygve



Rune Funch Søltoft

unread,
Dec 14, 2011, 8:40:33 AM12/14/11
to dci-ev...@googlegroups.com


2011/12/12 Ant Kutschera <ant.ku...@gmail.com>
@Rune: There is no communication between any objects.  Perhaps that is
the point. 
Well My point is that the real system (the trains and the stations) those connections do exist they are very real. Not modelling them is and abstraction, as in thrown away information. That doesn't mean it's a bad thing just that the information lost. 
We always have to abstract when we go from analog to digital the important part is to do it consciously.
In the case of a safety critical system (systems used for managing trains are, systems for planning time tables might not be) it's required to validate or verify that the system is implemented as described by requirements and design documents.

If you map stations to nodes in an arbitrary graph algorithm then you'll (likely) need to document that mapping to be able to claim verifiability and/or validity, if the code do not map real life objects to mathematical concepts such as nodes and edges but represents them 1:1 you no longer need to document your mappings and transformations they don't exist so there's nothing to document.

You can say "but that's for safety critical applications" and yes it is but can we learn from the law enforced requirements? What's the goal of those requirements? To ensure that the product works as intended!* 

When developing medical equipment up to 70% of the cost is verification and validation and one of the ways to trim the cost is to reduce the size of the documents. When a document is changed all documents below in the document tree must be checked, to ensure that the changes cascade downwards. Changing the requirements might easily result in 10 documents being updated or at least checked but the documents is actually the easy part. You can use a requirement management system to trace requirements from one document to the next, so the list of documents that needs changing can (in the perfect world) be auto generated. However it's very difficult to trace from documents to code. Especially to ordinary OO code where the constraints are weaker (see earlier post on temporal scoping for an example) and where the code for a UC often is distributed over several elements.

If the system we're building is a train management system we'd need to validate that the stations are correctly connected and that the system is not capable of sending trains between two stations that are not connected. We''l never get rid of representing the original graph (railway network) it's only a matter of where we are going to document it. Do we document it in our design documents and verify that it's correct? or do we document it as a network of connected objects in code? and verify in code that it's correct? if we choose the former we'll then have to map from the railways to our mathematical graph and validate that the mapping to code is correct. 

That's an extra step enforced due to our wish to abstract.
Is the cost worthwhile? Sometimes I'm sure it is and sometimes it's not. The trick is to ask that question and knowing that both options exist. DCI is one of those options** restrictedOO and DCI can both be used for the other

Best regards
Rune

*) and to ensure that when it doesn't the likelihood of bodily harm is as low as possible
**) When the connections are a part of the domain

James Coplien

unread,
Dec 14, 2011, 9:00:13 AM12/14/11
to dci-ev...@googlegroups.com

On Dec 14, 2011, at 1:32 , Trygve Reenskaug wrote:

Arguments like "I have worked with xxx for years, and have never had problem with dual identities" is not an argument against a better solution. I want the better solution if I can have it.


And part of the problem here is to quantify "better solution." I would guess that Ant's example violates basic mental models — that's usually the deeper underlying issue in designs with multiple identities. It leads to cognitive dissonance in the design process.

Self schizophrenia isn't a bad thing in any sense that it violates a Turing computational model. It is computable. The problem is in how it reflects or moulds how we think. That the program runs is no measure of success. That the program runs is no measure of success. That one can easily evolve it under complex requirements changes is a more meaningful measure of success. DCI claims that holds for use-case-intensive programs in an object-oriented milieu. Outside of that your mileage may vary. I believe Dijkstra (as I conceive it) fits within the milieu, and that the fact that non-DCI designs apparently suffice is to adopt a very static stance both in terms of the program building blocks and in terms of their evolution.

Serge Beaumont

unread,
Dec 14, 2011, 10:06:42 AM12/14/11
to dci-ev...@googlegroups.com
Trygve,

Your answer did give me what I was looking for, the fact that you consider "role state" to be non-DCI. I can understand the reasons for it and it definitely makes things simpler, but I keep wanting to push temporary state into an object.


Jim found a way to give state to the roles in his first  Dijstra/Ruby program. It was an experiment, and he has removed this feature in his later implementations.

That's interesting. Jim, can you comment on why you came to this conclusion?


So my boat-rocky question is this: shouldn't we have a notion of "PersistentRole", "StateRole", "RoleState", "DynamicData" or whatever you want to call a bunch of dynamically attached state (with appropriate accessors)? This state might have global scope, context scope or role scope.
"Persistent role" is meaningless since a role only exists during an interaction.

I meant not so much putting state in a role but something that is attachable like a role, but is purely for state. In the end it's still better encapsulation if state is as close to the behavior as it can get, isn't it? I'd like to have Context-scope state that I can attach to an object, and that will be removed as the program moves out of scope of that Context.

The Manhattan grid complicates the algorithm, but introduces two roles that essentially do exactly the same: SouthNeighbor and EastNeighbor. A name conflict surfaces if the two role methods have the same name and are injected into the same class. In my latest implementation, the selector is:recomputeTentativeDistance, but the role methods are distinct. The bodies of these two methods may or may not be the same. In my case, they are different in a version where all role methods writes a trace.

Ah, so the Manhattan form introduces some complexity. I haven't tried this yet, but I think that in my case it would depend on the order of attaching roles, since this would determine the order in the inheritance hierarchy.

In node = EastNeighbour(SouthNeighbour(node)) the EastNeighbour version would override the SouthNeighbour version. Hm, I have no idea how I would approach the distinction. Somehow there needs to be a notion of "I'm talking to you as Role X", and that's not something a dynamic language will give you like a typed language does...

I want to stress that I am not belittling other DCI implementations. On the contrary, they are very valuable for making the DCI paradigm available for programming here and now. They may be less than ideal, but never forget Voltaire: "the best is the enemy of the good".

No offense taken, if you were worried about that. I'm enjoying the voyage of learning, I'm not so much interested in the right or wrong of things.

Grtz,

Serge.

James Coplien

unread,
Dec 14, 2011, 10:19:20 AM12/14/11
to dci-ev...@googlegroups.com

On Dec 14, 2011, at 4:06 , Serge Beaumont wrote:

Trygve,

Your answer did give me what I was looking for, the fact that you consider "role state" to be non-DCI. I can understand the reasons for it and it definitely makes things simpler, but I keep wanting to push temporary state into an object.


Jim found a way to give state to the roles in his first  Dijstra/Ruby program. It was an experiment, and he has removed this feature in his later implementations.

That's interesting. Jim, can you comment on why you came to this conclusion?

Hmmm. What I did is that I wrote code whereby the roles gave states to objects. Ruby is a bit funny this way, because the role injection actually adds fields to the object in real time.

One of the major problems with this approach is that it is almost hopeless ever to pull such roles back out. That implies that objects tend to collect garbage over time Every time an object plays a role in a use case it grows. (Wrappers of course solve this, but two wrongs don't make a right.)

Another one of the problems with this approach is the "diamond problem" of name collisions. It's bad enough if two roles use the same data identifier. It's even weirder if a given object plays the same role twice in a row…

How I solved this in the end is to move the state into the Context. All role methods always have access to the Context, and there are no problems with data in the Context. So that works fine, and is reflected in the current version (both in Ruby and in C++, as I recall).

Anyhow, this whole Dijkstra example is becoming richer and richer by way of the increasing number of examples. I hope to upload more of them to fulloo.info over holiday break.

Serge Beaumont

unread,
Dec 14, 2011, 10:50:50 AM12/14/11
to dci-ev...@googlegroups.com
Jim,

You point at the exact issues I'm facing. Littering the object with state, namespace stuff… Still I have a bit of hope. You say that it could be solved with wrappers, but that they're wrong. In fact the current Python solution uses wrappers but makes them so transparent as to be almost non-existent. I don't have any self-schizophrenia, for instance, and == checks work as well. The only thing where you do see an effect is in holding a reference from the outside. This is what enables scope-based-attaching, by the way. Outside the context you don't see any change to the object because you're holding a reference to an unwrapped object.

I understand what you say about the evils of wrapping, but I'm hoping that I can have the best of both worlds: have wrapping be totally transparent in every respect but those I need for elegance in scoping.

Trygve Reenskaug

unread,
Dec 14, 2011, 11:10:10 AM12/14/11
to dci-ev...@googlegroups.com


On 2011.12.14 16:06, Serge Beaumont wrote:
Trygve,

Your answer did give me what I was looking for, the fact that you consider "role state" to be non-DCI. I can understand the reasons for it and it definitely makes things simpler, but I keep wanting to push temporary state into an object.
---


So my boat-rocky question is this: shouldn't we have a notion of "PersistentRole", "StateRole", "RoleState", "DynamicData" or whatever you want to call a bunch of dynamically attached state (with appropriate accessors)? This state might have global scope, context scope or role scope.
"Persistent role" is meaningless since a role only exists during an interaction.

I meant not so much putting state in a role but something that is attachable like a role, but is purely for state. In the end it's still better encapsulation if state is as close to the behavior as it can get, isn't it? I'd like to have Context-scope state that I can attach to an object, and that will be removed as the program moves out of scope of that Context.
Simple. Put the interaction-related state in the context.


Serge Beaumont

unread,
Dec 14, 2011, 1:32:34 PM12/14/11
to dci-ev...@googlegroups.com

It's simple, but is it the only option? Like Cope describes in his Dijkstra example, there is a notion of annotating nodes on a map. My mental model is then that I can attach temporary state to a node (a RolePlayer), and not the (to me) unnatural solution of keeping everything I want to say about an object somewhere separate from that object.

I want to be able to say node.visited instead of context.listofvisitednodes.contains(node), and node.weight instead of context.weightDictionary[node]. I might not be seeing something, but I think it's a lot more understandable and cleaner if I can attach temporary state than to keep a whole bunch of lists and dictionaries in the context.

ant.ku...@gmail.com

unread,
Dec 14, 2011, 1:40:10 PM12/14/11
to dci-ev...@googlegroups.com


"I want to be able to say node.visited instead of context.listofvisitednodes.contains(node)"

+1

----- Reply message -----
From: "Serge Beaumont" <serge.b...@gmail.com>
To: <dci-ev...@googlegroups.com>
Subject: Implemented the Dijkstra algorithm: lessons learned

James Coplien

unread,
Dec 14, 2011, 2:41:35 PM12/14/11
to dci-ev...@googlegroups.com

On Dec 14, 2011, at 7:40 , ant.ku...@gmail.com wrote:

It's simple, but is it the only option? Like Cope describes in his Dijkstra example, there is a notion of annotating nodes on a map. My mental model is then that I can attach temporary state to a node (a RolePlayer), and not the (to me) unnatural solution of keeping everything I want to say about an object somewhere separate from that object.

I think this analysis evidences the same kind of confusion that recurs here commonly: the difference between classes and objects.

To understand code, you don't understand objects. You understand classes and roles.

If you add state to an object you change its class. If the use case designers can add state to a class, it takes away the class designer's authority over data design. It creates a subtle coupling between the role and the class that is in no API. That object's data is now accessible to procedures outside the object.

Don't be led to believe that it must be O.K. because you can do the same thing with inheritance. Using inheritance to violate the encapsulation of a base class by a derived class method is equally bad. This is said to violate "self encapsulation."

Methinks ye doth protest too much about putting the data in the Context. Stuff that belongs with the use cases goes in the Context — not into the object state which is represented by the classes. The roles are just one construct within the Context: that such data might go in the Context doesn't mean that they should go into the roles. Next you will be saying that the identity of the class of the object to which the role is bound should also be in the role. Poppycock.

If such data really are intrinsic to the classes, then they should go there as part of the domain analysis. The class should have an API that gives controlled access to those data.

On Dec 14, 2011, at 7:40 , ant.ku...@gmail.com wrote:

"I want to be able to say node.visited instead of context.listofvisitednodes.contains(node)"

+1

I guess that if you're stuck with a stupid language like C# or Java, you're stuck with syntax like this. Even my C++ framework has straightforward helper functions to make the syntax palatable. But that's not the point. We're not discussion language syntax here, but computational semantics. Get your mind out of the gutter. 

Again, ladies and gentlemen, this is dci-evolution, where we are seeking elegant linguistic solutions to the fundamental computational problems in DCI — not how to shoehorn DCI into our limited syntactic framework of choice. Because of self-schizophrenia and the diamond problems, neither wrappers nor role data are a solution. The discussion here seems to keep retreating into vulgar solutions such as wrappers and state injection because of the limitations of the impoverished languages to which this discussants seem to have limited themselves. I think we can rise to a higher level than this.

Serge Beaumont

unread,
Dec 14, 2011, 4:48:06 PM12/14/11
to dci-ev...@googlegroups.com
Cope,

If you want to contribute to the discussion, please do not do so from such a high-handed position. I do not really appreciate the fact that me doing my best to contribute, understand and get my head around DCI concepts is labeled as "ye protest too much", "vulgar solutions", "get your mind out of the gutter" or "Poppycock".

You said: "If you add state to an object you change its class.". Who exactly is confused between classes and objects? Who needs to get his head out of something here?

I'm using a DYNAMIC language! When I attach state to an object in Python, I attach it to the INSTANCE, not the class. I am NOT using inheritance for this, or changing the class in any way. And I can REMOVE state from the INSTANCE as well. And I can use wrappers WITHOUT self-schizophrenia! Impoverished languages, you say? I'm using Python, which has one of the most powerful and easily accessible metaprogramming model!

Have you actually LOOKED at my examples?

*huff*

Ant Kutschera

unread,
Dec 15, 2011, 2:41:05 AM12/15/11
to dci-evolution
On Dec 14, 8:41 pm, James Coplien <jcopl...@gmail.com> wrote:
> Again, ladies and gentlemen, this is dci-evolution, where we are seeking elegant linguistic solutions to the fundamental computational problems in DCI — not how to shoehorn DCI into our limited syntactic framework of choice. Because of self-schizophrenia and the diamond problems, neither wrappers nor role data are a solution.

James, you always tell us to think about objects and not classes.

In the context of calculating lowest cost paths through a map, we need
to track whether a node has been visited. Surely it is more object
oriented to put that attribute on the object to which it is relevant,
rather than to artificially keep that attribute outside of the object
in the context?

The proof comes when you implement Dijkstra's algorithm using
wrappers, because one naturally places that attribute in the node.
You did it, Serge did it, and I did it.

Ant Kutschera

unread,
Dec 15, 2011, 3:25:22 AM12/15/11
to dci-evolution
On Dec 14, 3:00 pm, James Coplien <jcopl...@gmail.com> wrote:
> On Dec 14, 2011, at 1:32 , Trygve Reenskaug wrote:
>
> > Arguments like "I have worked with xxx for years, and have never had problem with dual identities" is not an argument against a better solution. I want the better solution if I can have it.
>
> And part of the problem here is to quantify "better solution."

I too want a better solution if I can have it. But DCI doesn't cut
the mustard, at this time.

My requirements in language selection are:

1) The language of choice needs to be mature and supported by rich
libraries and products, governed by well thought out specifications
ratified by the industry (no a single company like Microsoft, but a
set of companies with differing interests),
2) The language of choice needs to be deployable in large enterprises
governed my silly politics,
3) The language of choice needs to be one which will help me, as a
freelancer, make a good living, long term,
4) The language of choice needs to support DCI,
5) The language of choice needs to be supported by powerful IDEs which
allow programmers productivity to reach maximum levels.

So languages like Ruby are out of the question, when compared to
platforms like Java, .NET and SAP. Note I used the word platform.

SAP (ABAP) probably won't ever support DCI - last time I looked it
wasn't even OO.

Java the language is too static, and its requirement to provide a
class name when declaring variables causes naming problems, as we
discovered in the summer.

Groovy on the other hand is a language that runs on the Java platform
(since it is compiled into Java bytecode and is hence fully compatible
with all Java APIs/libraries/products/specifications).

So let's look at some Groovy code in a context:

class FlyingCarContext {

/* a role in this context */
class PlaneRole {
def fly(){
println "I'm flying!"
}
}

/* a role player */
def myFlyingCar

/* constructor */
FlyingCarContext(aFlyingCar){
myFlyingCar = aFlyingCar
}

def execute(){
myFlyingCar.fly()
}
}

To execute that context, I could do something like this (in Java or
Groovy):

Car aCar = new Car();
new FlyingCarContext(car).execute();

Using Groovy has entirely removed the naming problems which Java has
and it is very DCI compliant. And like I said a few days ago, you can
build a framework which handles context stacking as well as role
removal at the end of the context. It comes in high on the list of
DCI compatible languages.

So the million dollar question is: "Is this a better solution (than
one which uses wrapers)?"

I say no, it is not better, although perhaps no worse either. But it
still fails to meet my requirements, because programmer productivity
has been reduced due to the dynamics which have been introduced.

No current IDE is able to let the programmer see what methods are
available on the variable "myFlyingCar" in the execute method:

myFlyingCar.fly()

Rune claims that while no IDE can do this today, it is theoretically
possible. I am not convinced. I challenge those who are, to show me
I am wrong in my doubts.

The thing is, when I implement Dijkstra's algorithm using wrappers or
a view model, in a way that I have done for years, which incidentally
does not suffer from object-schizophrenic problems, I find it better
than an implementation which uses DCI. Productivity and the compilers
ability to check for type problems at compile time are more important
to me than mental models, but you'll have to wait for my next post to
find out why.

PS. What has this got to do with DCI evolution? Everything, because
in order for DCI to evolve and be absorbed by the masses, language
designers who support DCI will also have to fulfil the other
requirements.

Rune Funch Søltoft

unread,
Dec 15, 2011, 3:37:01 AM12/15/11
to dci-ev...@googlegroups.com


2011/12/15 Ant Kutschera <ant.ku...@gmail.com>


Rune claims that while no IDE can do this today, it is theoretically
possible.  I am not convinced.  I challenge those who are, to show me
I am wrong in my doubts.
Be careful with your quotes Ant. I've never said that. I didn't claim it was theoretically possible. I stated that I use an IDE like that every day at work. Actually I use two. VS has intellisense for JavaScript but it's not nearly as good as the one WebStorm has.
In WebStorm I have code completion, I have my usual list of parameters for a method. I can do my usual refactoring such as extract method, change signature, rename and all the usual stuff. It's not a claim that it can be done. It's a statement of it already having been done.

There's no evidence to support your claim that working with dynamic languages is less productive than working with static languages. You  might find yourself less productive in a dynamic language than in a static. I know I do. But I also know people for whom it's the other way around and if you dig into the research on the subject you'll find that your claim is not supported there either. You need to work differently, a different process but it's not given that static is less productive than dynamic or vice versa.

James Coplien

unread,
Dec 15, 2011, 4:27:32 AM12/15/11
to dci-ev...@googlegroups.com

On Dec 15, 2011, at 8:41 , Ant Kutschera wrote:

> James, you always tell us to think about objects and not classes.

No, not always. There are no objects in the source code. The source code is the programmer's domain.

Yet the running program — for which the programmer is also responsible — comprises objects.

The real core of DCI is to take something that is a gestalt at run time (an object) and to break it down into its compile-time gestalten (data and behavior). Yes: the goal is to think about objects. That is a difference that class-oriented programmers notice. The fact that we need to think anew about objects doesn't dispel the need to consider the source code. Part of that is now in classes, and part of that is in roles. Neither of them exist at run time.

James Coplien

unread,
Dec 15, 2011, 4:28:40 AM12/15/11
to dci-ev...@googlegroups.com

On Dec 15, 2011, at 9:25 , Ant Kutschera wrote:

> The thing is, when I implement Dijkstra's algorithm using wrappers or
> a view model, in a way that I have done for years, which incidentally
> does not suffer from object-schizophrenic problems, I find it better
> than an implementation which uses DCI.


I think that is because you are limited by your language, and how it affects the way you think about design.

James Coplien

unread,
Dec 15, 2011, 4:42:54 AM12/15/11
to dci-ev...@googlegroups.com
Serge,

I apologize for the tone. It is my attempt at the kind of rhetoric I feel is necessary to get people off their position and find a way to think differently about things. And I thought you were a good Dutch person who appreciates getting into a row like this…

I am very concerned to see a lot of the thinking here heading into a dead end. It's a dead end that we've explored before, and the reasons for getting out of it and the ways of getting out of it have thoroughly been presented here before.

I looked at your code but did not put too much time into it. This is a dci-evolution mailing list and I'm interested in furthering DCI and its expression in programming languages. For me, right now, that excludes wrappers, which is one of the dead ends or blind alleys. I'm going to put my own time into looking at the implementations that build on what we've already done and on the arguments that I feel are already settled. If you feel they are not settled, then I think we need a more disciplined comparison of your implementation with DCI. We are scientists here, and what passes for "lessons learned" here doesn't rank as material that I would consider passable even for an undergraduate essay, let alone a Master's thesis or a Ph.D. thesis. The level of reasoning and dialogue I seek here is on a Ph.D. level.

Perhaps if you want to pursue the wrapper solution, you should do so on object-composition. I would much prefer that we take up a disciplined evolution of DCI here.

That arguments appear here in the form of "yeah, I want this syntax" or "it worked for me" frustrate me deeply, and that's what throws me into this rhetorical stance. Again, I apologize. I suspect that I'll be having to apologize many times again in the future.

James Coplien

unread,
Dec 15, 2011, 4:43:59 AM12/15/11
to dci-ev...@googlegroups.com

On Dec 15, 2011, at 8:41 , Ant Kutschera wrote:

> The proof comes when you implement Dijkstra's algorithm using
> wrappers, because one naturally places that attribute in the node.
> You did it,


Show me where I ever said that example was DCI.

Trygve Reenskaug

unread,
Dec 15, 2011, 4:54:28 AM12/15/11
to dci-ev...@googlegroups.com
Hi Serge,
I find this discussion interesting and stimulating because it touches upon my mental model of DCI in general and the modified Dijkstra algorithm in particular. I have a sneaking suspicion that a Fortran model would be better than an object-oriented one. But we are now discussing an object model and the concrete question is what to do with the 'visited' and 'tentativeDistance' properties.  I found that 'visited' is a derived node property, the set of all 'unvisited' nodes being more basic. But that means that I zoom back from individual nodes to the graph as a whole. I see the graph as a whole and the (tentative) paths that have been calculated so far. The set of  'visited' nodes is the set of nodes participating in a path. A 'visited' node property is true if the node is a member of the 'visited' set, That's why I call it a derived property. The inverse definition is also possible; the set of 'visited' nodes can be computed by selecting all nodes with the 'visited' property == true. I find this alternative less illuminating because the path is more basic than its individual nodes.

For the Data classes, I focus on individual classes and their properties (state and behavior). For the Context and its Roles, I focus on the network of communicating objects as a whole. It is the structure that gets the attention; the roles and their behavior are secondary.

With POJO programming, all kinds of auxiliary properties, both state and behavior, are chopped up into noodles and distributed among the objects. With DCI, the noodles are assembled into whole system properties that are meaningful in themselves.

In my Dijkstra Context, then, there are three roles: Map, the geometry as a whole with its nodes and edges. Unvisited, the set of unvisited geometry nodes. DistanceDict, a dictionary that binds a node to its tentative distance from the start. The first has a global scope, the other two are scoped to the Context.

I have created may versions of my Squeak implementation of DCI. For every version, the separation between the Data part and the Context part becomes cleaner and cleaner. With my latest version, the separation is complete. This makes me believe that there are two fundamental object abstractions. The class with its state, behavior and  instances. The context with its state, behavior, roles, role methods.and role player objects. The class abstraction sees the object from its inside, visibility is bounded by the object encapsulation. The context abstraction sees the interacting objects as a whole. Each participating object is seen from its outside, the visibility is also bounded by its encapsulation. The two abstractions are now completely separated both in my mental model and in my implementation. The class and context abstractions seem fundamental and complementary.

Cheers
--Trygve

Ant Kutschera

unread,
Dec 15, 2011, 2:13:26 PM12/15/11
to dci-evolution
On Dec 15, 9:37 am, Rune Funch Søltoft <r...@asseco.dk> wrote:
> In WebStorm I have code completion, I have my usual list of parameters for
> a method. I can do my usual refactoring such as extract method, change
> signature, rename and all the usual stuff. It's not a claim that it can be
> done. It's a statement of it already having been done.

Can you please send me a screenshot of autocomplete offering me the
"fly" method on the line marked below, using the following code:

class FlyingCarContext {
/* a role in this context */
class PlaneRole {
def fly(){
println "I'm flying!"
}
}

/* a role player */
def myFlyingCar

/* constructor */
FlyingCarContext(aFlyingCar){
myFlyingCar = aFlyingCar
}

def execute(){
myFlyingCar. //AUTOCOMPLETE HERE PLEASE
}
}

Ant Kutschera

unread,
Dec 15, 2011, 2:23:12 PM12/15/11
to dci-evolution

And I think you are wrong ;-)

I like to think in terms of nodes and edges while working inside
Dijkstra's algorithm. That is something DCI lets me do just as much
as wrappers, mapped transfer objects or a view model. Each have
advantages and disadvantages. Of all the options, one has to choose
the "best", normally the one which one prefers the most. I've weighed
up the pros and cons of each, and I am happy with my current choice.

Actually, I find that having a class to specify what a node is, helps
me think about nodes better than having a train station playing the
dynamic role. If I have a train station, I don't know what roles it
really has on any specific line of the code, without studying the code
first. And, by having a class to represent the node, I have no issues
adding state to the object (i.e. in the place which my mental model
thinks it belongs) in order to help me track whether I have visited
the node or not.

Ant Kutschera

unread,
Dec 15, 2011, 2:31:05 PM12/15/11
to dci-evolution

I didn't say you said it was. I said that you added state to a node,
and I implied you did it because it felt natural to do so. The point
being, three people (well 4 if we include Stephan) felt it was worth
putting state in the node. To me, that signifies it is the natural
place for that state.

rune funch

unread,
Dec 15, 2011, 2:31:16 PM12/15/11
to dci-ev...@googlegroups.com
No cuz webstorm is a JS IDE. But don't be silly when it can be done
for a language as dynamic as JS then it can be done for any dynamic
language. You'll never get code completion for everything in a dynamic
language but you don't have that in java either. Whether or not you
have it depends on your tooling and the way you code. Just try to add
an object to an arraylist an fetch it again the line below. Now use
autocomplete for any interesting method. You can't you first need to
tell the compiler which type the object has runtime (aka cast) because
that information got thrown away. Similar with dynamic languages you
can come in a situation where the compiler needs help. In WebStorm
attaching methods runtime is _not_ one of them though

Mvh
Rune

rune funch

unread,
Dec 15, 2011, 2:48:25 PM12/15/11
to dci-ev...@googlegroups.com
Den 15/12/2011 kl. 20.23 skrev Ant Kutschera <ant.ku...@gmail.com>:

> I like to think in terms of nodes and edges while working inside
> Dijkstra's algorithm

I can easily see how this might help implement an abstract algorithm.
That you only have to think in the terms of the algorithm. Is that why
you prefer to just use nodes and edges?

rune funch

unread,
Dec 15, 2011, 2:51:10 PM12/15/11
to dci-ev...@googlegroups.com
Den 15/12/2011 kl. 20.31 skrev Ant Kutschera <ant.ku...@gmail.com>:

> To me, that signifies it is the natural
> place for that state.

Not everything that feels very real and natural is correct though ask
Galileo or any nuclear physicist or any procedural programmer writing
his first program in Java

Ant Kutschera

unread,
Dec 15, 2011, 2:52:13 PM12/15/11
to dci-evolution
On Dec 15, 10:54 am, Trygve Reenskaug <tryg...@ifi.uio.no> wrote:
> With POJO programming, all kinds of auxiliary properties, both state and
> behavior, are chopped up into noodles and distributed among the objects.

Hi Trygve,

I don't think that is necessarily true. What I have done in my
project was to create a component (in POJO) for calculating shortest
paths. That component defines an interface, composed of operations
which can be called (e.g. calculateFastestRoute), and an object model
(data) which is passed to the operation. To call an operation, I map
my domain object (e.g. train station) into the object model, namely
nodes, geometry, etc. I pass that object model to the operation and I
get a result back, in terms of a list of nodes showing the shortest
path. In my specific implementation I even have additional
information like the waiting time at each node. I can then map the
results back.

There is additional work in this mapping, but by sneakily making nodes
have a reference to train stations, the mapping is quite simple in the
end. Mapping from train station to node is also as simple as passing
the train station to the node constructor.

The result is that I do not have chopped noodles of state and
behaviour which is distributed all over the place. Rather, I have a
component of software which has a very clear behaviour defined by its
operations (a public interface into the component). That component
has a clear responsibility. All the relevant concerns have been
separated. Reviewing the algorithm is very easy, because the reviewer
only needs to know about nodes, which are clearly defined in a class,
so that the reader knows exactly which data the node has. Nodes
themselves contain no behaviour, true to a services paradigm, rather
than an OO paradigm.

Cheers,
Ant


James Coplien

unread,
Dec 15, 2011, 2:54:56 PM12/15/11
to dci-ev...@googlegroups.com
To me it implies that people are still in the mode of thinking from the inside of the object looking out — a natural thing to do in class-oriented programming.

The example was designed in large part as a test for the current level of comprehension and mitigation of the deeper issues underlying computational models. In particular, the code was designed to explore identity and equality, algorithmic thinking versus data thinking, language restrictions versus computational models, and a number of other axes of design. I focused on the areas where the rhetoric of this group (and of object-composition) have given me concern.

We have a long way to go.

Ant Kutschera

unread,
Dec 15, 2011, 2:59:55 PM12/15/11
to dci-evolution
On Dec 15, 8:31 pm, rune funch <funchsolt...@gmail.com> wrote:
> No cuz webstorm is a JS IDE. But don't be silly when it can be done
> for a language as dynamic as JS then it can be done for any dynamic
> language. You'll never get code completion for everything in a dynamic
> language but you don't have that in java either. Whether or not you
> have it depends on your tooling and the way you code. Just try to add
> an object to an arraylist an fetch it again the line below. Now use
> autocomplete for any interesting method. You can't you first need to
> tell the compiler which type the object has runtime (aka cast) because
> that information got thrown away. Similar with dynamic languages you
> can come in a situation where the compiler needs help. In WebStorm
> attaching methods runtime is _not_ one of them though

Rune, you have just contradicted yourself, and confirmed my original
statement. Dynamic languages cannot support autocomplete as well as
languages which require the programmer to declare the class of each
variable. That statement is true and irrefutable.

Try implementing Dijkstra's algorithm in Javascript in a manner
similar to the way James did it in Ruby, and you will see that
autocomplete is rendered almost completely useless.

In my opinion (and I am not alone here), productivity is reduced. And
that is one reason why DCI is not a better solution than wrappers, in
my opinion. In terms of evolution, DCI needs to address this issue,
in my opinion.

Ant Kutschera

unread,
Dec 15, 2011, 3:02:09 PM12/15/11
to dci-evolution
On Dec 15, 8:48 pm, rune funch <funchsolt...@gmail.com> wrote:

> Den 15/12/2011 kl. 20.23 skrev Ant Kutschera <ant.kutsch...@gmail.com>:
>
> > I like to think in terms of nodes and edges while working inside
> > Dijkstra's algorithm
>
> I can easily see how this might help implement an abstract algorithm.
> That you only have to think in the terms of the algorithm. Is that why
> you prefer to just use nodes and edges?

I prefer to think in terms of nodes and edges, because train stations
and train trips are not as accurate. And... in terms of using the
algorithm elsewhere (taxi trips, tourists walking around town, etc),
doing so makes the algorithm useable in other software.

Ant Kutschera

unread,
Dec 15, 2011, 3:04:44 PM12/15/11
to dci-evolution
On Dec 15, 8:54 pm, James Coplien <jcopl...@gmail.com> wrote:
> We have a long way to go.

+1

Rune Funch Søltoft

unread,
Dec 15, 2011, 3:16:11 PM12/15/11
to dci-ev...@googlegroups.com
2011/12/15 Ant Kutschera <ant.ku...@gmail.com>
As I said I can easily see how that helps talking about the solution domain. What I cannot see is how abstracting away the problem domain does anything to help review the correctness of the system (not the algorithm but the system). Customers very seldom pay to have perfect algorithms, they might even want imperfect algorithms (usually for performance reasons) but they care a lot about correct systems. Representing the solution in terms of the problem domain makes it possible to review the algorithm and the system

Rune Funch Søltoft

unread,
Dec 15, 2011, 3:34:35 PM12/15/11
to dci-ev...@googlegroups.com


2011/12/15 Ant Kutschera <ant.ku...@gmail.com>

On Dec 15, 8:31 pm, rune funch <funchsolt...@gmail.com> wrote:
> No cuz webstorm is a JS IDE. But don't be silly when it can be done
> for a language as dynamic as JS then it can be done for any dynamic
> language. You'll never get code completion for everything in a dynamic
> language but you don't have that in java either. Whether or not you
> have it depends on your tooling and the way you code. Just try to add
> an object to an arraylist an fetch it again the line below. Now use
> autocomplete for any interesting method. You can't you first need to
> tell the compiler which type the object has runtime (aka cast) because
> that information got thrown away. Similar with dynamic languages you
> can come in a situation where the compiler needs help. In WebStorm
> attaching methods runtime is _not_ one of them though

Rune, you have just contradicted yourself, and confirmed my original
statement.  Dynamic languages cannot support autocomplete as well as
languages which require the programmer to declare the class of each
variable.  That statement is true and irrefutable.

You are comparing apples and train stations. If I write in a dynamic language like JS and stay within the boundaries of what a static language is capable of, it's nonesense to say that I can't have the same intellisense. After all you could write a compiler that treated the code as statically typed and embed that compiler into my IDE/tools.
If I stray outside of the boundaries of what a statically language supports there will be scenarios where the intellisense will have to concede (or occupy the CPU for ever trying to solve an NP-hard or even NP complete problem). An example that can be done in JS with intellisense and can't be performed in statically language that I know of (except within limits Marvin) is attaching a new method to an object dynamically. If WebStrom is able to determine the type of the object (that is if it can't be multiple different types) then I will have intellisense for methods attached dynamically as well. if it can't determine the type the situation is no different from how intellisense works on say items from a non-generic collections in Java. You need to tell the compiler what type _you_ expect the object to have
 

Try implementing Dijkstra's algorithm in Javascript in a manner
similar to the way James did it in Ruby, and you will see that
autocomplete is rendered almost completely useless.
 
I haven't tried but again the implementation was by yourself and others proven impossible in Java. That does not make intellisense for Ruby impossible but simply demonstrates that there are things you can do in Ruby that can't be done in Java (or C#)
 
In my opinion (and I am not alone here), productivity is reduced.
No one ever claimed you were alone, I simply stated that the claim of statically typed languages being more productive isn't supported by empirical data. I've seen papers claiming it to be true and papers claiming the opposite.
 
 And
that is one reason why DCI is not a better solution than wrappers, 
in
my opinion.  In terms of evolution, DCI needs to address this issue,
in my opinion.

I've shown several times that you can have statically languages with dynamically scoped methods. I've given examples in C#, F# and in Marvin. The latter is build specifically to make it easier to have dynamically scoped methods for objects. The actual compiler for Marvin is the Mono C# compiler. I've only changed the parser to make it possible and all the parser does is rewrite the few Marvin extension to standard C#.

On this group I find it off topic that we keep discussing dynamically typed languages vs statically typed languages. I see it have relevance for how you'd choose a language for a project you're going to start today using DCI but I can't see that it has much to do with defining a new execution model or helps rewriting the type system/type theory

Trygve Reenskaug

unread,
Dec 15, 2011, 3:56:04 PM12/15/11
to dci-ev...@googlegroups.com
Re: the importance of autocomplete. What percentage of the total program development time do you estimate is spent actually typing at the keyboard?
--

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

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

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

Norway

James Coplien

unread,
Dec 15, 2011, 4:14:13 PM12/15/11
to dci-ev...@googlegroups.com

On Dec 15, 2011, at 9:56 , Trygve Reenskaug wrote:

Re: the importance of autocomplete. What percentage of the total program development time do you estimate is spent actually typing at the keyboard?


We did some integrative research on this at Bell Labs, and the numbers ranged from 15% down to 5% for programming. Much work these days involves computers, but little of that involves autocomplete.

The whole foundation of Agile is "individuals and interactions over processes and tools." A fool with a tool is still a fool. Tools have become an academic thing — perhaps because that's what they can produce. Intelligent editors and IDEs try to make up for thinking. (This, by the way, is one reason I so resisted Trygve's insistence on a DCI IDE. Seeing it in practice, I can see several things that it does that are effectively housekeeping — keeping track of things too big to be able to keep in my short-term memory.) Such scale does not seem to be a feature, in any sense, of the autocompletion examples that have been presented here. If you're bent on using tools, use the right tool for the right job. Autocompletion misses the mark here.

In particular, tools that supplant thinking are dangerous. I have no problems with compilers — the translation from source code to object code is a minor step above a table lookup, and is not deserving of brainpower. The conceptualization of roles and an algorithm requires thought. It is a common academic misunderstanding that much of contemporary software development can be automated. There are longstanding claims of automating the generation of code from requirements, yet I have seen nothing come out of academic research in the past 40 years that has fundamentally changed the way programmers work in this regard.

It's a bit sad that the discussion would go all the way down to something as lowly as autocomplete. That is especially so on this list. I fail to see how that relates to the conceptualizations we are trying to hone here.

For now, I see that the same is true for dynamic versus static typing. I happen to be a fan of static type-checking based on results from large software engineering projects that shows that it reduces errors. But before you have a type-checking system, you need a type model. We don't have a formal type model for DCI yet. I have talked at length with Trygve about this, and have even been tempted to get Luca Cardelli engaged in creating a DCI type system.

People confuse type systems with compiler type checking; I haven't seen a single discussion of the deeper issues of type systems here: only of the semantic sugar to do little more than spell checkers do. There is much more at stake. The academics here could help a lot by first developing the formal type theoretic foundations for DCI in retract theory or in some other suitable formalism; then compiler type-checking is more or less a "so what?" exercise.

In short, I have found the static-versus-dynamic discussion here so far to been an uninformed, uninforming, unsubstantiated tempest in a teapot. Let's get back to work. If that work is to include type systems, let's get serious about it and go beyond personal preference and opinion to some real scientific results. 

ant.ku...@gmail.com

unread,
Dec 16, 2011, 1:40:07 AM12/16/11
to dci-ev...@googlegroups.com
James wrote:

> Let's get back to work. If that work is to include type systems, let's get serious about it and go beyond personal preference and opinion to some real scientific results

I'm only portraying the misconceptions of the masses.  If the DCI paradigm encourages writing code in vi to aid the thought processes, so be it.

If you are looking for scientific result in this forum, maybe one statistic you can pull out of all this is that forums are not the optimal base for scientific research, when non-academic pragmatists like me try to force their *opinions* on the group.

Cheers,
Ant

ant.ku...@gmail.com

unread,
Dec 16, 2011, 1:46:33 AM12/16/11
to dci-ev...@googlegroups.com
Rune wrote:

> As I said I can easily see how that helps talking about the solution domain. What I cannot see is how abstracting away the problem domain does anything to help review the correctness of the system (not the algorithm but the system).

Interesting point. But at some stage reviewing the system as a whole gets too complex.  Your almost suggesting we should avoid abstraction because it removes the ability to think of the system as a whole.

The danger of having train stations in Dijkstra's algorithm is that the reviewer forgets to review the algorithm because they like simple trains rather than hard mathematical problems.

----- Reply message -----
From: "Rune Funch Søltoft" <r...@asseco.dk>
To: <dci-ev...@googlegroups.com>
Subject: Implemented the Dijkstra algorithm: lessons learned
Date: Thu, Dec 15, 2011 21:16


2011/12/15 Ant Kutschera <ant.ku...@gmail.com>
On Dec 15, 8:48 pm, rune funch <funchsolt...@gmail.com> wrote:

James Coplien

unread,
Dec 16, 2011, 5:49:53 AM12/16/11
to dci-ev...@googlegroups.com

On Dec 16, 2011, at 7:46 , ant.ku...@gmail.com wrote:

Your almost suggesting we should avoid abstraction because it removes the ability to think of the system as a whole.

That actually strikes a chord. See: "Abstraction Descant," by Dick Gabriel. 


Abstraction is evil.

Rune Funch Søltoft

unread,
Dec 18, 2011, 8:09:52 AM12/18/11
to dci-ev...@googlegroups.com
HI Ant,
I just spoke to our product owner. He's really pleased with our software and the ability it gives him to find the shortest rute. Actually he's so pleased that he'll like to use it for more than just finding the shortest rute, though that is of course still part of the requirement. He also wish to use it for planning purposes which introduces a few more business rules.

Any given station can have trains coming in from one or two directions*.
Any platform can have one of two tracks
Any track can brach at a turnout
A turnout can be connected with edges leading away in two or three directions

If a platform is part of a station that has trains coming in from one direction then the subgraph the platform is a node in is bidirectional
If a platform has two tracks the sub graph is bidirectional
If none of the above is true it must be ensured that the subgraph can only be directed.
Any given track is directed unless it's connecting two turnouts where the other two tracks connected to the same turnout are directed in opposite directions.

The requirements are:
To be able to find the fastest possible path between to stations
Choose the tracks so that the safety rules are followed (E.g. can't have two trains running in opposite directions on the same track between to turnouts)
Choose the platforms for each train making sure that in most case (90% or more) the same line stops at the same side of the same platform every time and that it always is planned for the same platform.
Since failures in the planning might result in train crashes it is important that the the above business rules can be verified in the code by review. E.g. it must be possible to see that a node with edges in three directions is always a turnout and that one with all edges coming in from the same side is a station.

*) Talking about edges coming in from a number of directions is in relation to a geographical map, not graph theory


We've so far got two candidate solutions. One that focuses on the solution domain and (partly) abstracts a way the problem domain and one that tries to keep the problem domain in focus while working on the solution.
For each of those think about
-How do we by review verify that a node with edges from three directions can only be a turnout and that nodes where all edges comes from the same direction can only be a station?
-How do we verify that the rule of a single track being one way unless in the above special case with turnouts? (which in turn is a property derived from what platform the tracks connected to the turn out will come to/from)
-In general how well does each solution help us to verify the correctness of our system implementation?

Best regards
Rune

ant.ku...@gmail.com

unread,
Dec 18, 2011, 12:35:48 PM12/18/11
to dci-ev...@googlegroups.com
You haven't mentioned testing.  I know one of DCIs things is to make code more reviewable, but that isn't everything.  If Scandinavian train carriers rely on reviewing their code and not also testing it and having redundant systems, I'll be taking the car next time I'm there ;-)

I'm in the middle of reading the book posted by James (great link, thanks!).  In reality it turns out, a node the way I wrote it is not actually an abstraction.  A node is indeed a role.  It is a specific look at the fine details of an object, for which you have a particular interest.

So in the end, we return to the old debate of whether wrappers are better than dynamic injected (or whatever the current trend is) methods.  

My design lecturer taught me about matrices with weighted scores.  You create a table.  Add columns for each possible design.  Add rows for each of the criteria you want to use for scoring.  For each criterion, choose a weighting (how important is the criterion).

Fill the table in by giving each design a score for the criterion, and multiply the score by the weighting.  Sum the weighted scores, and the design with the highest score wins.

Criterion could be: ability to use tools to refactor; ability to avoid superfluous naming; ability to avoid object schizophrenia; ability to assist productivity; ability to allow traditional review; ability to allow tool assisted review; etc.

Everyone here can do this and come to their own conclusions.  I don't think there is currently a black and white answer.  And that is why I keep posting; for DCI to evolve and be absorbed by the masses, I feel the people making design choices need a little less grey.

ant.ku...@gmail.com

unread,
Dec 18, 2011, 12:36:03 PM12/18/11
to dci-ev...@googlegroups.com
It says:

"Abstraction and encapsulation are good things;"

Of course it says a lot more too :-)

Like I said in my other post, I've come to realise that I'm not abstracting,  rather I'm focusing on exactly those parts of a node (including whether it been visited) which interest me in the context of an algorithm.  If Runes product manager wants to expand it to include platforms, that's fine. But its no reason to give the reviewer the potential to get confused by viewing the compartment types or co2 savings compared to car travel.



----- Reply message -----
From: "James Coplien" <jcop...@gmail.com>
To: <dci-ev...@googlegroups.com>
Subject: Implemented the Dijkstra algorithm: lessons learned
Date: Fri, Dec 16, 2011 11:49

On Dec 16, 2011, at 7:46 , ant.ku...@gmail.com wrote:

Your almost suggesting we should avoid abstraction because it removes the ability to think of the system as a whole.

Ant Kutschera

unread,
Jan 1, 2012, 6:01:15 AM1/1/12
to dci-evolution
Interesting comments from the Twitter dev team on Ruby's dynamic type
system: http://www.artima.com/scalazine/articles/twitter_on_scala.html

"It is a shame to have to write all that when there is a solution that
has existed in the world of programming languages for decades now."
Reply all
Reply to author
Forward
0 new messages