Closure scope and references

View: New views
13 Messages — Rating Filter:   Alert me  

Closure scope and references

by Russ Abbott :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

As a relative newcomer to Groovy, perhaps this is a well-known issue. But I'm confused about the following. When I run this code (which never calls genClosure():
Closure genClosure (var1) {
Closure closure = {caller, var2 ->
assert caller.scriptVar.is(scriptVar)
assert !(caller.scriptVar.is(var1))
assert !(caller.scriptVar.is(var2))
caller.scriptVar++
var1++
var2++
" caller.scriptVar: ${caller.scriptVar};" +
" scriptVar1: $var1; scriptVar2: $var2;"
} // endClosure
return closure // from genClosure
} // end genClosure
 
Closure closure = {caller, var2 ->
assert caller.scriptVar.is(scriptVar)
assert !(caller.scriptVar.is(var2))
caller.scriptVar++
scriptVar++
var2++
" caller.scriptVar: ${caller.scriptVar};" +
" scriptVar1: $scriptVar; scriptVar2: $var2;"
} // endClosure
 
 
this.scriptVar = 0
def scriptVar = 10
 
// closure = genClosure(scriptVar)
 
println closure(this, scriptVar)
println closure(this, scriptVar)
println closure(this, scriptVar)
println closure(this, scriptVar)
println "\n this.scriptVar: ${this.scriptVar}; scriptVar: $scriptVar; "

I get this output.

caller.scriptVar: 2; scriptVar1: 2; scriptVar2: 11;
caller.scriptVar: 4; scriptVar1: 4; scriptVar2: 11;
caller.scriptVar: 6; scriptVar1: 6; scriptVar2: 11;
caller.scriptVar: 8; scriptVar1: 8; scriptVar2: 11;
 
 this.scriptVar: 8; scriptVar: 10;

But when 

closure = genClosure(scriptVar)

is allowed to execute, this is the output.

 caller.scriptVar: 1; scriptVar1: 11; scriptVar2: 11;
caller.scriptVar: 2; scriptVar1: 12; scriptVar2: 11;
caller.scriptVar: 3; scriptVar1: 13; scriptVar2: 11;
caller.scriptVar: 4; scriptVar1: 14; scriptVar2: 11;
 
this.scriptVar: 4; scriptVar: 10;

Can someone explain to me the references? 
What are: this.scriptVar and scriptVar
Why do I get different results when generating the closure in these two different ways? In particular, what are the references of var1 and var2 in genClosure()?

Thanks.

-- Russ Abbott
_____________________________________________
Professor, Computer Science
California State University, Los Angeles
o Check out my blog at http://russabbott.blogspot.com/

Re: Closure scope and references

by Paul King :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Russ Abbott wrote:

> Hi,
>
> As a relative newcomer to Groovy, perhaps this is a well-known issue.
> But I'm confused about the following. When I run this code (which never
> calls genClosure():
>
> Closure genClosure (var1) {
>   Closure closure = {caller, var2 ->
>
>     assert caller.scriptVar.is(scriptVar)
>
>     assert !(caller.scriptVar.is(var1))
>
>     assert !(caller.scriptVar.is(var2))
>
>     caller.scriptVar++
>     var1++
>     var2++
>     " caller.scriptVar: ${caller.scriptVar};" +
>     " scriptVar1: $var1; scriptVar2: $var2;"
>
>   } // endClosure
>   return closure // from genClosure
>
> } // end genClosure  
>  
> Closure closure = {caller, var2 ->
>
>     assert caller.scriptVar.is(scriptVar)
>
>     assert !(caller.scriptVar.is(var2))
>
>   caller.scriptVar++
>   scriptVar++
>   var2++
>   " caller.scriptVar: ${caller.scriptVar};" +
>   " scriptVar1: $scriptVar; scriptVar2: $var2;"
>
> } // endClosure
>  
>  
> this.scriptVar = 0
>
> def scriptVar = 10
>  
> // closure = genClosure(scriptVar)
>  
> println closure(this, scriptVar)
>
> println closure(this, scriptVar)
> println closure(this, scriptVar)
>
> println closure(this, scriptVar)
> println "\n this.scriptVar: ${this.scriptVar}; scriptVar: $scriptVar; "
>
> I get this output.
>
> caller.scriptVar: 2; scriptVar1: 2; scriptVar2: 11;
> caller.scriptVar: 4; scriptVar1: 4; scriptVar2: 11;
> caller.scriptVar: 6; scriptVar1: 6; scriptVar2: 11;
> caller.scriptVar: 8; scriptVar1: 8; scriptVar2: 11;
>  
>
>  this.scriptVar: 8; scriptVar: 10;
>
> But when
>
> closure = genClosure(scriptVar)
>
> is allowed to execute, this is the output.
>
>  caller.scriptVar: 1; scriptVar1: 11; scriptVar2: 11;
>
>  caller.scriptVar: 2; scriptVar1: 12; scriptVar2: 11;
>
>  caller.scriptVar: 3; scriptVar1: 13; scriptVar2: 11;
>
>  caller.scriptVar: 4; scriptVar1: 14; scriptVar2: 11;
>
>  
>  this.scriptVar: 4; scriptVar: 10;
>
>
> Can someone explain to me the references?
> What are: this.scriptVar and scriptVar

