roxen.lists.pike.general

Subject Author Date
Re: Bug when using program as key of mapping Henrik_Grubbström <grubba[at]roxen[dot]com> 25-08-2009
On Tue, 25 Aug 2009, ¹ùÑ©ËÉ wrote:

> $ cat t.pike
>
> mapping m=([]);
> class SomeClass{}
> class OutsideClass{
>         class InsideClass(string|void dir,object|void room_design){
>                   array t(){
>                            return ({});
>                            SomeClass; //Line A
>                   }
>         };
>
>         void create()
>         {
>                   m[object_program(InsideClass("haha",SomeClass()))]=1;
>         }
> }
>
> void main()
> {
>         object ob=OutsideClass();
>         write("should be 1: %O\n",m[OutsideClass.InsideClass]);
> }
>
> $ pike t.pike
> Sould be 1: 0
>
> If remove Line A, the result is good:
>
> $ pike t.pike
> Sould be 1: 1

The reason for the difference is that in the first case InsideClass gets 
the flag PROGRAM_USES_PARENT set, since it refers (even though via 
ultimately dead code) to a symbol in a parent scope. When 
PROGRAM_USES_PARENT is set, Pike keeps track of the context from which 
the class came.

Consider the following case:

class A {
   class B {
     mixed b() { return C; }
   }
   class C {}
}

class D {
   inherit A;
   class C {
     inherit A::C;
     void c() {}
   }
}

int main()
{
   object a = A();
   object d = D();

   werror("function_object(a->B):%O\n", function_object(a->B));
   werror("function_object(a->C):%O\n", function_object(a->C));
   werror("function_object(d->B):%O\n", function_object(d->B));
   werror("function_object(d->C):%O\n", function_object(d->C));

   object b = a->B();
   werror("indices(b->b()()):%O\n", indices(b->b()()));

   object b2 = d->B();
   werror("indices(b2->b()()):%O\n", indices(b2->b()()));

   werror("function_object(b->b()): %O\n",
          function_object(b->b()));
   werror("function_object(b2->b()):%O\n",
          function_object(b2->b()));
}

Here the class A.B refers to the class A.C and thus gets 
PROGRAM_USES_PARENT set. The class A.C on the other hand
does not refer to anything. The class D.B keeps its flag,
and the class D.C gets the flag set, since it refers to
A.C via the inherit in D. The example thus outputs:

function_object(a->B):/main()->A()
function_object(a->C):0
function_object(d->B):/main()->D()
function_object(d->C):/main()->D()
indices(b->b()()):({ })
indices(b2->b()()):({ /* 1 element */
     "c"
})
b->b() == b2->b():0
function_object(b->b()): 0
function_object(b2->b()):/main()->D()

In your example, the program inserted in the mapping has a parent object 
(ob), while the lookup is done with a program lacking a parent object.
If you change the last line to

 	write("should be 1: %O\n",m[ob->InsideClass]);

You will get the expected 1 in the output, although if you have multiple 
instances of OutsideClass you will still run into problems, since you will 
have one InsiceClass for each object.

> Xuesong Guo

--
Henrik Grubbström					<grubba[at]roxen.com>
Roxen Internet Software AB