Build error on using VAR param in a double-nested method


(Matt Robertson) #1

I have a nested method inside of a nested method, and accessing a var parameter from the top-level method from inside the bottom-level method causes error E251: Cannot access "out" or "var" parameters from inside a lambda expression.

Here’s a code example for clarity:

method TopMethod (var aParam: Object);
	method NestedMethod;
		method DoubleNestedMethod;
			var
				i: Integer;
		begin (* DoubleNestedMethod *)
			i := aParam.aProperty;		// causes build error E251
			DoSomethingElse(aParam);	// causes build error E251
		end;
	begin (* NestedMethod *)
		DoubleNestedMethod;
	end;
begin (* TopMethod *)
	NestedMethod;
end;

(marc hoffman) #2

yes, that’s as designed. you’ll need to use a local variable for this.


(Matt Robertson) #3

Why should I need to use a local variable for this? That’s incredibly inconvenient.


(marc hoffman) #4

there’s technical reasons why nested method cannotnaccess the var/out parameters. i’ll have to defer to Carlo to explain what the exact problem is.


(Carlo Kok) #5

What marc said used to be true, but in v10 I removed those limitations; Which version are you using?

This code works fine:

unit issuedoublenestedtest;
interface

uses System,System.Collections.Generic,System.Linq,System.IO;implementation


method DoSomethingElse(var x: Object);
begin
  x := 'test2';
end;


method TopMethod (var aParam: Object);
	method NestedMethod;
		method DoubleNestedMethod;
			var
				i: Integer;
		begin (* DoubleNestedMethod *)
			//i := aParam.aProperty;		// causes build error E251
			DoSomethingElse(var aParam);	// causes build error E251
		end;
	begin (* NestedMethod *)
		DoubleNestedMethod;
	end;
begin (* TopMethod *)
	NestedMethod;
end;

begin
  var d: Object := 'test';
  TopMethod(var d);
  writeLn(d);
end.

(Prints test2)

If you use v10, can you give me a more exact testcase so I can try & fix that?


(Matt Robertson) #6

Thanks Carlo. I’m using 10.0.0.2351. I do have UseLegacyPreprocessor set to True at the moment, because I get about 8500 build errors if it’s not (as is being discussed here Elements 10 Build Error within false conditional define: "class member expected but 'case' found").

I’ll try the exact code sample you used with that switch on and off to see if I can give a more helpful description of the problem.


(Carlo Kok) #7

Thanks.


(marc hoffman) #8

Just FTR, that won’t affect this issue of course.


(Matt Robertson) #9

I didn’t expect it would, but it’s the only non-v10 aspect to my setup so I figured I’d mention it :slight_smile:


(Matt Robertson) #10

Ok here’s a stripped down and self-contained version of the code that is throwing errors in my project. I’m getting three Cannot access "out" or "var" parameters from inside a lambda expression errors with this code, in the lines noted with comments.

namespace Elem10Tests;

  uses
    java.util;

interface
  type
    DataRec = public class
      public
        punctOffset: LongInt;
        locations: ArrayList<Integer>;
        
        constructor;
      END;
    
    TPunctModifier = public class(Object)
      public
        fNumPunct, fPunctPos: Integer;
        
        FUNCTION PunctModifierOK (wdRefPos, wdTrial, wdTrialPunct: LongInt;
                                      VAR scanInfo: DataRec;
                                      iModifier: Integer): Boolean;
      end;
      
  procedure CheckTagHit (var scanInfo: DataRec; var isHit: Boolean);

