On 07/03/2013, at 6:26 AM, Luke Daley wrote:
> Resurrecting this as I have a story for it.
>
> On 04/02/2013, at 5:04 PM, Luke Daley <[email protected]> wrote:
>
>> Hi,
>>
>> I'm working on a spec for implicit file value coercion. This will likely
>> yield some more general stuff for implicit type coercion, but the focus is
>> for file values. There are a few tricky problems.
>>
>> In order to support “flexible input values” for files right now, you need to
>> do effectively this…
>>
>> class MyTask extends DefaultTask {
>>
>> Object someFile
>>
>> File getSomeFile() {
>> someFile == null : null : project.file(someFile)
>> }
>> }
>>
>> This allows (among other values) (1) …
>>
>> task myTask(type: MyTask) {
>> someFile "path/to/file"
>> }
>>
>> And (2):
>>
>> task myTask(type: MyTask) {
>> someFile { someLazilyEvaluatedValue }
>> }
>>
>> We want to avoid developers having to do this manually for a few reasons.
>> Developers should be able to just write the following and get the same
>> behaviour:
>>
>> class MyTask extends DefaultTask {
>> File someFile
>> }
>>
>> If we ignore #2 for the time being, we could do this by injecting a coercion
>> layer in the MOP. We would effectively intercept *every* method call, if
>> it's a coercible case then coerce the value and just call through to the
>> declared setter. That's actually quite a big change as it flips the
>> relationship around between the Groovy MOP and ours, but it's ultimately
>> doable I think.
>
> I was wrong here. We already route every method call through our MOP (of
> course) so this isn't a big deal.
>
>> #2 provides lazy evaluation because the closure gets stored and evaluated on
>> demand by project.file() in the getter. If we decide that this story
>> (implicit file value coercion) means supporting this usage, then we are
>> forced to answer some uncomfortable questions about laziness and what we
>> call convention mapping.
>>
>> Options:
>>
>> 1. Do not support deferring with this feature, all values are coerced
>> immediately.
>> 2. Do support deferring, ultimately meaning on-demand coercion
>>
>> I'm not sure how much of an option #1 actually is, given how widespread the
>> use of this feature is.
>>
>> If we go with #2, what do we do about the crossover with convention mapping?
>> How much of that needs to be considered for this story? if we completely
>> ignore it and add another layer, we'd now have two different out-of-object
>> places that object data is stored. It starts to look like we should look at
>> some convergence here. If so, that raises the question of whether we can
>> change any convention mapping API without a deprecation cycle (if it turns
>> out we need to).
>
> I think for now we can ignore #2 until we have a clearer answer on where we
> are going with this.
I want the coercion to be eager and for us to offer better ways to defer
configuration, at a coarser domain-object level rather than at the property
level. So:
myTask.someFile = someValue
is the same as
myTask.setSomeFile(myTask.project.file(someValue)).
The coercions will be available via a set of notation parsers (or whatever the
notation parsers turn into), and the convention mapping stuff will use the
parsers as well. So:
myTask.conventionMapping.someFile = { someValue }
will apply the conversion of someValue to File at the time that it needs to
provide the value.
--
Adam Murdoch
Gradle Co-founder
http://www.gradle.org
VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting
http://www.gradleware.com
Join us at the Gradle Summit 2013, June 13th and 14th in Santa Clara, CA:
http://www.gradlesummit.com