|
In the meeting, I wasn't quick enough in thinking. |
Topics to cover:
Groovy code may contain identifiers (aka 'names') with or without
qualifiers. Examples are:
qualified identifiers |
unqualified identifiers |
note |
|---|---|---|
this.prop |
prop |
problematic |
someObject.method() |
method() |
problematic |
|
def localVar; localVar |
new: statically resolved |
|
MyClass |
new: statically resolved |
The bold examples above are also called vanilla names.
They are problematic because one legally expects each vanilla name to be the
same as this.vanilla, which is currently not the case.
In code like
def builder = new MarkupBuilder()
builder.html{
body {
div { }
}
}
|
it is surprising that the body method call is resolved by builder although
this refers to its surrounding Closure.
|
When we say a name is resolved by an object, it is actually that object's metaclass that resolves that name. |
With the decision described in Paris Groovy Meeting Report the following changes
take place.
To make the handling of vanilla names inside closure less surprising with regard to implicit this.,
the following decision was taken.
|
Inside closures, |
This has two effects:
vanilla is the same as this.vanillathis can be used to refer to the declarer (sometimes called escaping the builder).Inside closures that work on builders, the surprising effect of name resolution remains that
vanilla is resolved by the builder, while this.vanilla is resolved by the declarer.
Note that this behaviour currently applies to all builders (not only markup): AntBuilder, NodeBuilder, SwingBuilder, and (Streaming)MarkupBuilder.
It also applies to subclasses of BuilderSupport that are in codebases out there.
Since builder's are made by usual Groovy means, any Groovy codebase may contain code that
applies the same method resolution trick that BuilderSupport implements, even for usages beyond 'building'.
Therefore, it is not only a 'builder' issue, it is a general issue of possibly surprising name resolution.
Proceeding with the status quo raises the following concerns (mostly contributed by James):
Concerns when going for a visual-clue-markup solution
I feel we can address these fully valid concerns in two ways:
Let's assume we have a keyword xxx which would demarcate the namespace for a builder
in the following way
def builder = new MarkupBuilder()
xxx (builder) { // new line and new indentation level :-(
html{ // this line even nicer than before :-)
body {
div { p '' }
}
}
}
// when used with logic
def builder = new MarkupBuilder()
xxx (builder) {
html{
body {
[1,2].each {
xxx(builder) { div { p '' } } // either namespace or
builder.div { builder.p ''} // qualify all
}
}
}
}
|
Beside using the xxx keyword as xxx(builder), we could also have it as *builder.xxx.
Here are some proposals for xxx:
xxx(builder){} |
builder.xxx {} |
note |
|---|---|---|
with(builder) |
builder.with |
with keyword already reserved |
identity(builder) |
builder.identity |
construct already known to Groovy users |
names(builder) |
builder.names |
reads nicely as verb or plural noun. But 'names' may be a too common variable name |
vanilla(builder) |
builder.vanilla |
sounds like icecream |
namespace(builder) |
builder.namespace |
for the XML-infected |
add here |
add here |
add here |
Builders are currently a library feature, not part of the language. I feel we should be careful with what we make part of the language.
Introducing additional tokens would make them part of the language, the above demarcation doesn't. It makes only the xxx part of the language.
Use of the xxx construct is actually left to the programmer, analogous to the decision whether he wants to use static or dynamic typing.
Even if we wanted, enforcing the construct wouldn't be possible. At any time, a programmer would be able to come up with a class like BuilderSupport and a MetaClass for it that does the trick.
So we essentially provide a mean that:
Created by Dierk König
On Sun Nov 27 16:24:52 CET 2005
Using TimTam