Hi,

At the moment, you can add properties to projects and tasks (and dependencies, 
source sets, and a few other things) dynamically, simply by assigning a value 
for the property:

someProp = 'value'
assert project.hasProperty('someProp')

jar.someProp = 'value'
assert jar.hasProperty('someProp')

This is all nice and convenient. However, it also causes some problems.  Here 
are some examples:

A typo in a property name:

jar {
   basename = 'someValue' // should be baseName
}

This adds a new property 'basename' instead of setting the value of 'baseName'. 
Instead, it probably should give you an error (and suggest that you try 
'baseName' instead).

Another problem is when you use convention properties before you apply the 
corresponding plugin:

sourceCompatibility = 1.6
apply plugin: 'java'

In this case, we end up with 2 properties called 'sourceCompatibility', each of 
which is used in different places. This, of course, can be extremely confusing.

To me, this implicit definition of properties is a nasty source of confusion, 
even to those who know Gradle well. I keep getting bitten by it, even now.

So, I'd like to get rid of it, and require instead that dynamic properties are 
declared explicitly.

One question is how this should look. We already have one way to extend an 
object, using the convention object mechanism. This works for both projects and 
tasks:

class MyConfigBean {
    String someProp
    List<File> someOtherProp = []
    File someFile() { .... } 
}

convention.plugins.myproperties = new MyConfigBean()

// The properties and methods of MyConfigBean are mixed in as properties of the 
project
someOtherProp << someFile()
println someProp

This is kind of interesting as a way to declare dynamic properties, for a few 
reasons:

* Plugins and build scripts would use the same mechanism
* Bean properties can be annotated with all kinds of meta-data, such as 
validation constraints, or mappings to command-line options.
* Bean properties can have javadoc attached, so that build documentation can be 
generated.
* It allows both properties and methods to be defined.
* It works well for all types of objects which need to be extended.
* It could provide namespacing, as you could group related properties and 
methods into separate classes.

The syntax is a little awkward, but might be good enough. 

But perhaps it would be good to add some kind of convenience methods for 
declaring properties.

One option, is to use a block to declare properties:

properties {
    String someProp = 'default-value'
    def otherProp
}

jar {
    properties { def customProp = 7 }
}

Another option, which really only works for extending a project, is to use the 
local variable definitions in the script:

String someProp = 'default-value'
def otherProp

assert project.hasProperty('someProp')

We could tackle this in two steps: first, make it easy to declare properties 
and deprecate (and warn about) the use of undeclared properties. And later, 
remove the ability to use undeclared properties.

Thoughts?


--
Adam Murdoch
Gradle Developer
http://www.gradle.org
CTO, Gradle Inc. - Gradle Training, Support, Consulting
http://www.gradle.biz

Reply via email to