FPC: Wrong behavior in nested use of TCollection.ForEach 
Author Message
 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 ***}


    WriteLn('3: ', Line1, ' * ',
Line2);                 {*** Output line 3 ***}
  end;
                                         {*** I
expected that output line 3 ***}
begin                                    {***
would be the same as output   ***}

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.*-*-*.com/



Thu, 31 Jul 2003 19:57:42 GMT  
 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 ***}


    WriteLn('3: ', Line1, ' * ', Line2);                 {*** Output
line 3 ***}
  end;
                                         {*** I expected that output
line 3 ***}
begin                                    {*** would be the same as
output   ***}

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/



Thu, 31 Jul 2003 20:02:40 GMT  
 FPC: Wrong behavior in nested use of TCollection.ForEach

Quote:

>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
 ...


Here's the error.

Duncan Murdoch



Thu, 31 Jul 2003 20:47:17 GMT  
 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);


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

begin

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/



Thu, 31 Jul 2003 21:56:35 GMT  
 FPC: Wrong behavior in nested use of TCollection.ForEach

Quote:

>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



Fri, 01 Aug 2003 00:59:35 GMT  
 FPC: Wrong behavior in nested use of TCollection.ForEach

Quote:

>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.

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.



Fri, 01 Aug 2003 15:58:43 GMT  
 
 [ 6 post ] 

 Relevant Pages 

1. Bug in tCollection.ForEach?

2. TDBGrid Behavior Seems Wrong

3. BDE: Capability not supported token: NESTED SELECT (when using Paradox files, works with Interbase)

4. Is using a timer to refresh wrong ?

5. Q: wrong DBImage-Using ?

6. Options for GUI development using FPC

7. FPC:problem with printing from fpc programs

8. FPC: translate execvp from c to FPC

9. Temporary Tables / FOREACH

10. ForEach and traversal methods in OOP data structures

11. HELP! ForEach/FirstThat methods

12. HELP! ForEach/FirstThat methods

 

 
Powered by phpBB® Forum Software