'this.scriptVar' when used inside a script is the same as 'binding.scriptVar'.
It normally wouldn't be considered good practice to use this.scriptVar
and also define a scriptVar using 'def' (which gives a local variable)
in the same script.

If you are trying to associate this with a Java mental model of the
world, think of your script as being inside a Groovy-created public
static void main method. Variables defined using 'def' will be local
variables while there is also a class wide 'map' called binding which
this will point you to for non-local property access.

> Why do I get different results when generating the closure in these two
> different ways? In particular, what are the references of var1 and var2
> in genClosure()?

Being a closure like thing, Groovy's Closure's bind unbound variables
to the enclosing scope, so var1 will be bound to the method parameter
var1 at the time you called genClosure (even though that call is now
complete).

Perhaps this helps:

int x = 4
int y = 30
c = { a -> x++; println "${++a} ${++a}" }
c y       // => 31 32
c y       // => 31 32
println x // => 6
println y // => 30


> -- Russ Abbott
> _____________________________________________
> Professor, Computer Science
> California State University, Los Angeles
> o Check out my blog at http://russabbott.blogspot.com/


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Closure scope and references

by Russ Abbott :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

OK. I think I see what you're saying about parameters. But I'm still confused.  Let's take this version of your example.

class MyInt {
  def value
  def incr() { ++value  }
  String toString() {return value}
}
 
def x = new MyInt(value: 30)
def y = 40

void incr1(a) { println "${a.incr()}"  }
void incr2(a) { println "${++a}"  }

incr1 x          // => 31
incr2 y          // => 41

println "$x $y"  // => 31 40

This example does not use Closures at all. When y is passed to incr2, it appears to be passed by value. But since everything is an object, why isn't a pointer to y's value passed and incremented as in the case of x?


-- Russ Abbott
_____________________________________________
Professor, Computer Science
California State University, Los Angeles
o Check out my blog at http://russabbott.blogspot.com/

On Fri, Jul 4, 2008 at 3:33 PM, Paul King <paulk@...> wrote:
Russ Abbott wrote:
Hi,

As a relative newcomer to Groovy, perhaps this is a well-known issue. But I'm confused about the following. When I run this code (which never calls genClosure():

Closure genClosure (var1) {
 Closure closure = {caller, var2 ->

   assert caller.scriptVar.is(scriptVar)

   assert !(caller.scriptVar.is(var1))

   assert !(caller.scriptVar.is(var2))

   caller.scriptVar++
   var1++
   var2++
   " caller.scriptVar: ${caller.scriptVar};" +    " scriptVar1: $var1; scriptVar2: $var2;"

 } // endClosure
 return closure // from genClosure

} // end genClosure    Closure closure = {caller, var2 ->

   assert caller.scriptVar.is(scriptVar)

   assert !(caller.scriptVar.is(var2))

 caller.scriptVar++
 scriptVar++
 var2++
 " caller.scriptVar: ${caller.scriptVar};" +  " scriptVar1: $scriptVar; scriptVar2: $var2;"

} // endClosure
  this.scriptVar = 0

