DCI in javascript

225 views
Skip to first unread message

Egon Elbre

unread,
Dec 22, 2012, 9:15:36 AM12/22/12
to object-co...@googlegroups.com
Implemented an DCI lib with javascript:


I've tested it only in chrome.

rune funch

unread,
Dec 22, 2012, 3:00:36 PM12/22/12
to object-co...@googlegroups.com
Therese a fem issues
* you are wrapping the role players
* roles aren't internal to the context

A role is not an object an in a dynamic language as JS there's no need for role types nor for wrappers. Most of what's needed to do DCI is given by the language and what is not is inherently difficult to do in JS unfortunately. You can help your self with a few utility functions eg one for binding a role to an object.
The difficult parts are cleaning up because there's no destructor/finalizer in JS and calling the right method when a role method and an instance method clashes. (See another thread for examples of this)
--
You received this message because you are subscribed to the Google Groups "object-composition" group.
To view this discussion on the web visit https://groups.google.com/d/msg/object-composition/-/EwngtHqFHl4J.
To post to this group, send email to object-co...@googlegroups.com.
To unsubscribe from this group, send email to object-composit...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/object-composition?hl=en.

Egon Elbre

unread,
Dec 22, 2012, 3:48:25 PM12/22/12
to object-co...@googlegroups.com
On Saturday, December 22, 2012 10:00:36 PM UTC+2, Rune wrote:
Therese a fem issues
* you are wrapping the role players
* roles aren't internal to the context


* Currently to me it seems wrapping is a better fit for JS since it avoids problems, like removing methods and GC-ing the roles.

There's also a possibility making every object an Actor and not use "wrapping" and just keep adding Roles to the Actor. To me the distinction between Data and Actors makes the implementation and conceptual model simpler.

Currently the Roles used in context are referenced until the main context finishes. So the wrapping allows Actor to be separately GCd and you won't need to do any cleaning up. If you need to talk to the object directly this gives a nice way to do it.

Of course you can always hide that you are using an Actor by just assigning back to the same variable. Or just do the wrapping during the context construction.

Although this wrapping may cause self-schizophrenia, it can be (partially) avoided by using a separate function for comparing, that takes Actors into account.

I don't have a "role type" per se, its just a method table that knows the context its defined in. Those Role/Context/Methods/Fn functions just attach some extra information to the objects - they are not classes/types; the only "class" there is Actor.

* Roles are internal to the context - makePlayerTalk should show it. Also it should be capable of handling multiple levels of contexts (except internal contexts).
 
When role method and instance method clashes I call, depending on the calling context, either the instance method or the role method - if there are multiple roles assigned then I just dispatch to the last assigned Role that has such method.

James O Coplien

unread,
Dec 23, 2012, 2:19:41 PM12/23/12
to object-co...@googlegroups.com

On Dec 22, 2012, at 2:48 , Egon Elbre wrote:

Currently to me it seems wrapping is a better fit for JS since it avoids problems

Maybe. But it's not DCI. And it adds an incredible number of problems. Please check out the earlier discussions on this list.

Egon Elbre

unread,
Dec 23, 2012, 4:53:24 PM12/23/12
to object-co...@googlegroups.com
Is it possible without adding any extra wrapping? It's really hard to see how it would be possible.

Here's the example:

function choose(a, b){
return Math.random() > 0.5 ? a : choose(b, a);
}

Context {
Role source {
function foo(){
print("source");
}
}

Role target {
function foo(){
print("target");
}
}

function init(source, target){
thing = choose(source, target)
thing.foo()
}
}

Context.init(player, player)

The source and target must be different since otherwise there would be no way to dispatch to the correct method. So essentially the source/target identifier must carry somehow around their Role notions. This means the identifiers by using equals cannot be the same unless you hide that fact. Hence the identifier must wrap the original object and the role together to work properly.

Or am I misunderstanding something?

James O Coplien

unread,
Dec 24, 2012, 12:14:07 AM12/24/12
to object-co...@googlegroups.com

On Dec 23, 2012, at 1:53 , Egon Elbre wrote:

Is it possible without adding any extra wrapping? It's really hard to see how it would be possible.

I think someone else has done this in Javascript without wrappers. I suggest checking the mail archives, or asking around here on the list.

rune funch

unread,
Dec 24, 2012, 3:03:57 AM12/24/12
to object-co...@googlegroups.com
Den 23/12/2012 kl. 22.53 skrev Egon Elbre <egon...@gmail.com>:

>
> Is it possible without adding any extra wrapping? It's really hard to see how it would be possible

