Type Test Inconsistency?

General discussions about working with the Astrobe IDE and programming ARM Cortex-M3, M4 and M7 microcontrollers.
Post Reply
gray
Posts: 71
Joined: Tue Feb 12, 2019 2:59 am
Location: Mauritius

Type Test Inconsistency?

Post by gray » Fri May 03, 2019 1:17 pm

From real-world code, distilled down to a test case:

Code: Select all

MODULE M;

  IMPORT Main, Out;
    
  TYPE
    T = RECORD i: INTEGER END;
    T1 = RECORD(T) k: INTEGER END;  
    R = RECORD t: T1 END;
    P = POINTER TO R;
    
  VAR
    p: P;
    
  PROCEDURE P2(VAR t: T);
  BEGIN
    t.i := 13;
    Out.String("T"); Out.Ln;
    CASE t OF T1:
      t.k := 4;
      Out.String("T1"); Out.Ln;
    END
  END P2;
    
  PROCEDURE P1(p: P);
  BEGIN
    P2(p.t)
  END P1;
    
BEGIN
  Out.String("reset"); Out.Ln;
  NEW(p);
  Out.String("case 1: P2 direct"); Out.Ln;
  P2(p.t);
  Out.String("case 2: P2 via P1"); Out.Ln;
  P1(p)
END M.
This prints:

Code: Select all

reset
case 1: P2 direct
T
T1
case 2: P2 via P1
T
My actual use case is "case 2", and I was baffled that the code within the CASE type test didn't execute. IMHO, both cases should yield the same result (case 1).

What do I miss?

PS: I just realised: still with the M3 7.0 compiler. Maybe 7.0.1 fixes that?

cfbsoftware
Site Admin
Posts: 440
Joined: Fri Dec 31, 2010 12:30 pm
Contact:

Re: Type Test Inconsistency?

Post by cfbsoftware » Fri May 03, 2019 11:30 pm

I suspect that this example is an attempt to circumvent the rule that does not allow type tests on expressions e.g. the following is invalid where p is a record:

Code: Select all

CASE p.t OF T1:
      t.k := 4;
      Out.String("T1"); Out.Ln;
    END
In this context p.t is an expression not a qualified identifier.

If you want to implement your example without any surprises stick to using pointers throughout:

Code: Select all

MODULE M;

  IMPORT Main, Out;
    
  TYPE
    T = RECORD i: INTEGER END;
    PT = POINTER TO T;

    T1 = RECORD(T) k: INTEGER END;  
    PT1 = POINTER TO T1;

    R = RECORD t: PT1 END;
    PR1 = POINTER TO R;
    
    
  VAR
    p: PR1;
    
  PROCEDURE P2(t: PT);
  BEGIN
    t.i := 13;
    Out.String("T"); Out.Ln;
    CASE t OF PT1:
      t.k := 4;
      Out.String("T1"); Out.Ln;
    END
  END P2;
    
  PROCEDURE P1(p: PR1);
  BEGIN
    P2(p.t)
  END P1;
    
BEGIN
  Out.String("reset"); Out.Ln;
  NEW(p);
  NEW(p.t);
  Out.String("case 1: P2 direct"); Out.Ln;
  P2(p.t);
  Out.String("case 2: P2 via P1"); Out.Ln;
  P1(p)
END M.

gray
Posts: 71
Joined: Tue Feb 12, 2019 2:59 am
Location: Mauritius

Re: Type Test Inconsistency?

Post by gray » Sat May 04, 2019 3:49 am

Assume P2 is implemented in another module, say implementing T and its extensions (my actual use case); the code is perfectly valid with a qualident as case variable. Now a module client calls P2 "wrongly", and P2 fails silently.

But the test-case should execute correctly with an IS type test.

Code: Select all

  PROCEDURE P2(VAR t: T);
  BEGIN
    t.i := 13;
    Out.String("T"); Out.Ln;
    IF t IS T1 THEN 
      t(T1).k := 4;
      Out.String("T1"); Out.Ln
    END
  END P2;
Same result (OMM, as said, M3 7.0 compiler).

cfbsoftware
Site Admin
Posts: 440
Joined: Fri Dec 31, 2010 12:30 pm
Contact:

Re: Type Test Inconsistency?

Post by cfbsoftware » Sat May 04, 2019 5:23 am

There is nothing wrong with procedure P2 in either example. I strongly recommend that you use pointers throughout to minimise confusion, but if you have a compelling reason to pass record elements around as in your example, and want to get your expected result, then you should make the pointer to PI a VAR parameter i.e.

Code: Select all

  PROCEDURE P1(VAR p: P);
  BEGIN
    P2(p.t)
  END P1;

gray
Posts: 71
Joined: Tue Feb 12, 2019 2:59 am
Location: Mauritius

Re: Type Test Inconsistency?

Post by gray » Sat May 11, 2019 3:45 am

Thanks, I have changed my code to use pointers now. As you say, it's clearer and cleaner.

Just out of interest, in the case without having the parameter for P1 declared as VAR, shouldn't the compiler flag the call to P2 from P1, as a read-only variable (p.t) is passed to a VAR parameter in P2?

cfbsoftware
Site Admin
Posts: 440
Joined: Fri Dec 31, 2010 12:30 pm
Contact:

Re: Type Test Inconsistency?

Post by cfbsoftware » Sat May 11, 2019 4:58 am

The value parameter that is passed to P1 is p, not p.t.

p is pointer. It is not a structured variable, so it is not read-only when it is passed as a value parameter. However, any changes to the value of p (not what it points to) only affect the local copy of the pointer.

Post Reply