Continuation in subcontexts

51 views
Skip to first unread message

Andreas Söderlund

unread,
Sep 17, 2013, 7:11:20 AM9/17/13
to object-co...@googlegroups.com
I'm thinking about how to make subcontexts pass a message back to the parent context, especially when the subcontext is asynchronous and/or long-lived. Here are some options, in a RoleMethod:

1. Return a deferred object from the Interaction

new SubContext().execute().done(self.doSomething).fail(...);

Quite simple, and error handling is the responsibility of the current Context. Very similar is

2. Pass a callback to the subcontext

new SubContext(self.doSomething).execute()

Error handling is now elsewhere. But my issue with 1 and 2: Is it true to DCI passing a function, instead of an object that will play a role? This leads me to

3. Pass the current Role or another object to the Context, letting it play a Role

new SubContext(self).execute() 

Here I'm unsure how to pass the message back however. The RoleMethods on self are gone when entering a new Context, so I cannot expose any of them as a RoleInterface. Is this a place for a new Interaction?

4. Create a new Interaction and pass the Context itself, letting it play a Role

new SubContext(context).execute() // context.nextStep() will be called inside the subcontext

What bothers me in this case is that a Role is allowed to pass its Context to another Context. Should it even care about the Context itself, not just the properties of it? And adding an Interaction to the Context for every subcontext, could it be a smell? Or is this a valid point for an Interaction? I'd appreciate your thoughts.


/Andreas

James O Coplien

unread,
Sep 17, 2013, 9:13:43 AM9/17/13
to object-co...@googlegroups.com
Asynchronous execution is an issue that seems to be completely separable from DCI. There are as many good and bad ways of passing message between asynchronous things as there are outside DCI. And I don't think DCI either helps or hurts the cause.


--
You received this message because you are subscribed to the Google Groups "object-composition" group.
To unsubscribe from this group and stop receiving emails from it, send an email to object-composit...@googlegroups.com.
To post to this group, send email to object-co...@googlegroups.com.
Visit this group at http://groups.google.com/group/object-composition.
For more options, visit https://groups.google.com/groups/opt_out.

Andreas

unread,
Sep 17, 2013, 10:11:28 AM9/17/13
to object-co...@googlegroups.com
I agree with that, but still I'm curious about function passing in DCI. If I decide to do option 2 and pass a callback to a context, can the callback play a role? Does it make sense?


2013/9/17 James O Coplien <jcop...@gmail.com>

rune funch

unread,
Sep 17, 2013, 10:21:10 AM9/17/13
to object-co...@googlegroups.com
Den 17/09/2013 kl. 15.13 skrev James O Coplien <jcop...@gmail.com>:

> Asynchronous execution is an issue that seems to be completely separable from DCI. There are as many good and bad ways of passing message between asynchronous things as there are outside DCI. And I don't think DCI either helps or hurts the cause.

+1

James O Coplien

unread,
Sep 17, 2013, 10:33:44 AM9/17/13
to object-co...@googlegroups.com

On Sep 17, 2013, at 4:11 , Andreas wrote:

I agree with that, but still I'm curious about function passing in DCI. If I decide to do option 2 and pass a callback to a context, can the callback play a role? Does it make sense?

Not entirely.

You can't "pass a role." A role is a name for an object — a name that carries some meaning and ability to interpret the object in certain ways.

I don't know what you mean by "a callback to a Context." Do you mean to invoke a method on that other Context object? Do you mean to call a method on one of the objects that plays a role in that other Context? You can of course pass the object — but in any case, the object effectively loses any appearance of having any of its role methods from the current context when passed back to the "parent" Context.

You do (I think) bring up a scenario that hasn't been explored in detail before (if I understand what you mean) that might place a Context in two places on the Context stack. That's a little weird, but as long as role scoping is obeyed (a role method may be called only from within the Context where that role is defined) I don't foresee any fundamental problems with that arrangement.

If by "a callback to a Context" you mean that an object that plays a role in one Context calls a method of an object that plays a role in another Context — well, yes, it happens all the time. Objects can carry several independent identities and are responsible for resolving any confusion that arises when called from different Contexts in unexpected sequences — just as an ordinary object is responsible for dealing with the confusion that arises from object methods being called from different threads in unexpected sequences. That's a general design question about which I believe DCI is neutral: i.e., it doesn't necessarily make things any worse or any better.

A good concrete motivating example might help.

Andreas Söderlund

unread,
Sep 17, 2013, 11:06:47 AM9/17/13
to object-co...@googlegroups.com
Thanks, what I'm thinking about is passing a function, like its done in for example javascript. Here's an example I'm working on, Facebook authentication for a login dialog:

class Login
{    
    Login(dialog, server) {
        this.dialog = dialog;
        this.server = server;
    }
    
    execute() {
        dialog.open();
    }

    role dialog {
        open() {
            // ...
            // Passing a RoleMethod to another Context here
            new FacebookAuthentication(context.server.authenticate).execute();
        }
    }
    
    role server {
        authenticate(token) {
            // ...
        }
    }
}

class FacebookAuthentication
{
    FacebookAuthentication(completed) {
        this.completed = completed; // The callback function
        this.fb = FB; // Existing object
    }
        
    execute() {
         fb.openPopupWindow();
    }
        
    role fb {
        openPopupWindow() {
            // ...
        }
        
        verifiedUser(token) {
            // Call the RoleMethod in the other context
            context.completed(token);
        }
    }
}



2013/9/17 James O Coplien <jcop...@gmail.com>

--

Matthew Browne

unread,
Sep 22, 2013, 5:24:22 PM9/22/13
to object-co...@googlegroups.com, cisc...@gmail.com
This is an interesting question. I recently encountered a similar situation where I wanted to call a method on a parent context from a sub-context, although as you point out, calling a parent context method is just one of the ways of passing a message back to the parent context.

