KingCode (43) [Avatar] Offline
#1
Hello Dierk,

Is it possible to implement an operator override with the use of the original implementation? I kept running into infinite recursion while trying to modify '+' below.

This may be convoluted, but it would seem to make sense when trying e.g. to reuse complex business rules in providing customized versions.

Any insight is greatly appreciated.

Thanks,
KC

/**
We are trying here to override the + Integer operator while using the overridden + within the implementation.

The example 'XtraOnePlusCategory(...)' categories's intent is to provide a "crooked addition" such that
x + y + 1 == x + y
where the LHS represents the overriden + and the RHS the traditional + operator
*/
// CATEGORY CLASSES DEFS -//

//---A --/
//Crooked addition, using the java Integer.plus(), with resulting stack overflow
class XtraOnePlusCategoryWithNaivePlus {
//Causes infinite recursion due to using +
static def plus( Integer self, Integer operand) {
return self + operand + 1
}
}

//---- B ---/
/**Attempting to invoke the java Integer.plus() with a nested category use.
This doesn't work, as the "new meaning" of + takes over as soon as the outer category usage block is entered.
*/
class IntPlusCategory {
static def plus( Integer self, Integer operand) {
return self + operand
}
}
class XtraOnePlusCategoryWithOriginalPlus {
static def plus( Integer self, Integer operand) {
def store
use( IntPlusCategory) {
store = self + operand + 1
}
return store
}
}

//--- C ---//
/** This goes around the problem created in A and B, by using minus(). However, what if minus() was already overridden with a different behaviour and therefore not useable for our purpose??
*/
class XtraOnePlusCategoryWithConvolutedPlus {
static def plus( Integer self, Integer operand) {
return -( -self - operand - 1)
}
}




use( XtraOnePlusCategoryWithNaivePlus) {
try {
assert 1 + 1 == 3
println "End of 'try' block: this should not print"
}
catch( Throwable t) {
println "Use of XtraOnePlusCategoryWithNaivePlus caused: " + t.class.name
}
}

use( XtraOnePlusCategoryWithOriginalPlus) {
try {
assert 1 + 1 == 3
println "End of 'try' block: this should not print"
}
catch( Throwable t) {
println "Use of XtraOnePlusCategoryWithOriginalPlus caused: " + t.class.name
}
}

use ( XtraOnePlusCategoryWithConvolutedPlus ) {
assert 1 + 1 == 3
}
KingCode (43) [Avatar] Offline
#2
Typo correction Re: Question re: Mix-in categories, section 7.5.3
Sorry, I mistyped

"...such that
x + y + 1 == x + y where the LHS represents the overriden + and the RHS the traditional + operator..."

which should read instead:

"such that
x + y == x + y + 1 where the LHS represents the overriden + and the RHS the traditional + operator..."
KingCode (43) [Avatar] Offline
#3
Re: Question re: Mix-in categories, section 7.5.3
After reading on, it seems an interceptor might do it?

//--- D ----//
/**
Ugly, but this allows the original use of + . Probably not adaptable, since complex cases might require many more booleans.
*/
class XtraOnePlusInterceptor implements Interceptor {
boolean calledOnce = false
boolean calledTwice = false

private void reset() {
calledOnce = false
calledTwice = false
}
Object beforeInvoke( Object object, String methodName, Object[] arguments) {
}
Object afterInvoke( Object object, String methodName, Object[] arguments, Object result) {
if ( calledTwice) {
reset()
return result
}
if ( methodName.equals( "plus") ) {
calledOnce = true
return ((Integer )result ).plus( 1)
}
return result
}
boolean doInvoke() {
if (!calledTwice ) {
if (calledOnce)
calledTwice = true
return true
}
return false
}
}
def intProxy = ProxyMetaClass.getInstance( Integer.class)
intProxy.interceptor = new XtraOnePlusInterceptor()

intProxy.use {
assert 1 + 1 == 3
assert 2 + 3 == 6
assert -20 + 19 == 0
assert 100 + 1000 == 1101
}
Mittie (397) [Avatar] Offline
#4
Re: Question re: Mix-in categories, section 7.5.3
> Is it possible to implement an operator override with
> the use of the original implementation?

Tricky, because of the recursion you mentioned.
One idea in this scenario is to first 'alias' the old implementation (register it under a new name in the MetaClass), override the operator like you did, and finally from inside the overriding method refer to the alias.

This discussion is worth relaying over to mailto:user@groovy.codehaus.org.

thanks for posting
Dierk
KingCode (43) [Avatar] Offline
#5
Re: Question re: Mix-in categories, section 7.5.3
Thanks Dierk,

That sounds like a good slution.