cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Stefano Mazzocchi <stef...@apache.org>
Subject Re: [Schecoon] flow control layer
Date Thu, 28 Feb 2002 15:12:14 GMT
Ovidiu Predescu wrote:

> > Trust the power of open development and trust the open-mindness of the
> > cocoon community.
> 
> I do trust the model, but sometime is hard to formulate what you want
> to accomplish.

True :)

> What I've been thinking about is a syntax which emulates the semantic
> of the Scheme language as close as possible, yet provide a syntax, and
> a tight integration with Java.
> 
> In Scheme there is no notion of statement, everything is an
> expression. This makes possible all sorts of things, so I'm going to
> follow this approach.
> 
> Scheme defines nested functions and lexical scoping. A free variable
> in an inner function (aka a variable not declared in that function) is
> bound in the lexical scope in which it appears, e.g. its definition is
> looked up in the outer scopes. This mechanism is called closure, and
> is a requirement for continuations as first class objects.
> 
> In Scheme identifiers can contain any symbol you like, except spaces,
> because operators, which are really functions, always appear in the
> first position in a list. So identifiers like call/cc, send-page,
> clear+add are perfectly valid. To be able to call normal Scheme
> functions from the flow language, we need to have the same
> ability. However because operators in jWebFlow are going to be infix,
> we need to require a space before them (see further why a space is not
> required after it). Characters like '(' ')' ',' are not allowed in
> identifiers. Special characters like '+' '-' '"' and ' are not allowed
> at the beginning or end of an identifier. This allows for things like
> '-a' 'a - b' 'a++', 'f(1)' to really mean what you intend. However
> 'a-b' is an identifier.
> 
> As I mentioned earlier functions also associate arguments by name. You
> can call a function either by enumerating the expressions, or by
> associating them with names. In the later case, you can pass fewer or
> more arguments than are actually declared by the function:
> 
>  function my_func(a, b, c)
>  {
>    ...
>  }
> 
>  // positional invocation:
>  my_func(1, 2, 3);
> 
>  // by name invocation:
>  my_func(a = 1, b = 2, c = 3);
>  my_func(c = 3, a = 1, b = 2);
>  my_func(a = 1);
>  my_func(d = 4, c = 3, a = 1, b = 2);
> 
> By name invocation will allow invocation from the XML sitemap without
> having to remember what is the order in which the arguments have been
> declared in the function:
> 
>   <map:call function="my_func">
>     <map:parameter name="c" value="2"/>
>     <map:parameter name="a" value="1"/>
>     <map:parameter name="b" value="3"/>
>   </map:call>

Yes, that's a very good point.

> The actual values of the arguments in my_func are associated using
> their actual name. Any additional arguments which are not declared by
> the function, will be simply ignored.
> 
> Like in Lisp, Scheme, JavaScript, Smalltalk, Python, etc. variables
> don't have types associated with them, only values have. Variables are
> declared using 'var':
> 
>  function my_func(a, b, c)
>  {
>    var d = 1;
>  }
> 
> Functions are first class objects, you can assign functions to
> variables. There is the notion of anonymous function, a function
> without a name:
> 
>  var f = function(a, b) { a + b; };
>  f(1, 2);

Makes perfect sense. 

In fact, I really liked the fact that java named the subroutines
'methods' and not 'functions' (C-like) or 'procedures' (Pascal-like), in
fact, a method is more abstract and a function, borrowing the math term,
is more or a mapping between two domains that a logic block.

So, having the ability to have functions as first class objects is both
powerful and elegant, at least to my eyes.

> The above declares f as a variable that holds a function which takes
> two arguments. The function returns the sum of the two
> arguments. Anonymous functions are the equivalent of lambda functions
> in Scheme.

yes, I see this, but with a much less eye-offending syntax :)
 
> Blocks of code are declared with curly braces ('{' and '}'). A block
> is really an sequential list of expressions. The value returned by the
> block is the last expression in the block:
> 
>  function my_func(a, b)
>  {
>    var c = { if (a > b) a; else b; };
>  }

Hmmm, not sure I like the implicit behavior of this. Sure it makes the
syntax more compact, but it might be harder to read. I would rewrite it
as

 function my_func(a,b) {
   return { 
	if (a > b) {
		return a; 
	} else {
		return b;
	}
   }
 }

[granted, the example is stupid, but you get the point]

> The 'return' special form, takes an optional expression as argument,
> and terminates the execution of the current block. The value of the
> block becomes the value of the 'return' expression, if any, otherwise
> void is returned (see below for an explanation of void).
> 
>  function my_func(a, b)
>  {
>    if (a == 0)
>      return b;
> 
>     // Some lengthy computation here
>     ...
>  }

What I don't like about 'implicit behavior' is the fact that people must
be aware of these rules in order to understand what's going on behind
their backs... sure, this is no problem for you when you write the code
since you probably know what you're doing, but yor colleages that comes
next has much less information to learn from.

So, I'm ok for having an implicit void return (which means 'no return
means I return nothing'), but I don't like the implicit valued return
out of 'last variable', I think this is potentially harmful even if
reduces verbosity.
 