def scriptVar = 10
 // closure = genClosure(scriptVar)
 println closure(this, scriptVar)

println closure(this, scriptVar)
println closure(this, scriptVar)

println closure(this, scriptVar)
println "\n this.scriptVar: ${this.scriptVar}; scriptVar: $scriptVar; "

I get this output.

caller.scriptVar: 2; scriptVar1: 2; scriptVar2: 11;
caller.scriptVar: 4; scriptVar1: 4; scriptVar2: 11;
caller.scriptVar: 6; scriptVar1: 6; scriptVar2: 11;
caller.scriptVar: 8; scriptVar1: 8; scriptVar2: 11;
 
 this.scriptVar: 8; scriptVar: 10;

But when
closure = genClosure(scriptVar)

is allowed to execute, this is the output.

 caller.scriptVar: 1; scriptVar1: 11; scriptVar2: 11;

 caller.scriptVar: 2; scriptVar1: 12; scriptVar2: 11;

 caller.scriptVar: 3; scriptVar1: 13; scriptVar2: 11;

 caller.scriptVar: 4; scriptVar1: 14; scriptVar2: 11;

  this.scriptVar: 4; scriptVar: 10;


Can someone explain to me the references? What are: this.scriptVar and scriptVar

'this.scriptVar' when used inside a script is the same as 'binding.scriptVar'.
It normally wouldn't be considered good practice to use this.scriptVar
and also define a scriptVar using 'def' (which gives a local variable)
in the same script.

If you are trying to associate this with a Java mental model of the
world, think of your script as being inside a Groovy-created public
static void main method. Variables defined using 'def' will be local
variables while there is also a class wide 'map' called binding which
this will point you to for non-local property access.


Why do I get different results when generating the closure in these two different ways? In particular, what are the references of var1 and var2 in genClosure()?

Being a closure like thing, Groovy's Closure's bind unbound variables
to the enclosing scope, so var1 will be bound to the method parameter
var1 at the time you called genClosure (even though that call is now
complete).

Perhaps this helps:

int x = 4
int y = 30
c = { a -> x++; println "${++a} ${++a}" }
c y       // => 31 32
c y       // => 31 32
println x // => 6
println y // => 30



-- Russ Abbott
_____________________________________________
Professor, Computer Science
California State University, Los Angeles
o Check out my blog at http://russabbott.blogspot.com/


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

  http://xircles.codehaus.org/manage_email




Re: Closure scope and references

by Russ Abbott :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Here's another version that uses next() as the name of ++ as post-increment. Of the four cases, I understand only the last one. (Or did I make a mistake somewhere?)

class MyInt {
  def value
  def next() { value++;  }
  String toString() {return value}
}
 
def w = new MyInt(value: 20)
def x = new MyInt(value: 30)
def y = 40
def z = 50

void incr(a) { println(a++)  }

println(w++)      // => 21. Why not 20? Why isn't w incremented. (See last line.)
incr x              // => 31. Why not 30? But x is incremented. (See last line.)
incr y              // => 40. Why isn't y incremented? (See last line.)
println(z++)     // => 50. This is the only one that makes sense to me.

println "$w $x $y $z"  // => 20 31 40 51

-- Russ Abbott
_____________________________________________
Professor, Computer Science
California State University, Los Angeles
o Check out my blog at http://russabbott.blogspot.com/

On Fri, Jul 4, 2008 at 7:06 PM, Russ Abbott <russ.abbott@...> wrote:
OK. I think I see what you're saying about parameters. But I'm still confused.  Let's take this version of your example.

class MyInt {
  def value
  def incr() { ++value  }
  String toString() {return value}
}
 
def x = new MyInt(value: 30)
def y = 40

void incr1(a) { println "${a.incr()}"  }
void incr2(a) { println "${++a}"  }

incr1 x          // => 31
incr2 y          // => 41

println "$x $y"  // => 31 40

This example does not use Closures at all. When y is passed to incr2, it appears to be passed by value. But since everything is an object, why isn't a pointer to y's value passed and incremented as in the case of x?



