On 06/03/2013, at 10:35 PM, Adam Murdoch <[email protected]> wrote:
> > 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. This is how the spec stands as is. Though it doesn't not yet say anything about the convention mapping case. -- Luke Daley Principal Engineer, Gradleware http://gradleware.com Join me at the Gradle Summit 2013, June 13th and 14th in Santa Clara, CA: http://www.gradlesummit.com --------------------------------------------------------------------- To unsubscribe from this list, please visit: http://xircles.codehaus.org/manage_email
