Board index » delphi » FPC: Wrong behavior in nested use of TCollection.ForEach

FPC: Wrong behavior in nested use of TCollection.ForEach

There is a difference in treatment between global
and local variables in nested use of
TCollection.ForEach.
The global variable is treated as expected, the
local variable is not.

uses
  Objects;

var
  Coll  : PCollection;
  Thing : PObject;

  Line1 : String;                            {***
This is a global variable ***}

procedure Zero;

  var
    Line2 : String;                           {***
This is a local variable ***}

  procedure Two (Thing: PObject);
  begin
    Line1 := 'BBB';
    Line2 := 'BBB';

    WriteLn('2: ', Line1, ' * ',
Line2);                 {*** Output line 2 ***}
  end;

  procedure One (Thing: PObject);
  begin
    Line1 := 'AAA';
    Line2 := 'AAA';

    WriteLn('1: ', Line1, ' * ',
Line2);                 {*** Output line 1 ***}

    Coll^.ForEach(@Two);

    WriteLn('3: ', Line1, ' * ',
Line2);                 {*** Output line 3 ***}
  end;
                                         {*** I
expected that output line 3 ***}
begin                                    {***
would be the same as output   ***}
  Coll^.ForEach(@One);                   {*** line
2. It is not.            ***}
end;

begin
  New(Coll, Init(1, 1));

  New(Thing, Init;
  Coll^.Insert(Thing);

  Zero;

  Dispose(Coll, Done);
end.

Sent via Deja.com
http://www.deja.com/

 

Re:FPC: Wrong behavior in nested use of TCollection.ForEach


There is a difference in treatment between global and local variables in
nested use of TCollection.ForEach.
The global variable is treated as expected, the local variable is not.

uses
  Objects;

var
  Coll  : PCollection;
  Thing : PObject;

  Line1 : String;                            {*** This is a global
variable ***}

procedure Zero;

  var
    Line2 : String;                           {*** This is a local
variable ***}

  procedure Two (Thing: PObject);
  begin
    Line1 := 'BBB';
    Line2 := 'BBB';

    WriteLn('2: ', Line1, ' * ', Line2);                 {*** Output
line 2 ***}
  end;

  procedure One (Thing: PObject);
  begin
    Line1 := 'AAA';
    Line2 := 'AAA';

    WriteLn('1: ', Line1, ' * ', Line2);                 {*** Output
line 1 ***}

    Coll^.ForEach(@Two);

    WriteLn('3: ', Line1, ' * ', Line2);                 {*** Output
line 3 ***}
  end;
                                         {*** I expected that output
line 3 ***}
begin                                    {*** would be the same as
output   ***}
  Coll^.ForEach(@One);                   {*** line 2. It is
not.            ***}
end;

begin
  New(Coll, Init(1, 1));

  New(Thing, Init;
  Coll^.Insert(Thing);

  Zero;

  Dispose(Coll, Done);
end.

Sent via Deja.com
http://www.deja.com/

Re:FPC: Wrong behavior in nested use of TCollection.ForEach


Quote
On Sun, 11 Feb 2001 12:02:40 GMT, erikv...@my-deja.com wrote:
>There is a difference in treatment between global and local variables in
>nested use of TCollection.ForEach.
>The global variable is treated as expected, the local variable is not.

I don't know the rules in FPC, but in Borland Pascal your usage is not
allowed.  The problem arises because the Action routine has to be
either a global routine or a routine that's local to the caller, since
ForEach is going to pass it a pointer to the stack frame of the
caller.

Quote
>procedure Zero;
 ...
>  procedure Two (Thing: PObject);
>  begin
 ...
>  end;

>  procedure One (Thing: PObject);
>  begin
 ...
>    Coll^.ForEach(@Two);

Here's the error.

Duncan Murdoch

Re:FPC: Wrong behavior in nested use of TCollection.ForEach


Quote
> I don't know the rules in FPC, but in Borland Pascal your usage is not
> allowed.  The problem arises because the Action routine has to be
> either a global routine or a routine that's local to the caller, since
> ForEach is going to pass it a pointer to the stack frame of the
> caller.

> ...

> Duncan Murdoch

Sounds reasonable.

I don't know the specific rules in FPC either, but there was neither an
error, nor a warning at compilation time. So I (naively) expected my
code to work. I think it would be a good thing, when the compiler
generates a message.

When I make Two local to One, everything works just fine. (See new
program.) The code is less readable now, but at least it works.

Thanks.
Erik V.

uses
  Objects;

var
  Coll  : PCollection;
  Thing : PObject;

  Line1 : String;

procedure Zero;

var
  Line2 : String;

  procedure One (Thing: PObject);
  var
    Line3 : String;

    procedure Two (Thing: PObject);
    begin
      Line1 := 'BBB';
      Line2 := 'BBB';
      Line3 := 'BBB';

      WriteLn('2: ', Line1, ' * ', Line2, ' * ', Line3);
    end;

  begin
    Line1 := 'AAA';
    Line2 := 'AAA';
    Line3 := 'AAA';

    WriteLn('1: ', Line1, ' * ', Line2, ' * ', Line3);

    Coll^.ForEach(@Two);

    WriteLn('3: ', Line1, ' * ', Line2, ' * ', Line3);
  end;

begin
  Coll^.ForEach(@One);
end;

begin
  New(Coll, Init(1, 1));

  New(Thing, Init);
  Coll^.Insert(Thing);

  Zero;

  Dispose(Coll, Done);
end.

Sent via Deja.com
http://www.deja.com/

Re:FPC: Wrong behavior in nested use of TCollection.ForEach


Quote
On Sun, 11 Feb 2001 13:56:35 GMT, erikv...@my-deja.com wrote:
>I don't know the specific rules in FPC either, but there was neither an
>error, nor a warning at compilation time. So I (naively) expected my
>code to work. I think it would be a good thing, when the compiler
>generates a message.

As far as I know, there's no compiler support for this.  I imagine
that ForEach does some low level hacking to get the stack frame
pointer.  

It would be really nice if the compiler did support pointers to local
procedures (as pointer to entry point plus pointer to stack frame).

Duncan Murdoch

Re:FPC: Wrong behavior in nested use of TCollection.ForEach


Quote
In article <9665mi$vu...@nnrp1.deja.com>, erikv...@my-deja.com wrote:

>I don't know the specific rules in FPC either, but there was neither an
>error, nor a warning at compilation time. So I (naively) expected my
>code to work. I think it would be a good thing, when the compiler
>generates a message.

There are no rules for this. The code of ForEach entirely determines the
behaviour on this, and it is afaik
compatible with Borland except that it is 32-bit.

The compiler doesn't warn because:
1. ForEach's internals are lowlevel, this is not a language statement.
2. The '@' forces the compiler to forget typing.

Afaik the rule is that the callback procedure passed to ForEach must be
local to the procedure that has "ForEach" in it.

Maybe you can also use a differrent local procedure(on the same level as the
aller), but in that case you probably shouldn't use any variables from the
parent.

Other Threads