implementation

  procedure CheckTagHit (var scanInfo: DataRec; var isHit: Boolean);
  
  begin
    isHit := scanInfo.locations.contains(scanInfo.punctOffset);
  end;
  
  constructor DataRec;
  
  begin
    punctOffset := 3;
    locations := new ArrayList<Integer>();
    locations.add(1);
    locations.add(2);
    locations.add(3);
  end;
  

  FUNCTION TPunctModifier.PunctModifierOK (wdRefPos, wdTrial, wdTrialPunct: LongInt;
                                                VAR scanInfo: DataRec;
                                                iModifier: Integer): Boolean;
      VAR
        refWdPos, toLimit: LongInt;
        theStartPos, theStopPos: LongInt;
        scanDone: Boolean;

    FUNCTION CheckAgreeOK (relPos, refWdPos: LongInt;
                            VAR scanInfo: DataRec): Boolean;
      VAR
        isOK: Boolean;

    BEGIN
      isOK := TRUE;
      exit isOK;
    END;

    FUNCTION ModifierFound (refWdPos, toLimit: LongInt;
                            VAR scanInfo: DataRec;
                            theStartPos, theStopPos: LongInt): Boolean;
        VAR
          iWdPos, nPunct: LongInt;
          done, isHit, checkVariant: Boolean;
  
        PROCEDURE CheckCurrentRange (VAR iWdPos, nPunct: LongInt;
                                      VAR done, isHit: Boolean);
          VAR
            currentRange: LongInt;
        
        BEGIN
          currentRange := refWdPos - iWdPos - nPunct;
          done := isHit;
        END;
  
        PROCEDURE CheckTaggedWords (VAR iWdPos, nPunct: LongInt;
                                      VAR checkVariant, isHit: Boolean);
            VAR
              testPunct: LongInt;
              isPunct: Boolean;
  
        BEGIN
            testPunct := scanInfo.locations[pred(iWdPos)];  // error here
            CheckTagHit(scanInfo, isHit);  // error here
        END;
  
        PROCEDURE CheckCharacters (VAR iWdPos, nPunct: LongInt;
                                    VAR isHit: Boolean);
          VAR
          iPunctIndex: Integer;
  
        BEGIN
            iPunctIndex := 0;
            WHILE ((iPunctIndex < fNumPunct) AND isHit) DO
            BEGIN
              iPunctIndex := succ(iPunctIndex);
              isHit := (iWdPos = fPunctPos - scanInfo.punctOffset);  // error here
            END;
        END;
  
    BEGIN  (* FUNCTION ModifierFound *)
        checkVariant := FALSE;
        done := FALSE;
        isHit := FALSE;
        nPunct := 0;
        iWdPos := refWdPos;
        WHILE NOT done DO
        BEGIN
          iWdPos := succ(iWdPos);
          done := (iWdPos > theStopPos);

          IF NOT done THEN
          BEGIN
            CheckTaggedWords(iWdPos, nPunct, checkVariant, isHit);
            CheckCharacters(iWdPos, nPunct, isHit);
            CheckCurrentRange(iWdPos, nPunct, done, isHit);
          END;
        END;
        
        exit isHit;
    END;

BEGIN (* FUNCTION TPunctModifier.PunctModifierOK *)
      scanDone := ModifierFound(refWdPos, toLimit, scanInfo, succ(theStartPos), theStopPos);
      exit NOT scanDone;
END;

{-------------------}
  
begin
  
end.

(marc hoffman) #11

Thanx. reproduced, and narrowed down to

namespace Elem10Tests;

uses
  java.util;

interface
type
  TPunctModifier = public class(Object)
  public
    FUNCTION PunctModifierOK(): Boolean;
  end;
      
implementation

  FUNCTION TPunctModifier.PunctModifierOK(): Boolean;

    FUNCTION ModifierFound (VAR scanInfo: String): Boolean;
  
      PROCEDURE CheckTaggedWords();
      BEGIN
        nil := scanInfo.length;  // error here
      END; (* CheckTaggedWords *)
  
    BEGIN  
    END; (* FUNCTION ModifierFound *)

  BEGIN 
  END; (* FUNCTION TPunctModifier.PunctModifierOK *)

{-------------------}
  
begin
end.

(RemObjects) #12

Thanks, logged as bugs://81608


(RemObjects) #13

bugs://81608 got closed with status fixed.