Object `+= lfuns are not called when they should have been.
It appears that we don't call += lfuns directly, instead we
expand a += b+c into a = a+b+c.
Well, that is all fine and dandy, but, the f_add function then
tries to fold this back into a += by checking if the number of refs
on the object == 1, and then calling `+= instead.
This check does not give any meaningful results given normal objects and
+= usage:
- For one, the object might have an extra instance on the stack, in which
case the minimum number of references becomes 2 already.
- And for another, the object might have multiple instances which all refer
to the same object; which *implies* that updating one of those using +=
should modify all of them.
The following sample code:
class refmeharder {
int val;
void create(int i) { werror("Set %d\n",val = i); };
void getval(string s) { werror("%s%d\n",s,val); };
void incval() { werror("Inc %d\n",++val); };
refmeharder `+=(int i) { werror("+= called %d\n", val+=i); return this; };
refmeharder `+(int i)
{ werror("+ called %d\n", val+i); return refmeharder(val+i); };
};
int main(int argc, array(string) argv)
{
refmeharder a=refmeharder(2);
refmeharder b=refmeharder(3);
refmeharder c=a,d=a,e=a,f=a,g=a,h=a;
a->incval();
b->incval();
c->incval();
a+=5;
b+=11;
c+=23;
a->getval("a");
b->getval("b");
c->getval("c");
return 0;
}
Together with the following debug-patch:
diff --git a/src/operators.c b/src/operators.c
index 45de79f..18fbe4a 100644
--- a/src/operators.c
+++ b/src/operators.c
@@ -1505,6 +1505,8 @@ PMOD_EXPORT void f_add(INT32 args)
/* The first argument is an object. */
o = sp[-args].u.object;
p = o->prog->inherits[SUBTYPEOF(sp[-args])].prog;
+if((i = FIND_LFUN(p, LFUN_ADD_EQ)) != -1)
+fprintf(stderr, "Object %p type %p refs %d\n", o, p, o->refs);
if(o->refs==1 &&
(i = FIND_LFUN(p, LFUN_ADD_EQ)) != -1)
{
Results in an output of:
Set 2000
Set 3000
Inc 2001
Inc 3001
Inc 2002
Object 0x200e750 type 0x2055450 refs 8
+ called 2007
Set 2007
Object 0x200e7b0 type 0x2055450 refs 2
+ called 3012
Set 3012
Object 0x200e750 type 0x2055450 refs 7
+ called 2025
Set 2025
a2007
b3012
c2025
But should have resulted in an output of:
Set 2000
Set 3000
Inc 2001
Inc 3001
Inc 2002
Object 0x200e750 type 0x2055450 refs 8
+= called 2007
Object 0x200e7b0 type 0x2055450 refs 2
+= called 3012
Object 0x200e750 type 0x2055450 refs 7
+= called 2040
a2040
b3012
c2040
I'll be adding something to this effect to the testsuites.
The immediate questions though here are:
- The refs==1 check is way too limiting, the question is, is there a
meaningful alternative? (Probably not).
- The only way to solve this seems to be by supporting
calling `+= lfuns directly. But, if we do, do we need to somehow
suppress the autoconversion from a+=b+c to a=a+b+c ?
Can it be suppressed for objects only?
Where in the code is this conversion being done?
--
Stephen.