Yes it certainly is. JS is one of the languages that gets closest to
DCI there two problem, one of which has a simple solution.
The two problems are cleaning up do to lack of finalizers you need to
do the cleaning up manually. The other is when instance and role
methods clash see another thread on this. I've posted a JS solution a
month or so ago.

Egon Elbre

unread,
Dec 24, 2012, 3:13:06 AM12/24/12
to object-co...@googlegroups.com
In your example object is unable to play multiple roles. (If you mean this example: http://jsfiddle.net/K543c/17/)

Egon Elbre

unread,
Dec 24, 2012, 3:15:11 AM12/24/12
to object-co...@googlegroups.com
I don't even mean just javascript - in any language. It either must have a wrapping or the wrapping has been hidden or it doesn't support all of DCI.
Something has to hold the roled identity, otherwise there can be no way to tell apart which role should be responding.

See the example below. If the source/target identifiers do not carry extra information (wrapping original object and role information) the result of "choose" must be the same for either call, hence there is no way to determine which roles behavior should be responding. My expectation from the following code is that "source" and then "target" is printed.

(And yes I've tried to find in this forum how it is done, but failed to find one. Maybe I am missing something obvious.)

So my claim is that role behavior and object must be composed/wrapped into a separate entity for it to work:

function choose(v, a, b){
return v > 0.5 ? a : b;
}

Context {
Role source {
function foo(){
print("source");
}
}

Role target {
function foo(){
print("target");
}
}

function init(source, target){
choose(1, source, target).foo()
choose(0, source, target).foo()
}
}

Context.init(player, player)

rune funch

unread,
Dec 24, 2012, 3:34:45 AM12/24/12
to object-co...@googlegroups.com

Den 24/12/2012 kl. 09.13 skrev Egon Elbre <egon...@gmail.com>:

In your example object is unable to play multiple roles. (If you mean this example: http://jsfiddle.net/K543c/17/)
That would be a limitation I was unaware of when I hacked it together aside from not handling name clashes (except for very trivial ones) why do you think it doesn't support playing multiple roles?



On Monday, December 24, 2012 10:03:57 AM UTC+2, Rune wrote:
Den 23/12/2012 kl. 22.53 skrev Egon Elbre <egon...@gmail.com>:

>
> Is it possible without adding any extra wrapping? It's really hard to see how it would be possible

Yes it certainly is. JS is one of the languages that gets closest to
DCI there two problem,  one of which has a simple solution.
The two problems are cleaning up do to lack of finalizers you need to
do the cleaning up manually. The other is when instance and role
methods clash see another thread on this. I've posted a JS solution a
month or so ago.

--
You received this message because you are subscribed to the Google Groups "object-composition" group.

Egon Elbre

unread,
Dec 24, 2012, 4:08:04 AM12/24/12
to object-co...@googlegroups.com
On Monday, December 24, 2012 10:34:45 AM UTC+2, Rune wrote:

Den 24/12/2012 kl. 09.13 skrev Egon Elbre <egon...@gmail.com>:

In your example object is unable to play multiple roles. (If you mean this example: http://jsfiddle.net/K543c/17/)
That would be a limitation I was unaware of when I hacked it together aside from not handling name clashes (except for very trivial ones) why do you think it doesn't support playing multiple roles?


Mainly just trying.

But, I presented the argument code previously. I see no way of doing that without wrapping or composing. When you inject - you lose the information that which role it should be playing. Hence one object multiple roles - do an assignment and there's no way to know which role that variable is meant to be playing.

Essentially in a context:

thing = pickOneOf(roleA, roleB)
thing.foo()

There is no way of knowing which role "one" should play, if the object playing the roleA and roleB is the same, unless you attach that information to the variables (composing/wrapping).

James O Coplien

unread,
Dec 24, 2012, 11:53:23 AM12/24/12
to object-co...@googlegroups.com

On Dec 24, 2012, at 12:15 , Egon Elbre wrote:

I don't even mean just javascript - in any language. It either must have a wrapping or the wrapping has been hidden or it doesn't support all of DCI.

Please go do a good more reading about DCI. I think you need a firmer grounding in its principles to understand even what we're trying to do. Retaining the object notion of identity (an object has state, behavior, and identity) is crucial to true DCI. When Trygve and I tried this with wrappers we ran into horrific bugs. ObejctTeams has the same problem.

Once you have understood the basics, then have a look at the code examples on fulloo.info. They avoid wrapping. Dependency injection is one technique; specific languages and environments use a variety of other tricks to make this work without descending to wrapping.

James O Coplien

unread,
Dec 24, 2012, 11:54:25 AM12/24/12
to object-co...@googlegroups.com

On Dec 24, 2012, at 1:08 , Egon Elbre wrote:

Hence one object multiple roles - do an assignment and there's no way to know which role that variable is meant to be playing

An object can of course play multiple roles.

Again, please don't try to learn DCI from the list. Look at the resources on http://fulloo.info.

Egon Elbre

unread,
Dec 25, 2012, 5:03:37 AM12/25/12
to object-co...@googlegroups.com


On Monday, December 24, 2012 6:53:23 PM UTC+2, Cope wrote:

On Dec 24, 2012, at 12:15 , Egon Elbre wrote:

I don't even mean just javascript - in any language. It either must have a wrapping or the wrapping has been hidden or it doesn't support all of DCI.

Please go do a good more reading about DCI. I think you need a firmer grounding in its principles to understand even what we're trying to do. Retaining the object notion of identity (an object has state, behavior, and identity) is crucial to true DCI. When Trygve and I tried this with wrappers we ran into horrific bugs. ObejctTeams has the same problem.


I can understand why the identity notion is important and why wrappers cause problems. Also I understand the need for capturing use cases. But, also I want to understand the limitations of DCI and where it totally breaks down - it usually gives a lot information where it can be used.
 
Once you have understood the basics, then have a look at the code examples on fulloo.info. They avoid wrapping. Dependency injection is one technique; specific languages and environments use a variety of other tricks to make this work without descending to wrapping.

In DCI execution model 3.3, 4) doesn't say how the correct Role is found.

My understandings on that:

Version 1: thing that the RoleName refers to internally wraps Role and lies about it's identity. And hides methods depending on the context. (As many have stated this is not the case).

Version 2: the RoleName itself acts as an extra information source and depending on that it either dispatch to the original object or the role behaviors and has the identity of object. Basically the actual object that the message dispatch is done on the tuple (object, Role) or (object, RoleName). Assuming you can't send a single message to multiple objects I must consider that as a composite/wrapping. (Also for me it doesn't matter if this redirection is inlined at compile time; or whether the wrapping/composing is local to the calling place - it's still wrapping/composing, just hidden.)

Alternative formulation of 2: RoleName is a "special name" to say how to lookup the method in the context. The RoleName "special name" for sending a message with additional Role + Context.

Version 3: ???

Consequences from Version 2:
For Roles only method calls can be allowed. This means no assigning by Role identifier to another variable and passing into a method as an argument. If that is the case, then the DCI model implementation becomes easier.

But also this example would be impossible to do by that version:

Role Source {
func transferTo(receiver, amount) {
receiver.add(amount)
}
}

Role ReceiverA {
func add(amount){
self.deposit(amount * 2)
}
}

Role RecieverB {
func add(amount){
self.deposit(amount)
}
}

if( v > 0.5 ){
Source.transferTo(RecieverA, 50)
} else {
Source.transferTo(RecieverB, 50)
}

I do understand such examples as a use case would be bad because the interaction won't be explict and transparent. This means you can't generally talk to a Role.


Code I've examined so far:

Javascript-DCI by Rune: doesn't handle multiple Roles
BabyIDE : does a inlined dispatch on (RoleName, object) [based on the code in The Common Sense of Object Oriented Programming]
Marvin : unfortunately, wasn't able to get examples compiling yet 
Scala DCI : wraps (also probably breaks when doing deep copy on the Role) [based on github explanation]

Probably my conclusion are wrong, but I'm not able to determine how exactly. I assume the misunderstanding comes from the lack of better vocabulary.

Trygve Reenskaug

unread,
Dec 25, 2012, 7:06:36 AM12/25/12
to object-co...@googlegroups.com


On 2012.12.25 11:03, Egon Elbre wrote:
>
> In DCI execution model 3.3, 4) doesn't say how the correct Role is found.
>
> My understandings on that:
>
> Version 1: thing that the RoleName refers to internally wraps Role and
> lies about it's identity. And hides methods depending on the context.
> (As many have stated this is not the case).
>
> Version 2: the RoleName itself acts as an extra information source and
> depending on that it either dispatch to the original object or the
> role behaviors and has the identity of object. Basically the actual
> object that the message dispatch is done on the tuple (object, Role)
> or (object, RoleName). Assuming you can't send a single message to
> multiple objects I must consider that as a composite/wrapping. (Also
> for me it doesn't matter if this redirection is inlined at compile
> time; or whether the wrapping/composing is local to the calling place
> - it's still wrapping/composing, just hidden.)
>
Thewse are non-problems. Look at my Squeak examples to find the answer.
If you want to dig deeper, look at my modifications of the Squeak
compiler and runtime system. Or study Marvin. This is much better than
guessing. You need a deep understanding of DCI to find its limitations.

rune funch

unread,
Dec 25, 2012, 10:32:33 AM12/25/12
to object-co...@googlegroups.com
Den 25/12/2012 kl. 11.03 skrev Egon Elbre <egon...@gmail.com>:

> Javascript-DCI by Rune: doesn't handle multiple Roles
Not true it easily handles multiple roles even when played by the same object

Egon Elbre

unread,
Dec 25, 2012, 12:49:03 PM12/25/12
to object-co...@googlegroups.com

rune funch

unread,
Dec 25, 2012, 1:11:20 PM12/25/12
to object-co...@googlegroups.com
That's not due to multiple roles but due to a name clash which if no news. Multiple roles is not an issue


--
You received this message because you are subscribed to the Google Groups "object-composition" group.

Egon Elbre

unread,
Dec 25, 2012, 1:13:39 PM12/25/12
to object-co...@googlegroups.com, try...@ifi.uio.no
Regarding, how to find the correct Role is an important part.

But, I agree that these are non-problems from DCI using standpoint, but regarding 
understanding the nuts and bolts, they are quite important. I just don't get the 
importance of using/not using wrapping/composite if it's hidden and keeps identity 
problems at bay.

The main point to the technicalities seems presenting same identity for the 
roles as the original object and the dispatch behavior. How that is achieved 
shouldn't matter, except the usability side. But just because implementation 
is using wrapping/composing and claim it's not DCI, really confuses me.

The statement why it's not DCI should be, that it has self-schizophrenia or it 
doesn't handle multiple roles or it doesn't handle nested contexts -- and not how
it's implemented.

I'm already trying to understand the Squeak code part - but my squeaking isn't as 
good as I would like to.

Egon Elbre

unread,
Dec 25, 2012, 1:25:20 PM12/25/12
to object-co...@googlegroups.com


On Tuesday, December 25, 2012 8:11:20 PM UTC+2, Rune wrote:
Den 25/12/2012 kl. 18.49 skrev Egon Elbre <egon...@gmail.com>:
On Tuesday, December 25, 2012 5:32:33 PM UTC+2, Rune wrote:
Den 25/12/2012 kl. 11.03 skrev Egon Elbre <egon...@gmail.com>:

> Javascript-DCI by Rune: doesn't handle multiple Roles
Not true it easily handles multiple roles even when played by the same object

That's not due to multiple roles but due to a name clash which if no news. Multiple roles is not an issue

If you have one role per object per context then the problem can be avoided. More properly given a context
a object you can uniquely identify the Role by using the identifier reference to the object alone. If you add
another Role the correct the Role that should act cannot be uniquely determined. Hence the problem is in
multiple Roles.

(OK, noticed something after writing the first part)

I think you are right - the problem of determining between the Role and Object exists even without multiple roles.
But I wouldn't call that name clashing - the problem is determining the correct Role/Object that should handle the message.

rune funch

unread,
Dec 25, 2012, 2:31:03 PM12/25/12
to object-co...@googlegroups.com
Den 25/12/2012 kl. 19.13 skrev Egon Elbre <egon...@gmail.com>:

> The main point to the technicalities seems presenting same identity for the
> roles as the original object and the dispatch behavior. How that is achieved
> shouldn't matter

Show some come that accomplishes this. Including when library code is
called. You can't do that in C#/Java/C++ or JavaScript. I've seen
people try in Ruby but haven't seen any one succeeding so my money is
on that you can't do it in ruby either

Egon Elbre

unread,
Dec 25, 2012, 3:02:30 PM12/25/12
to object-co...@googlegroups.com
My point is that it shouldn't matter how exactly it's done, and I didn't claim
I can do all of it perfectly. Here are some ideas that some may consider not DCI.

With wrapping you have the identity problem, this means that when you pass
Role as an argument or use it in assignment you must always do manual unwrapping.
Yes, it's an annoyance to do so. But, let's now deal with that annoyance - if you 
can add a global hook to all method calls you can automate unwrapping. 
In Ruby you maybe able to do that with set_trace_func - I'm not that good with Ruby.
Of course that can add a lot of overhead to method calls.

Or maybe do code replacement: replace every method call of RoleName.method(args) 
with _Roled_(RolePlayer, Role).method(args). Where _Roled_ composes RolePlayer and
Role together and method is dispatched accordingly.

Or maybe simpler: replace every method call of RoleName.method(args) 
with Dispatch(RolePlayer, Role, "method", args).

In Java it's possible to do the two latter ones.

(And no I don't have examples of them, at least not yet and these ideas 
possibly can be spectacular failures)

rune funch

unread,
Dec 25, 2012, 3:23:30 PM12/25/12
to object-co...@googlegroups.com
Den 25/12/2012 kl. 19.25 skrev Egon Elbre <egon...@gmail.com>:

> the problem is determining the correct Role/Object that should handle the message
No it's the same object playing multiple roles. The problem is
determining which of several methods to call and that is a problem
based on name clashes not multiple roles and is as noted several times
a common problem with method injection implementations

rune funch

unread,
Dec 25, 2012, 3:25:16 PM12/25/12
to object-co...@googlegroups.com
Den 25/12/2012 kl. 21.02 skrev Egon Elbre <egon...@gmail.com>:

> Or maybe do code replacement: replace every method call of RoleName.method(args)
> with _Roled_(RolePlayer, Role).method(args). Where _Roled_ composes RolePlayer and
> Role together and method is dispatched accordingly
You can do that compile time so no need to wrap

James O Coplien

unread,
Dec 25, 2012, 3:30:10 PM12/25/12
to object-co...@googlegroups.com
I agree that the mechanism shouldn't matter.

The test case is Dijkstra's Algorithm, posted in several language variants on fulloo.info. Egon, please argue in Ruby code.
> --
> You received this message because you are subscribed to the Google Groups "object-composition" group.

James O Coplien

unread,
Dec 25, 2012, 3:31:16 PM12/25/12
to object-co...@googlegroups.com

On Dec 25, 2012, at 12:02 , Egon Elbre wrote:

Or maybe simpler: replace every method call of RoleName.method(args) 
with Dispatch(RolePlayer, Role, "method", args).

In Java it's possible to do the two latter ones.

That you can do it doesn't mean you should.

One of the top goals of DCI is code readability. There are many people who have tried the Dispatch approach in Java. The code has always been impenetrable. I'd of course like to be proven wrong. But it will take more than this level of argumentation to do it.

Egon Elbre

unread,
Dec 25, 2012, 3:34:50 PM12/25/12
to object-co...@googlegroups.com
On Tuesday, December 25, 2012 10:30:10 PM UTC+2, Cope wrote:
I agree that the mechanism shouldn't matter.

The test case is Dijkstra's Algorithm, posted in several language variants on fulloo.info. Egon, please argue in Ruby code.

Yes sir :)

(mostly I'm language unbiased, I just pick whatever feels easiest to write and least ambiguous at some point)

Egon Elbre

unread,
Dec 25, 2012, 3:40:02 PM12/25/12
to object-co...@googlegroups.com
If you know the Role/RoleName it's being invoked through you will be able to determine 
the correct method and the problem of clashing just disappears.

But as you have been here longer I'm willing to call it method clashing as well.

Egon Elbre

unread,
Dec 25, 2012, 3:44:13 PM12/25/12
to object-co...@googlegroups.com
The proof should be in the pudding, so I will see what I can come up with. (But I won't guarantee success)

James O Coplien

unread,
Dec 25, 2012, 3:54:42 PM12/25/12
to object-co...@googlegroups.com

On Dec 25, 2012, at 12:34 , Egon Elbre wrote:

(mostly I'm language unbiased, I just pick whatever feels easiest to write and least ambiguous at some point)

Great. Just do it.

James O Coplien

unread,
Dec 25, 2012, 3:55:55 PM12/25/12
to object-co...@googlegroups.com

On Dec 25, 2012, at 12:44 , Egon Elbre wrote:

The proof should be in the pudding, so I will see what I can come up with. (But I won't guarantee success)

I can predict that the deck is pretty strong against you.

There were some folks who used a Java library to do something very DCI-like a few months ago. You can maybe check the mail history here.

Marc Grue

unread,
Dec 26, 2012, 11:11:08 AM12/26/12
to object-co...@googlegroups.com
Hi Egon,

The Scala macro approach doesn't wrap. I don't understand what you mean with "deep copy on the Role"…?

Can you help me locate the github explanations that led you to these impressions, so that I can make those more clear?

Cheers,
Marc

Egon Elbre

unread,
Dec 26, 2012, 12:52:11 PM12/26/12
to object-co...@googlegroups.com


On Wednesday, December 26, 2012 6:11:08 PM UTC+2, Marc Grue wrote:
Hi Egon,

The Scala macro approach doesn't wrap. I don't understand what you mean with "deep copy on the Role"…?


It seemed to me that when you do a deep-clone on the Role it will act as the Role. Basically: deepClone(Role).roleMethod() would call the role method - although I havent't tested that.
 

Can you help me locate the github explanations that led you to these impressions, so that I can make those more clear?

Mainly the explanation in "Compound objects and re-binding" and the Example from github page. 

Also the core in the core source it says

Generates the following code for the Role Player 'Account with Source'
...
new $AnonClass(RolePlayer](MoneyTransfer.this.acc1).obj)

Which to me seems like creating a new object based on the created class and using that as the Role.

James O Coplien

unread,
Dec 27, 2012, 2:59:52 PM12/27/12
to object-co...@googlegroups.com

On Dec 26, 2012, at 7:52 , Egon Elbre wrote:

It seemed to me that when you do a deep-clone on the Role it will act as the Role.

Maybe, but then you violate object identity. Again: Please try the Manhattan Dijkstra algorithm to see if it works.

Ant Kutschera

unread,
Dec 27, 2012, 6:41:07 PM12/27/12
to object-co...@googlegroups.com
On Thursday, 27 December 2012 20:59:52 UTC+1, Cope wrote:

Please try the Manhattan Dijkstra algorithm to see if it works.

+1

That certainly is a good example to try! 

Marc Grue

unread,
Dec 28, 2012, 9:09:24 AM12/28/12
to object-co...@googlegroups.com
Hi Egon,

I don't understand where deep copying relates to DCI. If you see a potential problem I would be happy to test it against the macro - in that case some pseudo testing code could serve as a start...

On 26/12/2012, at 18.52, Egon Elbre <egon...@gmail.com> wrote:
On Wednesday, December 26, 2012 6:11:08 PM UTC+2, Marc Grue wrote:
Can you help me locate the github explanations that led you to these impressions, so that I can make those more clear? 
Mainly the explanation in "Compound objects and re-binding" and the Example from github page. 
Also the core in the core source it says
Generates the following code for the Role Player 'Account with Source'
new $AnonClass(RolePlayer](MoneyTransfer.this.acc1).obj)
Which to me seems like creating a new object based on the created class and using that as the Role.

Thanks for the pointers - I'll have a look to see if I can clarify. 

Having only limited knowledge of the inner mechanics and concepts of Scala, my understanding so far is that the role binding mechanism of my macro is not creating a new object at runtime. A synthetic anonymous class ($anon) is created at compile time that extends the instance class and Role trait. At runtime the instance object will then find itself augmented with the role trait mixed in (magic!).

Later I can rebind another Role to the same object by removing the old mixin and add another one - all at compile time. We can bind the roles as though it would happen at runtime, but the "preparation" happens at compile time. In a way we can have and eat the cake at the same time!

I'm on thin ice on this, so before we have a Scala expert on board, I would take my explanations with a big grain of salt :)

Cheers,
Marc

Egon Elbre

unread,
Dec 28, 2012, 11:38:20 AM12/28/12
to object-co...@googlegroups.com


On Friday, December 28, 2012 4:09:24 PM UTC+2, Marc Grue wrote:
Hi Egon,

I don't understand where deep copying relates to DCI. If you see a potential problem I would be happy to test it against the macro - in that case some pseudo testing code could serve as a start...


(All the following is according to my current understanding of DCI )

How deep-copying relates to DCI is that when you do a deep-copy on a Role you are getting a new object that shouldn't be playing the Role in the current Context since the Role is an artifact that belongs to both Context and Object - hence it should not react to Role messages anymore. I was unfortunately incapable of writing deepClone to test it.

So deepClone(Role).roleMethod() should either fail to compile or throw method missing.
 
On 26/12/2012, at 18.52, Egon Elbre <egon...@gmail.com> wrote:
On Wednesday, December 26, 2012 6:11:08 PM UTC+2, Marc Grue wrote:
Can you help me locate the github explanations that led you to these impressions, so that I can make those more clear? 
Mainly the explanation in "Compound objects and re-binding" and the Example from github page. 
Also the core in the core source it says
Generates the following code for the Role Player 'Account with Source'
new $AnonClass(RolePlayer)(MoneyTransfer.this.acc1).obj)
Which to me seems like creating a new object based on the created class and using that as the Role.

Thanks for the pointers - I'll have a look to see if I can clarify. 

Having only limited knowledge of the inner mechanics and concepts of Scala, my understanding so far is that the role binding mechanism of my macro is not creating a new object at runtime. A synthetic anonymous class ($anon) is created at compile time that extends the instance class and Role trait. At runtime the instance object will then find itself augmented with the role trait mixed in (magic!).

Later I can rebind another Role to the same object by removing the old mixin and add another one - all at compile time. We can bind the roles as though it would happen at runtime, but the "preparation" happens at compile time. In a way we can have and eat the cake at the same time!

I'm on thin ice on this, so before we have a Scala expert on board, I would take my explanations with a big grain of salt :)

Agreed, I just reported how I understood it, and also I'm not a Scala expert.

I installed Scala and tested this:

System.identityHashCode(obj) == System.identityHashCode(role)

that shows that it's not the same object. I don't know when the role object is created and how its calls get delegated to the obj, but in my opinion it really doesn't matter, since most of the time it's nicely hidden.

rune funch

unread,
Dec 28, 2012, 2:07:01 PM12/28/12
to object-co...@googlegroups.com
2012/12/28 Egon Elbre <egon...@gmail.com>

that shows that it's not the same object. I don't know when the role object is created and how its calls get delegated to the obj, but in my opinion it really doesn't matter, since most of the time it's nicely hidden.

and it's those times where it's not nicely hidden that creates awfully well hidden bugs

James O Coplien

unread,
Dec 28, 2012, 3:08:08 PM12/28/12
to object-co...@googlegroups.com
On Dec 28, 2012, at 6:38 , Egon Elbre wrote:

since most of the time it's nicely hidden.

"Most of the time" doesn't count.

I would guess that the wrapping suggestion will fail.

Have I suggested running the Dijkstra example?

Ant Kutschera

unread,
Dec 28, 2012, 6:15:48 PM12/28/12
to object-co...@googlegroups.com
On Friday, 28 December 2012 15:09:24 UTC+1, Marc Grue wrote:
Having only limited knowledge of the inner mechanics and concepts of Scala, my understanding so far is that the role binding mechanism of my macro is not creating a new object at runtime. A synthetic anonymous class ($anon) is created at compile time that extends the instance class and Role trait. At runtime the instance object will then find itself augmented with the role trait mixed in (magic!).

I haven't looked at your macros yet, but I do know from my own investigations that JVM Bytecode suffers from the problem that the class definition is read a class-load time and it cannot be modified thereafter, so there is only one way to add role methods which I know of, which to me is unsatisfactory.  Groovy does it this way: http://groovy.codehaus.org/ExpandoMetaClass.

It would be interesting to see if you could get the Scala compiler to do the same (with macros, compiler plugins or some other way), AND maintain full type safety using type inference.

If the test proposed by Egon (System.identityHashCode(obj) == System.identityHashCode(role)) equates to false, then your solution isn't pure DCI like Cope requires. 
 
I'm on thin ice on this, so before we have a Scala expert on board, I would take my explanations with a big grain of salt :)

In the last year I have come to know Scala very well.  But I don't have time at the moment to study this or help out.  I might do in say April...

What you might do is look at the decompiled bytecode using JD-GUI (http://java.decompiler.free.fr/) to see what Scala is actually doing.  The code is virtually readable as Java, so should help you a lot.

Cheers,
Ant

Egon Elbre

unread,
Dec 30, 2012, 8:28:35 AM12/30/12
to object-co...@googlegroups.com
Here's a different version using source transformation:

http://egonelbre.com/js/dci/

On Saturday, December 22, 2012 4:15:36 PM UTC+2, Egon Elbre wrote:
Implemented an DCI lib with javascript:


I've tested it only in chrome.

Matthew Browne

unread,
Mar 1, 2013, 8:59:56 AM3/1/13
to object-co...@googlegroups.com
I think the source transformation is a very promising approach. It could even be changed to allow for a Marvin-like syntax with a "role" keyword, etc.

As to the compilation step, compilation could actually be done in the browser prior to running the code, which might be useful for development purposes, although my personal preference would be to use something like LiveReload, which runs compilers for you as soon as you save the file, then reloads the page for you (and there are ways to achieve the same thing with node.js for free without requiring the purchase of LiveReload).

If it were implemented for both Javascript and CoffeeScript I think it would definitely further the use of DCI in the Javascript community (both client-side and server-side).

I could post an example of how the syntax might work if people are interested. I'm thinking that it would use the new ECMAScript 6 syntax for classes, and be quite similar to Marvin for contexts, roles, and interactions. I don't know much about the implementation details of source transformation so perhaps this is too ambitious, but Egon's example is encouraging.

Egon Elbre

unread,
Mar 1, 2013, 9:52:26 AM3/1/13
to object-co...@googlegroups.com


On Friday, March 1, 2013 3:59:56 PM UTC+2, Matthew Browne wrote:
I think the source transformation is a very promising approach. It could even be changed to allow for a Marvin-like syntax with a "role" keyword, etc.

As to the compilation step, compilation could actually be done in the browser prior to running the code, which might be useful for development purposes, although my personal preference would be to use something like LiveReload, which runs compilers for you as soon as you save the file, then reloads the page for you (and there are ways to achieve the same thing with node.js for free without requiring the purchase of LiveReload).

The compilation step isn't necessary actually, it can run as a function as well... I think I may have forgot to update the code. http://egonelbre.com/js/dci/js/dci.js there is a function Context that doesn't require separate compilation step - I'm just not that sure how well it works with closures and in browsers other than Chrome. Compilation step in that sense is safer than doing it at "runtime".
 

If it were implemented for both Javascript and CoffeeScript I think it would definitely further the use of DCI in the Javascript community (both client-side and server-side).


Since the function works in Javascript you should be able to call it from CoffeeScript.
 
I could post an example of how the syntax might work if people are interested. I'm thinking that it would use the new ECMAScript 6 syntax for classes, and be quite similar to Marvin for contexts, roles, and interactions. I don't know much about the implementation details of source transformation so perhaps this is too ambitious, but Egon's example is encouraging.


The source transformation is pretty trivial when you have the proper AST. I just used javascript objects to avoid parsing out the AST.

The basic idea is simple: find all roles and their methods (Role,MethodName), decalre those functions as Role$MethodName. Everywhere in the context/role methods where Role.MethodName is called replace it with Role$MethodName.call(Role, .. args ..) (call in javascript invokes a method in the Role context). Then make each Role to a variable and to make a object play that role just assign to it.

I'm not sure whether it would benefit from the ECMA6 class syntax. I think that current syntax suits javascript best.

But also it could be designed via fluent interfaces:

Context().
    role('Initial', {}).
    role('Neighbor', {
      visited: function(){
        ...
      }
    }).init(function(initial, destination, graph){
      ...
    }).done();

to make it more declarative. But since I intended the source transformation more as a proof of concept and a reference for implementing DCI, it wouldn't benefit from this syntax.

Matthew Browne

unread,
Mar 2, 2013, 10:48:50 AM3/2/13
to object-co...@googlegroups.com
Nice, so now you can use it without needing to put the @ symbol at the beginning and end of the context. What I meant though is that it's still essentially compilation, it's just compilation that happens in the browser (since you're still calling toString() on the functions and modifying the source), so you might as well just use something like LiveReload at that point, and also the code should probably be pre-compiled before releasing to production (for the admittedly small performance benefit).

Since the function works in Javascript you should be able to call it from CoffeeScript.
I was referring to a "role" keyword that would be able to be parsed whether the source was in CoffeeScript or Javascript. And I figured that since you're doing source transformation anyway, it would certainly be possible to allow for such a keyword, but in any case I think it's good to have your version so users can decide which syntax they prefer.

As to the ECMA6 class syntax, it's just syntactic sugar so you're right that it's not necessary. (For the record, the end result it produces is exactly the same as what you'd get using the traditional constructor/prototype approach, just a little more concisely.)

One other cool thing about your function is that it allows for the case where you're defining roles outside of the context so the same role can be used by more than one context.

Thanks for the explanation and great job with this...it might need some tweaks as you mentioned but it's already quite usable.
--
You received this message because you are subscribed to a topic in the Google Groups "object-composition" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/object-composition/5YJ6duRtdTQ/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to object-composit...@googlegroups.com.

To post to this group, send email to object-co...@googlegroups.com.

Matthew Browne

unread,
Mar 2, 2013, 11:13:50 AM3/2/13
to object-co...@googlegroups.com
I thought it would be interesting to try out the example Rune and I were discussing in my PHP 5.4 thread using your function, and it works quite well!

Cafe = Context(
function(student, employee) {
    Student = student;
    Employee = employee;
   
    return {
        execute: function() {
            Student.work("homework");
            Employee.work();
        }
    };
},
{
    Student: {
          work: function(workType) {
              this.work(workType);
          }
    }

  , Employee: {
          work: function() {
              log("I'm serving the customers");
          }
    }
});

function Person() {}
Person.prototype.work = function(workType) {
    log("I'm doing my " + workType);
};

var person = new Person();
var cafeContext = Cafe(person, person);
cafeContext.execute();



In this case there's only one interaction ( execute() ), but I think getting an object back when calling the context probably makes sense especially if there were more than one interaction.

I'm thinking it might be better to have an optional parameter for specifying the interaction methods rather than declaring them using "return {...}" as I have done here. But this works very well overall.
Reply all
Reply to author
Forward
0 new messages