-- Russ Abbott
_____________________________________________
Professor, Computer Science
California State University, Los Angeles
o Check out my blog at http://russabbott.blogspot.com/

On Fri, Jul 4, 2008 at 3:33 PM, Paul King <paulk@...> wrote:
Russ Abbott wrote:
Hi,

As a relative newcomer to Groovy, perhaps this is a well-known issue. But I'm confused about the following. When I run this code (which never calls genClosure():

Closure genClosure (var1) {
 Closure closure = {caller, var2 ->

   assert caller.scriptVar.is(scriptVar)

   assert !(caller.scriptVar.is(var1))

   assert !(caller.scriptVar.is(var2))

   caller.scriptVar++
   var1++
   var2++
   " caller.scriptVar: ${caller.scriptVar};" +    " scriptVar1: $var1; scriptVar2: $var2;"

 } // endClosure
 return closure // from genClosure

} // end genClosure    Closure closure = {caller, var2 ->

   assert caller.scriptVar.is(scriptVar)

   assert !(caller.scriptVar.is(var2))

 caller.scriptVar++
 scriptVar++
 var2++
 " caller.scriptVar: ${caller.scriptVar};" +  " scriptVar1: $scriptVar; scriptVar2: $var2;"

} // endClosure
  this.scriptVar = 0

def scriptVar = 10
 // closure = genClosure(scriptVar)
 println closure(this, scriptVar)

println closure(this, scriptVar)
println closure(this, scriptVar)

println closure(this, scriptVar)
println "\n this.scriptVar: ${this.scriptVar}; scriptVar: $scriptVar; "

I get this output.

caller.scriptVar: 2; scriptVar1: 2; scriptVar2: 11;
caller.scriptVar: 4; scriptVar1: 4; scriptVar2: 11;
caller.scriptVar: 6; scriptVar1: 6; scriptVar2: 11;
caller.scriptVar: 8; scriptVar1: 8; scriptVar2: 11;
 
 this.scriptVar: 8; scriptVar: 10;

But when
closure = genClosure(scriptVar)

is allowed to execute, this is the output.

 caller.scriptVar: 1; scriptVar1: 11; scriptVar2: 11;

 caller.scriptVar: 2; scriptVar1: 12; scriptVar2: 11;

 caller.scriptVar: 3; scriptVar1: 13; scriptVar2: 11;

 caller.scriptVar: 4; scriptVar1: 14; scriptVar2: 11;

  this.scriptVar: 4; scriptVar: 10;


Can someone explain to me the references? What are: this.scriptVar and scriptVar

'this.scriptVar' when used inside a script is the same as 'binding.scriptVar'.
It normally wouldn't be considered good practice to use this.scriptVar
and also define a scriptVar using 'def' (which gives a local variable)
in the same script.

If you are trying to associate this with a Java mental model of the
world, think of your script as being inside a Groovy-created public
static void main method. Variables defined using 'def' will be local
variables while there is also a class wide 'map' called binding which
this will point you to for non-local property access.


Why do I get different results when generating the closure in these two different ways? In particular, what are the references of var1 and var2 in genClosure()?

Being a closure like thing, Groovy's Closure's bind unbound variables
to the enclosing scope, so var1 will be bound to the method parameter
var1 at the time you called genClosure (even though that call is now
complete).

Perhaps this helps:

int x = 4
int y = 30
c = { a -> x++; println "${++a} ${++a}" }
c y       // => 31 32
c y       // => 31 32
println x // => 6
println y // => 30



-- Russ Abbott
_____________________________________________
Professor, Computer Science
California State University, Los Angeles
o Check out my blog at http://russabbott.blogspot.com/


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

  http://xircles.codehaus.org/manage_email





Re: Closure scope and references

by Paul King :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


If I may simplify your example a little further, consider this:

class MyInt {
  def value
  def incr() { ++value  }
  String toString() {return value}
}
 
def x = new MyInt(value: 30)
def y = 40

void incr1(a) { println "${a.incr()}"  }
void incr2(a) { println "${a.next()}"  }

incr1 x          // => 31
incr2 y          // => 41

println "$x $y"  // => 31 40

