Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 2 Next »

Metadata

Number:

GEP-3

Title:

Command Expression based DSL

Version:

1

Type:

Feature

Target:

1.7 or 2.0

Status:

Draft

Leader:

Jochen "blackdrag" Theodorou

Created:

2009-30-06

Last modification:

2009-30-06

Abstract

Since Groovy 1.0 Groovy supports command expressions. These are method calls without parenthesizing the arguments. This would be in theory a nice base for DSLs, but our command expressions are too limited, because we were not able to find easy rules on how to handle multiple arguments. This proposal now tries to close the gap by defining the evaluation order and meaning of those arguments. The concept is very near to what Scala allows, but is not equal for historic reasons.

Rationale

Current Command Expression

examples of current command expressions are:

command expression

meaning

foo a1

foo (a1)

foo {c}

foo ({c})

foo m {c}

foo (m({c})

foo a1, a2

foo (a1, a2)

foo k1:v1, a2, k2:v2

foo ([k1:v1, k2:v2], a2)

foo k1:m{c}

foo ([k1:m({c})])

examples of current command expressions, that are not allowed:

command expression

possible meanings

foo a1 a2

foo(a1,a2)
foo(a1(a2))
foo(a1).a2

foo a1 a2 a3

foo(a1,a2,a3)
foo(a1(a2(a3)))
foo(a1).a2(a3)
foo(a1,a2(a3))

This list is not intended to be complete.

Constraints

  • existing valid usages must be kept as much as possible (backwards compatibility)
  • the evaluation must be easily explainable
  • the grammar should support it

Details

What I want to allow are expressions such as

expression

possible meanings

allowed in old syntax

foo {c}

foo({c})

(tick) (same meaning)

foo a1

foo(a1)

(tick) (same meaning)

foo a1()

foo(a1())

(tick) (same meaning)

foo a1 {c}

foo(a1({c}))

(tick) (same meaning)

foo a1 a2

(error)

(error)

foo a1() a2

(error)

(error)

foo a1 a2()

(error)

(error)

foo a1 a2 {c}

(error)

(error)

foo a1 {c} a2

(error)

(error)

foo a1 {c} a2 {c}

(error)

(error)

foo a1 a2 a3

foo(a1).a2(a3)

(error)

foo a1() a2 a3()

foo(a1()).a2(a3())

(error)

foo a1 a2() a3

(error)

(error)

foo a1 a2 a3 {c}

foo(a1).a2(a3({c}))

(error)

foo a1 a2 a3 a4

(error)

(error)

foo a1 a2 a3 a4 {c}

(error)

(error)

foo a1 a2 a3 a4 a5

foo(a1).a2(a3).a4(a5)

(error)

foo a1() a2 a3() a4 a5()

foo(a1()).a2(a3()).a4(a5())

(error)

foo a1 a2 a3 a4 a5 {c}

foo(a1).a2(a3).a4(a5({c})

(error)

I think that table shows enough to recognize the pattern. The attached block has a special role as it does not count as argument on its own directly. Instead the block is always bound to the identifier before and makes a method call. that itself is no command expression, but a normal method call expression. As can be seen too, this syntax nicely extends the existing Groovy syntax. Of course this also means, it will not be possible to omit commas if multiple arguments are used. A case that is not supported today anyway. For a DSL that is not really a problem though.

Example: A DSL for SQL

SELECT "column_name"
FROM "table_name"
WHERE "column_name" IN ('value1', 'value2', ...)

In current Groovy this could maybe expressed by

With this new command dsl you could also do

It should be noticed, that both cases have quite different semantics. In the second case the writer saves a lot of commas, but of course not all of them. Also the lack of any kind of operator like the comma makes it diifivult to span the DSL across multiple lines. A more extended example would be

SELECT COUNT("column_name")
FROM "table_name"

To express this in map style is a bit difficult, because of where to place count... a possible version is mabye

Differences to Scala

For historic reasons

println foo

has to be supported. This seems to not to be a valid version in Scala, since that would be interpreted as

and not as

. On the other hand

is interpreted as

in Scala and is invalid in current Groovy as well as after this proposal. So it could be stated, that this proposal is less object oriented then Scala, because the DSL usually starts with the method, not the object. On the other hand it is possible to write

So the Groovy notation would be a bit more verbose, but not much.

References

Mailing-list discussions

JIRA issues

  • No labels