You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@groovy.apache.org by bo zhang <zh...@gmail.com> on 2017/04/13 13:56:31 UTC

How to determine the equality of two closures?

Hello everybody,

I just have encountered a problem thus need your help. I want to treat the
following closures as "equivalent":

Clousure c1={
"This is a closure"
}

Clousure c2={
"This is a closure"
}

assert closureEqual(c1,c2)

Apparently, even though all fields and methods (the internal bytecode) are
equal, c1 and c2 are still different classes (xxx_closure$1 and
xxx_closure$2). AFAIK, everything but name in these two classes are equal.

Is there any possibilities to achieve my goal? Thank you very much.

Re: How to determine the equality of two closures?

Posted by bo zhang <zh...@gmail.com>.
Yes, Jochen, you're right, I came up with the possibility you mentioned as
well. It's not a good idea. Thanks.

And thank you very much for your solution, Jason, that's brilliant.

2017-04-13 23:47 GMT+08:00 Jochen Theodorou <bl...@gmx.org>:

>
>
> On 13.04.2017 16:22, bo zhang wrote:
>
>> Thanks for your reply.
>>
>> Actually, I'm writing a Gradle plugin in which I want to apply Gradle's
>> up-to-date check
>> <https://docs.gradle.org/current/userguide/more_about_tasks.
>> html#sec:up_to_date_checks>
>> and treated some closures as task input. That is to say, if a
>> user-defined closure in build.gradle doesn't change between two builds,
>> I can consider the task as "up-to-date" and skip them.
>>
>> For example, a user writes a configuration block in build.gradle:
>>
>> ...
>> someConfiguration {
>>      "That is my closure"
>> }
>> ...
>>
>> As long as that closure doesn't change, the task depending on it should
>> be considered as "up-to-date".
>>
>
> yes... I am wondering if the assumption is ok though...
>
> someConfiguration {
>   compile.transitive = project.hasProperty("transitiveCompile")
> }
>
> Even if the Closure itself has always the same class, it may at any point
> produce different effects. Your assumption works only based on no side
> effects.
>
> bye Jochen
>

Re: How to determine the equality of two closures?

Posted by Jochen Theodorou <bl...@gmx.org>.

On 13.04.2017 16:22, bo zhang wrote:
> Thanks for your reply.
>
> Actually, I'm writing a Gradle plugin in which I want to apply Gradle's
> up-to-date check
> <https://docs.gradle.org/current/userguide/more_about_tasks.html#sec:up_to_date_checks>
> and treated some closures as task input. That is to say, if a
> user-defined closure in build.gradle doesn't change between two builds,
> I can consider the task as "up-to-date" and skip them.
>
> For example, a user writes a configuration block in build.gradle:
>
> ...
> someConfiguration {
>      "That is my closure"
> }
> ...
>
> As long as that closure doesn't change, the task depending on it should
> be considered as "up-to-date".

yes... I am wondering if the assumption is ok though...

someConfiguration {
   compile.transitive = project.hasProperty("transitiveCompile")
}

Even if the Closure itself has always the same class, it may at any 
point produce different effects. Your assumption works only based on no 
side effects.

bye Jochen

Re: How to determine the equality of two closures?

Posted by bo zhang <zh...@gmail.com>.
Thanks for your reply.

Actually, I'm writing a Gradle plugin in which I want to apply Gradle's
up-to-date check
<https://docs.gradle.org/current/userguide/more_about_tasks.html#sec:up_to_date_checks>
and treated some closures as task input. That is to say, if a user-defined
closure in build.gradle doesn't change between two builds, I can consider
the task as "up-to-date" and skip them.

For example, a user writes a configuration block in build.gradle:

...
someConfiguration {
     "That is my closure"
}
...

As long as that closure doesn't change, the task depending on it should be
considered as "up-to-date".

I hope I have made myself understood.


2017-04-13 22:07 GMT+08:00 Jochen Theodorou <bl...@gmx.org>:

