cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Ovidiu Predescu <>
Subject Re: [RT] Managing Flow and Resources
Date Wed, 19 Dec 2001 21:49:43 GMT
On Tue, 18 Dec 2001 20:57:22 -0600, Judson Lester <> wrote:

> Rereading that post in the context of later messages, it comes across much 
> more clearly, and a couple of thoughts occur to me.
> One: in accepting the idea of a flowmap, are we committed to abandoning other 
> Servlets?  Moreover, is there an advantage to avoiding the use of the Servlet 
> scopes (notably session scope)?  (I'm led to this conclusion by the 
> "continuation identifier URLs" in Ovidiu's example) If not, what call is 
> there for return values  in the flowmap?
> For example, (from the continuation example)
> function buy()
> {
>   credentials = get-user();
>   ship-to-address(credentials);
>   charge-credit-card(credentials);
> }
> would there be anything wrong with
> ...
> until(session.contains(credentials))
> 	get-user();
> ship-to-address(session.credentials);
> ....
> (syntax is odd, but I think the idea comes across)
> I recall criticisms about business logic in the flowmap, and encouraging the 
> use of Servlets in this way would help, I think.

The variable scoping is a really good point, thanks for bringing it

Lets look at the shopping cart example I gave in

If I understand right, I think you're touching on two points:

a) non-local exits affect the flow of the program, essentially adding
the notion of non-returning functions.

b) how variables defined in this language relate to session scope
variables in the servlet specification.

a) If you look closely at the get-user function, you will notice an
interesting fact, which is a non-local exit to a totally different
context, in case the user doesn't enter valid information:

function get-user()
  // get-user() returns only with valid credentials.
  // If no valid credentials are found, this function never returns.

  for (count = 0; count < 3; count++) {

    user = request.getParameter("username");
    passwd = request.getParameter("password");

    usersDB = UsersDatabase.newConnection();
    if (!usersDB.isUserKnown(user, passwd))
      return userDB.credentialsForUser(user, passwd);

  // This shows the user a sorry page with a single link that points to Home.
  // This is an example of a non-local exit, where the computation will
  // continue at a different location in the program.

What this essentially means for the caller of get-user is that it's
guaranteed that the returned value is a useful. Otherwise the flow of
the program continues in a different part of it, and never returns to
the caller.

This can make the applications potentially easier to write for a
developer doesn't have to explicitly handle error conditions. It's a
bit difficult to follow if you're not aware of the special
functionality of the send-page() function, but as you understand it,
it's much clear.

b) A continuation captures the whole state of the program, which means
program counter, call stack frames and local variables. This implies
that maintaining session objects is no longer necessary, as the whole
context is kept much better in local variables. This is very different
from the current servlet programming model, where you have to store
values across invocations in the session object.

With continuations, going back in the processing history using the
"back" button in the browser, means reverting to old values of
variables in your program. This is very difficult to achieve with
session objects.

So to answer your question about the servlet model, I think there's
little value in maintaining the session object idea. And I don't think
of anything else from the servlet programming model that needs to be
kept around. The request object is passed to the flow program, but not
the response, who is generated by the send-page() indirectly.

> Two:
> The current description of the syntax of tail calls speaks to me of huge 
> call chains.  The default behavior should usually not be to return to one's 
> caller, no?  There might be points of flow that would be frequently revisted, 
> but they ought not be "returned" to.  I'm reminded of the C/C++/Java 
> complaint of default fall-though being "wrong" in the majority of switch 
> statements.  The analogy is that if flow falls off the end of a function, it 
> should return to the caller, which seems to me should usually be wrong.  
> Perhaps return should be allowed, but all returns should be explicit?  
> In the buy() example, oughtn't a> ship-to-address and charge-credit-card fall 
> more into Servlets?  (Perhaps not entirely, but some portion...) and b> where 
> does buy() lead, eventually?  

The intent of the ship-to-address was to collect the address where the
shipment should be sent, and not to do the actual shipment. It should
perhaps be renamed to get-address-for-shipping instead to avoid any

charge-credit-card would be a similar function:

function charge-credit-card(credentials)

  // Let the user choose a credit card. The following will present the
  // user with a list of credit cards to choose from. We simplify here,
  // and assume the credit cards where previously entered into the
  // system, and the getCreditCards() method returns a list of them, for
  // the page to present them.

  send-page("choose-credit-card.xml", "my-pipeline",
            {"credit-cards = credentials.getCreditCards() });

  // The credit card chosen by the user is returned as an index in the
  // array of cards.
  credit-card = request.getParameter("credit-card");

  // Return to the caller with a CreditCard object, which represents
  // the one chosen by the user.
  return credentials.getCreditCard(credit-card);

The complete buy() function would then look like this:

function buy()
  credentials = get-user();
  address = ship-to-address(credentials);
  credit-card = charge-credit-card(credentials);

  // This calls the back-end systems to do the actual shipment. We
  // oversimplify here and assume there are no errors generated by the
  // back-end.

  Backend.shipGoodsForUser(credentials, address, credit-card);

  // This sends a response page to the client, telling him/her the
  // shipment is complete. The generated page contains only a link to the
  // home page of the Web site, which is equivalent to having a non-local
  // exit from this function. This means this function never returns!

  send-page("shipment-complete.xml", "my-pipeline",
            {"address" = address, "credit-card" = credit-card"});

So buy() really becomes a function that doesn't return to its caller.

> A corrolary of a required return keyword would be that a function would 
> declare itself returning (or a non-returning function be declared 
> "entry-point shopping-cart ()"), as a returning function would be an invalid 
> last call in a function.  

As the get-user() function shows, you can have functions that either
return with a value or not return at all. I think this is very
powerful, and we should maintain it, otherwise we force the user in
devising two different functions.

> I'd tentatively suggest that returns not be allowed, since it would be 
> incredibly difficult to implement logic in the flowmap without them.

I'm not sure I understand this: should return be or not be allowed?

> Of course "continuations" as they exist in Scheme rely on them, but
> the idea of an object to keep track of the current position doesn't
> strictly require a call stack.

As I've shown above, a continuation maintains everything, including
the call stack.

Thanks for you insightful comments!

Best regards,
Ovidiu Predescu <> (inside HP's firewall only) (my SourceForge page) (GNU, Emacs, other stuff)

To unsubscribe, e-mail:
For additional commands, email:

View raw message