> As Scheme the language has proper tail recursion. This means the
> following code consumes no stack at runtime:
> 
>  function f (i, acc)
>  {
>    if (i == 0)
>      acc;
>    else
>      f (i - 1, acc + i);
>  }
> 
>  f (100000);

Cool, even if I don't see much use of big-time recursion in flow
languages (at least, if you need it, there's too much business logic in
your flow)

> Built-in datatypes are numbers, arrays, dictionaries and function
> objects. There is a special type 'void', that has a single possible
> value named 'void'.

What about 'strings', 'dates' and the like? 

> With numbers there is no distinction between int, float etc. as in
> Java. Instead, as in Scheme, the language supports a tower of numeric
> subtypes, which allows arbitrarily large numbers, either exact or
> inexact, in a transparent manner.
> 
> An array is declared using square brackets ('[' and ']'):
> 
>  var array = [1, 2, "abc"];

how do you access the array values?

 var a = array[1];

would be my guess, where the [*] expression indicates a positional
indication.
 
> A dictionary is defined using comma in an expression context:
> 
>  var dict = {"a" = 1, "b" = 2};

how do I access the dict values?

 var a = dict["a"];

would be my guess, where the [*] expression indicates an hashmap-like
random-access indication. (sort of an array with indirected positions)
 
> As in Scheme and JavaScript, dynamic code can be created and executed
> at runtime using the 'eval' function:
> 
>  eval("1 + 2");
> 
> parses and evaluates the "1 + 2" expression. Eval makes the parser and
> evaluator available in the language.

Yes, this is really powerful. I remember discovering this in BASIC when
I was a little kid and loved it :)
 
> The interface with Java is straightforward. You can write:
> 
>  import java.io.*;
> 
>  var a = new InputStream(new File("/tmp/a"));
> 
> The 'import' statement is a special expression which defines, in the
> current scope, a set of variables with the same name as the imported
> classes. E.g. this means that the scope of an imported class name is
> valid only in the scope in which it was defined:
> 
>   {
>     import org.MyClass;
> 
>     var a = new MyClass(); // refers to org.MyClass
>   }
>   new MyClass(); => illegal, MyClass not defined
> 
>   import com.MyClass;
>   var b = new MyClass; // refers to com.MyClass;

cool, I love this, it finally removes the need for classname collision
in the same file (as for the classname Parser, which almost every
package defines nowadays!) 

What about:

 import org.first.MyClass;

 var a = new MyClass();

 {
   import org.second.MyClass;
 
   var a = new MyClass();
 }

 a = ??

is "a" still referenced to 'org.first.MyClass'?
 
> Handling Java exceptions is similar with Java:
> 
>  try {
>    a.write("abc");
>  }
>  catch(IOException e) {
>    System.out.println("exception caught: " + e);
>    throw new RuntimeException(e);
>  }
> 
> The lexical scoping, of which I've talked about earlier, allows things
> like this:
> 
>  function my_func(a, b)
>  {
>    function(c)
>    {
>      return a + b + c;
>    }
>  }
> 
>  var f1 = my_func(1, 2);
>  var f2 = my_func(2, 3);
> 
>  f1(3); // returns 6
>  f2(4); // returns 9
> 
> my_func is a function which returns a function object. Inside the
> returned function object, the values of a and b are bound to the ones
> at the time of my_func invocation. For example in the f1 case, the a
> and b values are bound to 1 and 2 respectively. This is what is called
> 'closure' in functional languages.

yes, this is a very cool feature.
 
> I guess I can go on and on, but I'll stop here. Please let me know if
> I forgot to mention something which you consider is important.

I'll think about it a little more.

> Right now I'm trying to decide on a way to implement the translator,
> which also allows me to introduce support for macros at a later
> point. Macros would be an advanced feature of the language, which
> allows one to introduce new syntaces for the language, essentially
> extending the language syntax at runtime. This is one of the very
> powerful features of Scheme and Lisp languages in
> general. Particularly Scheme has a very powerful way of defining
> macros, and I'd like to have this in the language as well. In fact, if
> you look at Scheme, the core language has very few built-in
> constructs, and everything else is defined in terms of these using
> macros.
> 
> While programming in Python some years ago, I always missed the
> ability to define my own syntax. 

Ahg, smells like FS to me :)

> The Python parser is implemented very
> nicely, which makes you think you can extend the syntax, or define new
> mini-languages by using Python's parser. Unfortunately this is not
> possible, as Python doesn't expose the parser at the language level.
> 
> OK, I'm not going to talk more about this feature, as I think Stefano
> will quickly categorize it in the "flexibility syndrom" category ;-)

yep :) 

> I'll see instead if I can implement the translator in a way which
> leaves the doors open.

ok, we'll see where this brings us.

-- 
Stefano Mazzocchi      One must still have chaos in oneself to be
                          able to give birth to a dancing star.
<stefano@apache.org>                             Friedrich Nietzsche
--------------------------------------------------------------------


---------------------------------------------------------------------
To unsubscribe, e-mail: cocoon-dev-unsubscribe@xml.apache.org
For additional commands, email: cocoon-dev-help@xml.apache.org


Mime
View raw message