a.incr() is an operation which changes the original (and happens
to also return the changed value).

a.next() returns a new object (recall that Integer's are designed
to be immutable as far as the Java world is concerned)

Now, changing to ++a, that is just a shorthand for a = a.next()
So, the 'pointer' a which originally points to y in your example
will point to a new Integer after ++a and of course Y is unchanged.

Some languages like Ruby make it easier to determine which methods
update the original vs return a new thing, e.g. sort vs sort! but
at the moment Groovy doesn't follow that because Java has never had
it. Perhaps we should consider that style a little more as it might
make some things clearer - though if you are using ++ you are striving
for brevity over clarity, so perhaps there is not much we can do there.

Paul.

Russ Abbott wrote:

> OK. I think I see what you're saying about parameters. But I'm still
> confused.  Let's take this version of your example.
>
> class MyInt {
>   def value
>   def incr() { ++value  }
>   String toString() {return value}
> }
>  
> def x = new MyInt(value: 30)
> def y = 40
>
> void incr1(a) { println "${a.incr()}"  }
> void incr2(a) { println "${++a}"  }
>
> incr1 x          // => 31
> incr2 y          // => 41
>
> println "$x $y"  // => 31 40
>
> This example does not use Closures at all. When y is passed to incr2, it
> appears to be passed by value. But since everything is an object, why
> isn't a pointer to y's value passed and incremented as in the case of x?
>
>
> -- Russ Abbott
> _____________________________________________
> Professor, Computer Science
> California State University, Los Angeles
> o Check out my blog at http://russabbott.blogspot.com/
>
> On Fri, Jul 4, 2008 at 3:33 PM, Paul King <paulk@...
> <mailto:paulk@...>> wrote:
>
>     Russ Abbott wrote:
>
>         Hi,
>
>         As a relative newcomer to Groovy, perhaps this is a well-known
>         issue. But I'm confused about the following. When I run this
>         code (which never calls genClosure():
>
>         Closure genClosure (var1) {
>          Closure closure = {caller, var2 ->
>
>            assert caller.scriptVar.is
>         <http://caller.scriptVar.is>(scriptVar)
>
>            assert !(caller.scriptVar.is <http://caller.scriptVar.is>(var1))
>
>            assert !(caller.scriptVar.is <http://caller.scriptVar.is>(var2))
>
>            caller.scriptVar++
>            var1++
>            var2++
>            " caller.scriptVar: ${caller.scriptVar};" +    " scriptVar1:
>         $var1; scriptVar2: $var2;"
>
>          } // endClosure
>          return closure // from genClosure
>
>         } // end genClosure    Closure closure = {caller, var2 ->
>
>            assert caller.scriptVar.is
>         <http://caller.scriptVar.is>(scriptVar)
>
>            assert !(caller.scriptVar.is <http://caller.scriptVar.is>(var2))
>
>          caller.scriptVar++
>          scriptVar++
>          var2++
>          " caller.scriptVar: ${caller.scriptVar};" +  " scriptVar1:
>         $scriptVar; scriptVar2: $var2;"
>
>         } // endClosure
>           this.scriptVar = 0
>
>         def scriptVar = 10
>          // closure = genClosure(scriptVar)
>          println closure(this, scriptVar)
>
>         println closure(this, scriptVar)
>         println closure(this, scriptVar)
>
>         println closure(this, scriptVar)
>         println "\n this.scriptVar: ${this.scriptVar}; scriptVar:
>         $scriptVar; "
>
>         I get this output.
>
>         caller.scriptVar: 2; scriptVar1: 2; scriptVar2: 11;
>         caller.scriptVar: 4; scriptVar1: 4; scriptVar2: 11;
>         caller.scriptVar: 6; scriptVar1: 6; scriptVar2: 11;
>         caller.scriptVar: 8; scriptVar1: 8; scriptVar2: 11;
>          
>          this.scriptVar: 8; scriptVar: 10;
>
>         But when
>         closure = genClosure(scriptVar)
>
>         is allowed to execute, this is the output.
>
>          caller.scriptVar: 1; scriptVar1: 11; scriptVar2: 11;
>
>          caller.scriptVar: 2; scriptVar1: 12; scriptVar2: 11;
>
>          caller.scriptVar: 3; scriptVar1: 13; scriptVar2: 11;
>
>          caller.scriptVar: 4; scriptVar1: 14; scriptVar2: 11;
>
>           this.scriptVar: 4; scriptVar: 10;
>
>
>         Can someone explain to me the references? What are:
>         this.scriptVar and scriptVar
>
>
>     'this.scriptVar' when used inside a script is the same as
>     'binding.scriptVar'.
>     It normally wouldn't be considered good practice to use this.scriptVar
>     and also define a scriptVar using 'def' (which gives a local variable)
>     in the same script.
>
>     If you are trying to associate this with a Java mental model of the
>     world, think of your script as being inside a Groovy-created public
>     static void main method. Variables defined using 'def' will be local
>     variables while there is also a class wide 'map' called binding which
>     this will point you to for non-local property access.
>
>
>         Why do I get different results when generating the closure in
>         these two different ways? In particular, what are the references
>         of var1 and var2 in genClosure()?
>
>
>     Being a closure like thing, Groovy's Closure's bind unbound variables
>     to the enclosing scope, so var1 will be bound to the method parameter
>     var1 at the time you called genClosure (even though that call is now
>     complete).
>
>     Perhaps this helps:
>
>     int x = 4
>     int y = 30
>     c = { a -> x++; println "${++a} ${++a}" }
>     c y       // => 31 32
>     c y       // => 31 32
>     println x // => 6
>     println y // => 30
>
>
>
>         -- Russ Abbott
>         _____________________________________________
>         Professor, Computer Science
>         California State University, Los Angeles
>         o Check out my blog at http://russabbott.blogspot.com/
>
>
>
>     ---------------------------------------------------------------------
>     To unsubscribe from this list, please visit:
>
>       http://xircles.codehaus.org/manage_email
>
>
>


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Closure scope and references

by Jim White :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Russ Abbott wrote:

> OK. I think I see what you're saying about parameters. But I'm still
> confused.  Let's take this version of your example.
>
> class MyInt {
>   def value
>   def incr() { ++value  }
>   String toString() {return value}
> }
>  
> def x = new MyInt(value: 30)
> def y = 40
>
> void incr1(a) { println "${a.incr()}"  }
> void incr2(a) { println "${++a}"  }
>
> incr1 x          // => 31
> incr2 y          // => 41
>
> println "$x $y"  // => 31 40
>
> This example does not use Closures at all. When y is passed to incr2, it
> appears to be passed by value. But since everything is an object, why
> isn't a pointer to y's value passed and incremented as in the case of x?

Because incr2 is effectively doing this:

void incr2(a) { a = a + 1; println a }

If you want ++ to work on MyInt, you need to define next():

class MyInt {
   def value
   def incr() { ++value  }
   Number next() { ++value }
   String toString() {return value}
}

def x = new MyInt(value: 30)
def y = 40
def z = new MyInt(value: 40)

void incr1(a) { println "${a.incr()}"  }
void incr2(a) { println "${++a}"  }

incr1 x          // => 31
incr2 y          // => 41
incr2 z          // => 41

println "$x $y $z"  // => 31 40 41

Jim


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Closure scope and references

by Russ Abbott :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Thanks for all your help. You're right that I was assuming that ++ changes the actual object rather than re-assigning the variable. That explains why it matters whether the ++ is done at the top level or in a method when the object is an Integer.

This seems to make it clear.

def a = 10
assert a++ == 10   // a++ is equivalent to: b = a; a = a.next; return b
assert a == 11

assert 10++ == 10   // Generates and discards 11.
assert 10.next() == 11

class MyInt {
   def value

   boolean equals(other) {other instanceof MyInt && other.value == value}

   // next() generates and returns a successor object. It doesn't change this one.
   def next() {return new MyInt(value: value + 1)}
}
 
def x = new MyInt(value: 30)

assert x++ == new MyInt(value: 30)   // x++ is equivalent to: b = x; x = x.next; return b
assert x ==  new MyInt(value: 31)

assert new MyInt(value:50)++ == new MyInt(value:50)   // Generates and discards new MyInt(value:51)
assert new MyInt(value:50).next() == new MyInt(value:51)

The basic lesson is that ++ is is intended to apply to variables and not to objects. When applied to an object a new successor object is created and essentially discarded. This makes ++ different from other operators.  Is that a fair way to look at it?

-- Russ

Re: Closure scope and references

by Paul King :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Russ Abbott wrote:

> Thanks for all your help. You're right that I was assuming that ++
> changes the actual object rather than re-assigning the variable. That
> explains why it matters whether the ++ is done at the top level or in a
> method when the object is an Integer.
>
> This seems to make it clear.
>
> def a = 10
> assert a++ == 10   // a++ is equivalent to: b = a; a = a.next; return b
> assert a == 11
>
> assert 10++ == 10   // Generates and discards 11.
> assert 10.next() == 11
>
> class MyInt {
>    def value
>
>    boolean equals(other) {other instanceof MyInt && other.value == value}
>
>    // next() generates and returns a successor object. It doesn't change
> this one.
>    def next() {return new MyInt(value: value + 1)}
> }
>  
> def x = new MyInt(value: 30)
>
> assert x++ == new MyInt(value: 30)   // x++ is equivalent to: b = x; x =
> x.next; return b
> assert x ==  new MyInt(value: 31)
>
> assert new MyInt(value:50)++ == new MyInt(value:50)   // Generates and
> discards new MyInt(value:51)
> assert new MyInt(value:50).next() == new MyInt(value:51)
>
> The basic lesson is that ++ is is intended to apply to variables and not
> to objects. When applied to an object a new successor object is created
> and essentially discarded. This makes ++ different from other
> operators.  Is that a fair way to look at it?

That is a fair way to look at the convention but you can also do
non-conventional behavior if you think you must have it:

class MyInt {
   def value
   boolean equals(other) {other.value == value}
   def next() {value++; return this}
}
 
def x = new MyInt(value: 30)
assert x++ == new MyInt(value: 31)
assert x == new MyInt(value: 31)

assert new MyInt(value:50)++ == new MyInt(value:50)   // Generates and discards new MyInt(value:51)
assert new MyInt(value:50).next() == new MyInt(value:51)

Cheers, Paul.


> -- Russ


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Closure scope and references

by Jochen Theodorou :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Russ Abbott schrieb:
[...]
> The basic lesson is that ++ is is intended to apply to variables and not
> to objects. When applied to an object a new successor object is created
> and essentially discarded. This makes ++ different from other
> operators.  Is that a fair way to look at it?

each operator can define if it modifies the object or not. Think of
<,>,==,!=. All of them do not modify the object, nor do they return
something that is equal to the original object.. they don't have to! <<
usually modifies the object, but all other operators usually create
something new. For example ~ will negate an object, but it will alo
create a new object without modifying the old one... if defined like it
is usually defined that is.

bye blackdrag

--
Jochen "blackdrag" Theodorou
The Groovy Project Tech Lead (http://groovy.codehaus.org)
http://blackdragsview.blogspot.com/
http://www.g2one.com/

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Closure scope and references

by Russ Abbott :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

The ++ operator changes the value of the variable to which it is applied. That is, it assigns a new value to the variable. None of the others do. That's what's confusing about it.  Furthermore, when applied directly to objects other operators return results that make sense. The "!" operator returns the negation of the object. The ++ operator doesn't do that as currently defined. (It shouldn't be allowed to be applied to objects at all.) In other words, ++ really is different from most operators and quite confusing in its differences.

-- Russ Abbott
_____________________________________________
Professor, Computer Science
California State University, Los Angeles
o Check out my blog at http://russabbott.blogspot.com/

On Tue, Jul 15, 2008 at 4:51 AM, Jochen Theodorou <blackdrag@...> wrote:
Russ Abbott schrieb:
[...]

The basic lesson is that ++ is is intended to apply to variables and not to objects. When applied to an object a new successor object is created and essentially discarded. This makes ++ different from other operators.  Is that a fair way to look at it?

each operator can define if it modifies the object or not. Think of <,>,==,!=. All of them do not modify the object, nor do they return something that is equal to the original object.. they don't have to! << usually modifies the object, but all other operators usually create something new. For example ~ will negate an object, but it will alo create a new object without modifying the old one... if defined like it is usually defined that is.

bye blackdrag

--
Jochen "blackdrag" Theodorou
The Groovy Project Tech Lead (http://groovy.codehaus.org)
http://blackdragsview.blogspot.com/
http://www.g2one.com/


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

  http://xircles.codehaus.org/manage_email




Re: Closure scope and references

by Jochen Theodorou :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Russ Abbott schrieb:
> The ++ operator changes the value of the /variable /to which it is
> applied. That is, it assigns a new value to the variable. None of the
> others do. That's what's confusing about it.  

there is of course also -- ;) Any +=, -=, <<=, >>= would also do the
assignment, only that in these cases you see that.

> Furthermore, when applied
> directly to objects other operators return results that make sense. The
> "!" operator returns the negation of the object. The ++ operator doesn't
> do that as currently defined. (It shouldn't be allowed to be applied to
> objects at all.) In other words, ++ really is different from most
> operators and quite confusing in its differences.

++ is mapped to the method call next(), it is also a unary operator.
These two make it different in the first place. Other operators are
usually binary and are mapped to other method calls. next() may or may
not be a method that modifies the current object instead of creating a
new one. If ++ would be a mutating operator, then the later assignment
would have no affect, and ++x would be the same as x++.

now.. what exactly is the problem with allowing 1++? Only because x=1++
is not the same as x=++1?

I still don't get what the confusion is

bye blackdrag

--
Jochen "blackdrag" Theodorou
The Groovy Project Tech Lead (http://groovy.codehaus.org)
http://blackdragsview.blogspot.com/
http://www.g2one.com/

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Closure scope and references

by Russ Abbott :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

My complaint about allowing 1++ is that ++ is intended to be used variables and not with objects. It simply makes no sense to apply to objects. As such it should be syntactically illegal.

-- Russ Abbott
_____________________________________________
Professor, Computer Science
California State University, Los Angeles
o Check out my blog at http://russabbott.blogspot.com/

On Mon, Jul 21, 2008 at 10:49 AM, Jochen Theodorou <blackdrag@...> wrote:
Russ Abbott schrieb:

The ++ operator changes the value of the /variable /to which it is applied. That is, it assigns a new value to the variable. None of the others do. That's what's confusing about it.  

there is of course also -- ;) Any +=, -=, <<=, >>= would also do the assignment, only that in these cases you see that.


Furthermore, when applied directly to objects other operators return results that make sense. The "!" operator returns the negation of the object. The ++ operator doesn't do that as currently defined. (It shouldn't be allowed to be applied to objects at all.) In other words, ++ really is different from most operators and quite confusing in its differences.

++ is mapped to the method call next(), it is also a unary operator. These two make it different in the first place. Other operators are usually binary and are mapped to other method calls. next() may or may not be a method that modifies the current object instead of creating a new one. If ++ would be a mutating operator, then the later assignment would have no affect, and ++x would be the same as x++.

now.. what exactly is the problem with allowing 1++? Only because x=1++ is not the same as x=++1?

I still don't get what the confusion is


bye blackdrag

--
Jochen "blackdrag" Theodorou
The Groovy Project Tech Lead (http://groovy.codehaus.org)
http://blackdragsview.blogspot.com/
http://www.g2one.com/

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

  http://xircles.codehaus.org/manage_email




Re: Closure scope and references

by Jochen Theodorou :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Russ Abbott schrieb:
> My complaint about allowing 1++ is that ++ is intended to be used
> variables and not with objects. It simply makes no sense to apply to
> objects. As such it should be syntactically illegal.

as I said, if there is a mutating next() method on the object, then it
could make sense. While we don't encourage this, we do not disallow it
for now either. So if it makes sense or not is depending on the point of
view... But I tend to disallow it too.

bye blackdrag
--
Jochen "blackdrag" Theodorou
The Groovy Project Tech Lead (http://groovy.codehaus.org)
http://blackdragsview.blogspot.com/
http://www.g2one.com/

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email