I agree with what Jim said about asynchronous calls being a separate discussion - there are lots of ways you could do it asynchronously that wouldn't require any additional interaction methods - one you didn't mention is using events (although that would effectively be the same as your example of a deferred object in this case).

So as far as DCI is concerned I think the interesting options to compare from your original list are #3 and #4.


In your original post, you said:
I'm thinking about how to make subcontexts pass a message back to the parent context, especially when the subcontext is asynchronous and/or long-lived.
I don't think the word "especially" belongs in that sentence. For a single method call on the sub-context you could just get a return value immediately and then pass that return value directly to the next role method in the parent context that you want to call. So I only see this being an issue in three scenarios:

Scenario 1. The sub-context method is asynchronous, and needs to return a value back to the parent context.

Scenario 2.
The sub-context method calls other method(s) in the sub-context, and after the last of these methods completes, a value should be returned to the parent context. This could of course be accomplished simply by passing the return value back to the sub-context method that was initially called, which in turn would return it to the parent context. In practice this would probably be obvious, but just to be clear what I mean, here's an example:

In the parent context:
returnValue = new SubContext(self).execute()

In the sub-context:
function execute() {
  //...
  return foo();
}
function foo() {
  //...
  return something;
}


Scenario 3.
You want to call a parent context method from a sub-context, but also have some other sub-context behavior that should happen afterwards, e.g.:

In the parent context:
new SubContext(self).execute();

In the sub-context:
foo();
parentContext.nextStep();
if (someCondition) bar();


Let's consider your option #3:

3. Pass the current Role or another object to the Context, letting it play a Role

new SubContext(self).execute()

Here I'm unsure how to pass the message back however. The RoleMethods on self are gone when entering a new Context, so I cannot expose any of them as a RoleInterface. Is this a place for a new Interaction?
When you say "pass the current Role" it looks like what you actually meant was "pass the current role player".

I wonder if it's actually necessary in all cases for the parent context roles to be unbound when a parent context calls a sub-context...it seems that in many cases, a sub-context is just a specialization of some function that the parent context could do itself but which either needs to be reused by other contexts (a habit) or is just distinct enough to deserve its own context for better code organization. If the parent context roles remained bound upon entering the sub-context, then your option #3 would be viable, but I can see how allowing that would be problematic. It would definitely need to be under the programmer's control, and the default should still be to unbind roles automatically when switching contexts. In the end I imagine it's probably best to forget about option 3, unless you create a new interaction method on the parent context as you mentioned.

4. Create a new Interaction and pass the Context itself, letting it play a Role

new SubContext(context).execute() // context.nextStep() will be called inside the subcontext

What bothers me in this case is that a Role is allowed to pass its Context to another Context. Should it even care about the Context itself, not just the properties of it? And adding an Interaction to the Context for every subcontext, could it be a smell? Or is this a valid point for an Interaction? I'd appreciate your thoughts.
If the sub-context method is actually asynchronous (scenario #1 above), it seems like your best option is to use an asynchronous technique like your #1 or #2, or events.

For scenario 2 you can just use a regular return value as I mentioned above.

For scenario 3, my vote would be for option #4 - I think that scenario would be a valid motivation for a new interaction method on the parent context, especially in the case where everything is completely synchronous, in which case it doesn't seem right to require the programmer to use an asynchronous technique.

I hope my musings on this have been helpful in some way...

Matthew Browne

unread,
Sep 22, 2013, 5:26:28 PM9/22/13
to object-co...@googlegroups.com, cisc...@gmail.com
On another note...

Andreas, is your code example real code? Did you write a source
transformation library that makes the "role" keyword work? I notice
you're using the ECMAScript 6 "class" feature as well (TypeScript?) The
syntax seems ideal for DCI in Javascript and I'd be very interested to
know if you've had success with an implementation of this code.

Andreas Söderlund

unread,
Sep 22, 2013, 5:45:57 PM9/22/13
to object-co...@googlegroups.com
Thanks Matthew for your analysis. It helps for sure. :) I'll come back with comments on that, just wanted to say that the source code doesn't exist yet, but there is good hope. Some clever guy had a kickstarter funded for rewriting the coffeescript compiler, its practically usable, and I'm planning to use its extensibility to make that transform to JavaScript. I'll be back before I'm starting, so we can discuss details in the group. Here's the project: https://github.com/michaelficarra/CoffeeScriptRedux

/Andreas

Matthew Browne

unread,
Sep 22, 2013, 6:07:35 PM9/22/13
to object-co...@googlegroups.com
Cool. I think the ideal thing would be to have implementations for both CoffeeScript and TypeScript. TypeScript not only because it's nice to have the option of using types, but also because it's a superset of regular Javascript including some of the features planned for ECMAScript 6...so it would be killing 2 birds with one stone - an option for those wanting to use TypeScript as well as those who only want plain Javascript. But I haven't looked at sweetjs in detail yet (which Egon recommended) so that should be considered as an option for a plain Javascript implementation as well.

In addition to the DCI goodness, it would be great if a transpiler could make a self keyword available in every method, including role methods of course. Very often in Javascript I end up having to put in this line to avoid scoping issues with this:

var self = this;

In CoffeeScript I believe it's less of an issue, plus CoffeeScript has some nice Ruby-like syntax.

(It's worth noting that the issues with this might be less of an issue in future versions of Javascript anyway - for details see the "lexical this" section of this post on Brendan Eich's blog. The proposal is that in the places where this would be set to undefined in today's Javascript, it would instead be set to the surrounding object by default. But for DCI role methods obviously there should still be a self keyword available.)
--
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/-bJT08UOOJA/unsubscribe.
To unsubscribe from this group and all its topics, send an email to object-composit...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages