You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@commons.apache.org by Todd Jonker <tv...@pobox.com> on 2002/12/12 23:09:44 UTC

[Jelly] Towards Functional programming in Jelly scripts

Hey Jellyfolk,

I'm trying to write some Jelly tags specific to a custom component
framework.  In doing so, I realized that it would be extremely helpful to be
able to write functional tags.  In effect, I'd like Jelly to be able to
support a functional programming paradigm in addition to its current
procedural paradigm.

In short, I suggest that Script.run() and Tag.doTag() both be modified to
return Object.  In other words, every tag becomes an expression that can
evaluate to a single value.  Those tags for which this isn't meaningful can
simply return null.

People familiar with Scheme or Lisp will immediately recognize what I'm
looking for and why: it will enable even easier scripting with more flexible
evaluation models.

Let me explain with a concrete example.  I want to extend JellySwing to have
an expression language that can perform Action enabling, eg:

<and>
  <instanceof value="${something}" class="MyClass" />
  <isNotNull value="${another}/>
  <core:invoke method="isReady" on="${another}"/>
</and>

The value of this script would be a Boolean.  Functional tags like these
would also be of obvious utility in JellyUnit, since this can express more
things than Jexl (as far as I can tell).  It can also be transparently
extended by any tag library without relying on variable-naming conventions.


The problem I've run into is that the only way to get a value out of a
script is via the JellyContext, by defining a variable name and making sure
my tag sticks the result in the right place.  But it order to get this model
to interact with existing logical and expression tags, the "result" variable
has to be scattered all over the file.

(Harking back to grad school, one observes that the functional model can
cleanly express the procedural model, whereas the opposite is not true.)


Perhaps there's a way to get this kind of functionality from the existing
APIs, but I've searched all over and can't see how to do it.

I realize that this API extension would involve adding lots of "return
null"s to existing tags and scripts, but it'll be MUCH easier to do this now
while Jelly's still in Beta.  And I believe the added power and
expressiveness are well worth the effort.  Of course I volunteer to help
make the transition if its implemented.


I'd love to hear feedback from James and the other users.

Cheers,
-Todd

-- 
I look for what needs to be done.... After all, that's how the universe
designs itself. -R. Buckminster Fuller, engineer, designer, and architect
(1895-1983)



Re: [Jelly] Towards Functional programming in Jelly scripts

Posted by Paul Libbrecht <pa...@activemath.org>.
I wonder wether an extension of XMLOutput would not be closer to the 
lines of what you're saying within Jelly. It would be much more 
flexible than a simple return value. In all my jelly-scripts, it's 
unused (and considered as "ah yes, I mistyped that one").

I sort of agree that it does not really make sense for a component to 
have to add itself to a possible parent container. Also, the layout 
business would have much less overhead it did not have to be plugged at 
the component level.

Presumably, a good example where something close to functional would be 
needed would be things like ImageFilters. Swing components could also 
take advantage of it; I am sure I can imagine containers which actually 
do something weird to their children (e.g. a hyperbolic viewer, a 
color-change...).

Paul


On Samedi, déce 14, 2002, at 19:47 Europe/Brussels, Todd Jonker wrote:
> In short, adding return-values to Script and Tag provides the same 
> benefits
> as having return values in normal functions and methods.   As such, I
> believe it would open up Jelly to a much broader variety of XML tasks, 
> while providing opportunities to reduce the coupling and complexity of 
> Tag
> classes. 
>  

Re: [Jelly] Towards Functional programming in Jelly scripts

Posted by Todd Jonker <tv...@pobox.com>.
Thanks for the feedback, Rodney and James.  Rodney, your workaround code is
quite similar to what I'm having to do, dut it's rather more complex than it
would need to be if tags and scripts had return values.

Regarding your suggested patch to TagSupport, yes that's a way to avoid
changing subclasses.  However, I don't feel it's the best long-term solution
since it adds another facet of complexity and indirection.  It's already
difficult enough to trace the code through non-trivial tag libraries like
JellySwing.

James, your expression language would be a valuable addition, too.  I
believe others on the list have talked about making pluggable expression
languages, and I agreed that it would be extremely useful.  However, it
doesn't solve my particular problem, so I hope you'll let me explain in more
detail.

At the moment, I find it very difficult to get values back from Jelly
scripts after they have run.  Jelly scripts and tags act in many ways like
functions, but they cannot have return values, so they can only perform
side-effects like JellyContext.setVariable().  I feel that this is a recipe
for complex and fragile programs.

I was drawn to Jelly specifically because of JellySwing, since it does 75%
of what I need for my UI framework's configuration system.  I need to write
XML files that put together panels and frames, refactor and compose them,
and access external components.  However, each script must also return the
window or panel to the framework so the WindowManager can latch onto it.
The only way to do this currently is to write my Jelly scripts like:

  <frame var="result">...</frame>

Where "result" is an externally-specified magic variable.  I'm effectively
shoving the value in a global because a Jelly script can't return a value
like a "real" function.

What I dislike about the FunctionalTagParent pattern is that it will be very
hard to evolve and extend, because the child tags are tightly-coupled to
specific types of parents.  The functional approach lets each tag build up
and directly return it's value, and the parent can be any class.  As with a
method call, it's up to the parent to determine what to do with the result.
The child tags can be completely decoupled from their context, and therefore
are much easier to reuse.

To give a concrete example, consider JellySwing's frame/action nesting.
Currently, an ActionTag code must be used inside a ComponentTag (without
falling back to the var="result" workaround).  I would like to be able to
define sets of actions that are not bound to a particular component, so they
can be used several places:

  <actionSet>
    <action name="New Browser" ... />
    <action name="Quit" ... />
  <actionSet>

As far as I can see, there's no clean way to do this in Jelly, without
making ActionSetTag extend ComponentTag.  Under a functional model, the
sequence of child tags would evaluate to a sequence of values.  ActionTag
can be completely decoupled from any particular context.

I'm envision something like:

class ActionSetTag
{
    public Object doTag(XMLOutput output)
    {
        List bodyResults = invokeBody(output);

        myActions.addAll(bodyResults);
    }

    private Set myActions;
}

(Note that type-safety can be ensured via an appropriate DTD, a very nice
benefit.)

For a parent tag like FrameTag, after calling invokeBody it can simply
iterate through the results and handle each one appropriately to it's type.
Of course, it would be nice to get the results as they occur, to allow
short-circuiting, but that can also be added to the current framework quite
easily.


In short, adding return-values to Script and Tag provides the same benefits
as having return values in normal functions and methods.   As such, I
believe it would open up Jelly to a much broader variety of XML tasks, while
providing opportunities to reduce the coupling and complexity of Tag
classes.  


Sincerely,
.T.


Re: [Jelly] Towards Functional programming in Jelly scripts

Posted by James Strachan <ja...@yahoo.co.uk>.
Agreed with all of that.

Another approach could be to create a functional expression language. e.g.
you could bind the core library to a new namespace with a different
expression language (say, lisp or scheme etc).

<lisp:if test="(dont(), know(), lisp(), much())">
    ...
</lisp:if>

or to use your original example...

> > <and>
> >   <instanceof value="${something}" class="MyClass" />
> >   <isNotNull value="${another}/>
> >   <core:invoke method="isReady" on="${another}"/>
> > </and>
> >


<lisp:if test="(and(instanceof(something, 'MyClass'), isNotNull(another),
isReady(another))">
    ...
</lisp:if>

James
-------
http://radio.weblogs.com/0112098/
----- Original Message -----
From: "Rodney Waldhoff" <rw...@apache.org>
To: "Jakarta Commons Users List" <co...@jakarta.apache.org>
Sent: Thursday, December 12, 2002 11:34 PM
Subject: Re: [Jelly] Towards Functional programming in Jelly scripts


> I'll withhold judgement on the doTag returns Object idea for now, except
> to say I've also run into situations where it something like that would be
> useful (and it may not be that disruptive if most folks extend TagSupport
> and we did something like: Object doTagWithReturn(XMLOutput out) {
> doTag(out); return null; }) but as to how one might accomplish this in the
> current API, I think something like this might suffice:
>
> interface FunctionalTagParent {
>   void addResult(Object obj);
> }
>
> class FunctionalTagParentBase extends TagSupport implements
FunctionalTagParent {
>   List results = new ArrayList();
>   void addResult(Object obj) {
>      results.add(obj);
>   }
>
>   Iterator getResults() {
>      return results.iterator();
>   }
> }
>
> class AndTag extends FunctionalTagParentBase implements
FunctionalTagParent {
>   public void doTag(XMLOutput out) {
>     invokeBody(out);
>     boolean result = true;
>     for(Iterator iter = getResults(); iter.hasNext();) {
>       result &= ((Boolean)(iter.next())).booleanValue();
>     }
>     FunctionalTagParent parent =
findAncestorWithClass(FunctionalTagParent.class);
>     if(null != parent) { parent.addResult(new Boolean(result)); }
>   }
> }
>
> etc.
>
> This is what I've done in similiar circumstances (e.g., this is how
> <j:invoke> and <j:new> work with <j:arg>).  Is this an approach you've
> already considered?
>
> On Thu, 12 Dec 2002, Todd Jonker wrote:
>
> > Hey Jellyfolk,
> >
> > I'm trying to write some Jelly tags specific to a custom component
> > framework.  In doing so, I realized that it would be extremely helpful
to be
> > able to write functional tags.  In effect, I'd like Jelly to be able to
> > support a functional programming paradigm in addition to its current
> > procedural paradigm.
> >
> > In short, I suggest that Script.run() and Tag.doTag() both be modified
to
> > return Object.  In other words, every tag becomes an expression that can
> > evaluate to a single value.  Those tags for which this isn't meaningful
can
> > simply return null.
> >
> > People familiar with Scheme or Lisp will immediately recognize what I'm
> > looking for and why: it will enable even easier scripting with more
flexible
> > evaluation models.
> >
> > Let me explain with a concrete example.  I want to extend JellySwing to
have
> > an expression language that can perform Action enabling, eg:
> >
> > <and>
> >   <instanceof value="${something}" class="MyClass" />
> >   <isNotNull value="${another}/>
> >   <core:invoke method="isReady" on="${another}"/>
> > </and>
> >
> > The value of this script would be a Boolean.  Functional tags like these
> > would also be of obvious utility in JellyUnit, since this can express
more
> > things than Jexl (as far as I can tell).  It can also be transparently
> > extended by any tag library without relying on variable-naming
conventions.
> >
> >
> > The problem I've run into is that the only way to get a value out of a
> > script is via the JellyContext, by defining a variable name and making
sure
> > my tag sticks the result in the right place.  But it order to get this
model
> > to interact with existing logical and expression tags, the "result"
variable
> > has to be scattered all over the file.
> >
> > (Harking back to grad school, one observes that the functional model can
> > cleanly express the procedural model, whereas the opposite is not true.)
> >
> >
> > Perhaps there's a way to get this kind of functionality from the
existing
> > APIs, but I've searched all over and can't see how to do it.
> >
> > I realize that this API extension would involve adding lots of "return
> > null"s to existing tags and scripts, but it'll be MUCH easier to do this
now
> > while Jelly's still in Beta.  And I believe the added power and
> > expressiveness are well worth the effort.  Of course I volunteer to help
> > make the transition if its implemented.
> >
> >
> > I'd love to hear feedback from James and the other users.
> >
> > Cheers,
> > -Todd
> >
> > --
> > I look for what needs to be done.... After all, that's how the universe
> > designs itself. -R. Buckminster Fuller, engineer, designer, and
architect
> > (1895-1983)
>
>
> --
> To unsubscribe, e-mail:
<ma...@jakarta.apache.org>
> For additional commands, e-mail:
<ma...@jakarta.apache.org>
>

