On Thu, Feb 10, 2011 at 4:10 AM, Adam Murdoch <[email protected]> wrote:

> 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.
>

Absolutely. I think this is pretty high priority.


>
> 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.
>

We should definitely rethink the syntax. The '.plugins' bit is really
confusing for our scenario here.


>
> 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 }
> }
>

We definitely should provide this convenience for the sake of readability.


>
> 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')
>

This is an interesting idea. But after thinking about it, I prefer the
properties block also for projects.

1.) It is a bit harder to keep in mind that the above adds a property to the
project object, and not just to the script. The properties block would make
this clearer I think.
2.) The properties block fits better to the Gradle way that you declare your
build in the script and do not program it.

I think there is a case for script variables which are not exposed by the
project object. Groovy does not make it easy to us. I see those scenarios:

1.) foo = 'bar '

In Groovy that creates a global variable for the script which can also be
used in the methods of the script.
In Gradle I think we should allow this notation only for setting existing
properties of the project object.

2.) String foo = 'bar'
In Groovy that creates a script variable that can't be used in the methods
of the script. Which is a bit of a pity (See
http://www.gradle.org/0.9.2/docs/userguide/potential_traps.html#sec:groovy_script_variables
)
In Gradle I think this should create a script variable which is not exposed
by the project. I'm wondering whether we should think about tweaking the
Groovy behaviour in regard to accessing it from a method.

I think script variable are fine for build scripts which you use to put low
level implementation details and which are then used by the main build
scripts.


>
> 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.
>

That would be fantastic and an important step towards customized DSL Doc and
IDE content assist.

Hans


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

Reply via email to