>
>
> On 13.04.2017 15:56, bo zhang wrote:
>
>> Hello everybody,
>>
>> I just have encountered a problem thus need your help. I want to treat
>> the following closures as "equivalent":
>>
>> Clousure c1={
>> "This is a closure"
>> }
>>
>> Clousure c2={
>> "This is a closure"
>> }
>>
>> assert closureEqual(c1,c2)
>>
>
> may I ask how you want to use that? I was thinking about this in the past,
> but I failed to create a reasonable scenario in which I would need this.
>
> Apparently, even though all fields and methods (the internal bytecode)
>> are equal, c1 and c2 are still different classes (xxx_closure$1 and
>> xxx_closure$2). AFAIK, everything but name in these two classes are equal.
>>
>> Is there any possibilities to achieve my goal? Thank you very much.
>>
>
> right now, not no.
>
> bye Jochen
>

Re: How to determine the equality of two closures?

Posted by Jochen Theodorou <bl...@gmx.org>.
On 13.04.2017 18:03, Winnebeck, Jason wrote:
> That's cool, so that defines lastValue as a field of the actual closure class?

yes, you can do it with a combination of additional parameter and curry 
as well of course.

> The issue with using a field is the watch not using the map would fail when performing multiple watches:
>
> person.watch({skills}....
> person.watch({name}...

ok, that changes things

bye Jochen

RE: How to determine the equality of two closures?

Posted by "Winnebeck, Jason" <Ja...@windstream.com>.
That's cool, so that defines lastValue as a field of the actual closure class?

The issue with using a field is the watch not using the map would fail when performing multiple watches:

person.watch({skills}....
person.watch({name}...

In those two values, the lastValue field would confuse the state between the {skills} watch and the {name} watch. Also I didn't want to complicate the example but in the real implementation the watch is a utility class shared between many objects and classes and not a closure so my watch state map key is the watched instance + watch closure class and the map is the field of a real class. In real a scripting DSL example I would have probably added watch to Object metaclass which delegates to a WatchManager implementation.

Jason

-----Original Message-----
From: Jochen Theodorou [mailto:blackdrag@gmx.org] 
Sent: Thursday, April 13, 2017 11:39 AM
To: users@groovy.apache.org
Subject: Re: How to determine the equality of two closures?

Jason, have you ever trief something like this?

>  person.watch = { cond, action, elseAction ->
>    def value = person.with(cond).clone()
>    @groovy.transform.Field lastValue
>    if (value != lastValue) action(lastValue, value) else elseAction()
>    lastValue = value
>  }

bye Jochen

This email message and any attachments are for the sole use of the intended recipient(s). Any unauthorized review, use, disclosure or distribution is prohibited. If you are not the intended recipient, please contact the sender by reply email and destroy all copies of the original message and any attachments.

Re: How to determine the equality of two closures?

Posted by Jochen Theodorou <bl...@gmx.org>.
Jason, have you ever trief something like this?

>  person.watch = { cond, action, elseAction ->
>    def value = person.with(cond).clone()
>    @groovy.transform.Field lastValue
>    if (value != lastValue) action(lastValue, value) else elseAction()
>    lastValue = value
>  }

bye Jochen

RE: How to determine the equality of two closures?

Posted by "Winnebeck, Jason" <Ja...@windstream.com>.
I wrote my reply before I saw your use case of Gradle build scripts. My technique probably won’t work there because I assume the build script is re-compiled between each run so would give a different class object, but I don’t know how the up-to-date check works…

Here is what I did. In this example each time runScript runs and calls watch, despite the “cond” closure being different instances each time, they are all of the same class so that’s how I know it’s the same call site. However, if I made another function “runScript2” even if it had identical code, the closures would not compare “equal” for my use case (which in my watch case, is exactly what I’d want anyway).

def person = [name: 'Jason', skills: ['Groovy']]

def watches = [:]

person.watch = { cond, action, elseAction ->
def value = person.with(cond).clone()
def lastValue = watches[cond.class]
if (value != lastValue) action(lastValue, value) else elseAction()
watches[cond.class] = value
}

void runScript(def p) {
p.watch({skills},
         {o, n -> println "Skills are now $n"},
         {println "Skills have not changed"})
}

runScript(person)
runScript(person)
person.skills << 'Java'
runScript(person)

Output:
Skills are now [Groovy]
Skills have not changed
Skills are now [Groovy, Java]

From: bo zhang [mailto:zhangbodut@gmail.com]
Sent: Thursday, April 13, 2017 11:05 AM
To: users@groovy.apache.org
Subject: Re: How to determine the equality of two closures?

Sorry Jason, but I don't quite understand, would you please explain it more detailedly? Thanks a lot.

2017-04-13 22:28 GMT+08:00 Winnebeck, Jason <Ja...@windstream.com>>:
Jochen, I had a use case that was very close to this that may or may not inspire bo zhang for an alternative solution to closure equality. I had to rely on the Groovy implementation detail that each Closure instance created from an expression at a line of code had the same class (I did put this assumption in a unit test in my project so I'd know if that broke). That let me create a DSL like AngularJS watches:

def person = [name: 'Jason', skills: ['groovy']]

person.watch( {skills} ) {oldVal, newVal ->
  println "person.$name's skills changed from $oldVal to $newVal"
}

To implement the watch method, I have a map of Class to watcher's state. So when the person.watch expression is run again, the state is preserved from the last run, using the closure's class as the key to recover the state. In this example, two watches with the same closure definition would have two states. But if I put the two watch into a function, the closures would share the same line of code and compare as "equal"

Jason

-----Original Message-----
From: Jochen Theodorou [mailto:blackdrag@gmx.org<ma...@gmx.org>]
Sent: Thursday, April 13, 2017 10:08 AM
To: users@groovy.apache.org<ma...@groovy.apache.org>
Subject: Re: How to determine the equality of two closures?



On 13.04.2017 15:56, bo zhang wrote:
> Hello everybody,
>
> I just have encountered a problem thus need your help. I want to treat
> the following closures as "equivalent":
>
> Clousure c1={
> "This is a closure"
> }
>
> Clousure c2={
> "This is a closure"
> }
>
> assert closureEqual(c1,c2)

may I ask how you want to use that? I was thinking about this in the past, but I failed to create a reasonable scenario in which I would need this.

> Apparently, even though all fields and methods (the internal bytecode)
> are equal, c1 and c2 are still different classes (xxx_closure$1 and
> xxx_closure$2). AFAIK, everything but name in these two classes are equal.
>
> Is there any possibilities to achieve my goal? Thank you very much.

right now, not no.

bye Jochen
This email message and any attachments are for the sole use of the intended recipient(s). Any unauthorized review, use, disclosure or distribution is prohibited. If you are not the intended recipient, please contact the sender by reply email and destroy all copies of the original message and any attachments.


Re: How to determine the equality of two closures?

Posted by bo zhang <zh...@gmail.com>.
Sorry Jason, but I don't quite understand, would you please explain it
more detailedly? Thanks a lot.

2017-04-13 22:28 GMT+08:00 Winnebeck, Jason <Ja...@windstream.com>
:

> Jochen, I had a use case that was very close to this that may or may not
> inspire bo zhang for an alternative solution to closure equality. I had to
> rely on the Groovy implementation detail that each Closure instance created
> from an expression at a line of code had the same class (I did put this
> assumption in a unit test in my project so I'd know if that broke). That
> let me create a DSL like AngularJS watches:
>
> def person = [name: 'Jason', skills: ['groovy']]
>
> person.watch( {skills} ) {oldVal, newVal ->
>   println "person.$name's skills changed from $oldVal to $newVal"
> }
>
> To implement the watch method, I have a map of Class to watcher's state.
> So when the person.watch expression is run again, the state is preserved
> from the last run, using the closure's class as the key to recover the
> state. In this example, two watches with the same closure definition would
> have two states. But if I put the two watch into a function, the closures
> would share the same line of code and compare as "equal"
>
> Jason
>
> -----Original Message-----
> From: Jochen Theodorou [mailto:blackdrag@gmx.org]
> Sent: Thursday, April 13, 2017 10:08 AM
> To: users@groovy.apache.org
> Subject: Re: How to determine the equality of two closures?
>
>
>
> On 13.04.2017 15:56, bo zhang wrote:
> > Hello everybody,
> >
> > I just have encountered a problem thus need your help. I want to treat
> > the following closures as "equivalent":
> >
> > Clousure c1={
> > "This is a closure"
> > }
> >
> > Clousure c2={
> > "This is a closure"
> > }
> >
> > assert closureEqual(c1,c2)
>
> may I ask how you want to use that? I was thinking about this in the past,
> but I failed to create a reasonable scenario in which I would need this.
>
> > Apparently, even though all fields and methods (the internal bytecode)
> > are equal, c1 and c2 are still different classes (xxx_closure$1 and
> > xxx_closure$2). AFAIK, everything but name in these two classes are
> equal.
> >
> > Is there any possibilities to achieve my goal? Thank you very much.
>
> right now, not no.
>
> bye Jochen
>
> This email message and any attachments are for the sole use of the
> intended recipient(s). Any unauthorized review, use, disclosure or
> distribution is prohibited. If you are not the intended recipient, please
> contact the sender by reply email and destroy all copies of the original
> message and any attachments.
>

RE: How to determine the equality of two closures?

Posted by "Winnebeck, Jason" <Ja...@windstream.com>.
Jochen, I had a use case that was very close to this that may or may not inspire bo zhang for an alternative solution to closure equality. I had to rely on the Groovy implementation detail that each Closure instance created from an expression at a line of code had the same class (I did put this assumption in a unit test in my project so I'd know if that broke). That let me create a DSL like AngularJS watches:

def person = [name: 'Jason', skills: ['groovy']]

person.watch( {skills} ) {oldVal, newVal ->
  println "person.$name's skills changed from $oldVal to $newVal"
}

To implement the watch method, I have a map of Class to watcher's state. So when the person.watch expression is run again, the state is preserved from the last run, using the closure's class as the key to recover the state. In this example, two watches with the same closure definition would have two states. But if I put the two watch into a function, the closures would share the same line of code and compare as "equal"

Jason

-----Original Message-----
From: Jochen Theodorou [mailto:blackdrag@gmx.org] 
Sent: Thursday, April 13, 2017 10:08 AM
To: users@groovy.apache.org
Subject: Re: How to determine the equality of two closures?



On 13.04.2017 15:56, bo zhang wrote:
> Hello everybody,
>
> I just have encountered a problem thus need your help. I want to treat 
> the following closures as "equivalent":
>
> Clousure c1={
> "This is a closure"
> }
>
> Clousure c2={
> "This is a closure"
> }
>
> assert closureEqual(c1,c2)

may I ask how you want to use that? I was thinking about this in the past, but I failed to create a reasonable scenario in which I would need this.

> Apparently, even though all fields and methods (the internal bytecode) 
> are equal, c1 and c2 are still different classes (xxx_closure$1 and 
> xxx_closure$2). AFAIK, everything but name in these two classes are equal.
>
> Is there any possibilities to achieve my goal? Thank you very much.

right now, not no.

bye Jochen

This email message and any attachments are for the sole use of the intended recipient(s). Any unauthorized review, use, disclosure or distribution is prohibited. If you are not the intended recipient, please contact the sender by reply email and destroy all copies of the original message and any attachments.

Re: How to determine the equality of two closures?

Posted by Jochen Theodorou <bl...@gmx.org>.

On 13.04.2017 15:56, bo zhang wrote:
> Hello everybody,
>
> I just have encountered a problem thus need your help. I want to treat
> the following closures as "equivalent":
>
> Clousure c1={
> "This is a closure"
> }
>
> Clousure c2={
> "This is a closure"
> }
>
> assert closureEqual(c1,c2)

may I ask how you want to use that? I was thinking about this in the 
past, but I failed to create a reasonable scenario in which I would need 
this.

> Apparently, even though all fields and methods (the internal bytecode)
> are equal, c1 and c2 are still different classes (xxx_closure$1 and
> xxx_closure$2). AFAIK, everything but name in these two classes are equal.
>
> Is there any possibilities to achieve my goal? Thank you very much.

right now, not no.

bye Jochen