__________________________________________________
Do You Yahoo!?
Everything you'll ever need on one web page
from News and Sport to Email and Music Charts
http://uk.my.yahoo.com

Re: [Jelly] Towards Functional programming in Jelly scripts

Posted by Rodney Waldhoff <rw...@apache.org>.
I'll withhold judgement on the doTag returns Object idea for now, except
to say I've also run into situations where it something like that would be
useful (and it may not be that disruptive if most folks extend TagSupport
and we did something like: Object doTagWithReturn(XMLOutput out) {
doTag(out); return null; }) but as to how one might accomplish this in the
current API, I think something like this might suffice:

interface FunctionalTagParent {
  void addResult(Object obj);
}

class FunctionalTagParentBase extends TagSupport implements FunctionalTagParent {
  List results = new ArrayList();
  void addResult(Object obj) {
     results.add(obj);
  }

  Iterator getResults() {
     return results.iterator();
  }
}

class AndTag extends FunctionalTagParentBase implements FunctionalTagParent {
  public void doTag(XMLOutput out) {
    invokeBody(out);
    boolean result = true;
    for(Iterator iter = getResults(); iter.hasNext();) {
      result &= ((Boolean)(iter.next())).booleanValue();
    }
    FunctionalTagParent parent = findAncestorWithClass(FunctionalTagParent.class);
    if(null != parent) { parent.addResult(new Boolean(result)); }
  }
}

etc.

This is what I've done in similiar circumstances (e.g., this is how
<j:invoke> and <j:new> work with <j:arg>).  Is this an approach you've
already considered?

On Thu, 12 Dec 2002, Todd Jonker wrote:

> Hey Jellyfolk,
>
> I'm trying to write some Jelly tags specific to a custom component
> framework.  In doing so, I realized that it would be extremely helpful to be
> able to write functional tags.  In effect, I'd like Jelly to be able to
> support a functional programming paradigm in addition to its current
> procedural paradigm.
>
> In short, I suggest that Script.run() and Tag.doTag() both be modified to
> return Object.  In other words, every tag becomes an expression that can
> evaluate to a single value.  Those tags for which this isn't meaningful can
> simply return null.
>
> People familiar with Scheme or Lisp will immediately recognize what I'm
> looking for and why: it will enable even easier scripting with more flexible
> evaluation models.
>
> Let me explain with a concrete example.  I want to extend JellySwing to have
> an expression language that can perform Action enabling, eg:
>
> <and>
>   <instanceof value="${something}" class="MyClass" />
>   <isNotNull value="${another}/>
>   <core:invoke method="isReady" on="${another}"/>
> </and>
>
> The value of this script would be a Boolean.  Functional tags like these
> would also be of obvious utility in JellyUnit, since this can express more
> things than Jexl (as far as I can tell).  It can also be transparently
> extended by any tag library without relying on variable-naming conventions.
>
>
> The problem I've run into is that the only way to get a value out of a
> script is via the JellyContext, by defining a variable name and making sure
> my tag sticks the result in the right place.  But it order to get this model
> to interact with existing logical and expression tags, the "result" variable
> has to be scattered all over the file.
>
> (Harking back to grad school, one observes that the functional model can
> cleanly express the procedural model, whereas the opposite is not true.)
>
>
> Perhaps there's a way to get this kind of functionality from the existing
> APIs, but I've searched all over and can't see how to do it.
>
> I realize that this API extension would involve adding lots of "return
> null"s to existing tags and scripts, but it'll be MUCH easier to do this now
> while Jelly's still in Beta.  And I believe the added power and
> expressiveness are well worth the effort.  Of course I volunteer to help
> make the transition if its implemented.
>
>
> I'd love to hear feedback from James and the other users.
>
> Cheers,
> -Todd
>
> --
> I look for what needs to be done.... After all, that's how the universe
> designs itself. -R. Buckminster Fuller, engineer, designer, and architect
> (1895-1983)