General discussions about working with the Astrobe IDE and programming ARM Cortex-M0, M3, M4 and M7 microcontrollers.
-
gray
- Posts: 143
- Joined: Tue Feb 12, 2019 2:59 am
- Location: Mauritius
Post
by gray » Sat Apr 13, 2019 4:17 am
Code: Select all
MODULE M;
TYPE
T1 = POINTER TO T1Desc;
T1Desc = RECORD
END;
T2 = POINTER TO T2Desc;
T2Desc = RECORD(T1Desc)
END;
VAR
t1: T1;
t2: T2;
PROCEDURE P1(t: T1);
END P1;
PROCEDURE P2(VAR t: T1);
END P2;
BEGIN
t1 := t2;
P1(t2);
P2(t2) (* does not compile *)
END M.
I am not sure why the compiler rejects the assignment to the VAR procedure parameter in P2.
-
cfbsoftware
- Site Admin
- Posts: 525
- Joined: Fri Dec 31, 2010 12:30 pm
-
Contact:
Post
by cfbsoftware » Sat Apr 13, 2019 5:02 am
Refer to section 10.1.
Formal parameters in the Oberon Language Report. In particular:
The type of each formal parameter is specified in the parameter list. For variable parameters, it must be identical to the corresponding actual parameter's type, except in the case of a record, where it must be a base type of the corresponding actual parameter's type.
At compile time, the type of the actual parameter in your call to P2 is T2 whereas it should be T1. The call to P1 is OK because the formal parameter to P1 is not a variable parameter.
The following example is OK:
Code: Select all
MODULE M2;
TYPE
T1 = POINTER TO T1Desc;
T1Desc = RECORD
END;
T2 = POINTER TO T2Desc;
T2Desc = RECORD(T1Desc)
END;
VAR
t1: T1;
t2: T2;
t1d: T1Desc;
t2d: T2Desc;
PROCEDURE P1(t: T1);
END P1;
PROCEDURE P2(VAR t: T1);
END P2;
PROCEDURE P1d(VAR t: T1Desc);
END P1d;
BEGIN
t1 := t2;
t1d := t2d;
P1(t2);
P2(t1);
P1d(t2d)
END M2.
-
gray
- Posts: 143
- Joined: Tue Feb 12, 2019 2:59 am
- Location: Mauritius
Post
by gray » Sun Apr 14, 2019 1:30 am
Hm, thanks, yes, the Report is clear about this. Mr W's writing is succinct and precise as usual. I was mulling over the reason why pointers to an extended type cannot be passed as VAR parameters declared as pointer to a base type thereof.
Is this the (or a) use case and problem the rule prevents?
Code: Select all
MODULE M9;
TYPE
T1 = POINTER TO T1Desc;
T1Desc = RECORD
i: INTEGER
END;
T2 = POINTER TO T2Desc;
T2Desc = RECORD(T1Desc)
k: INTEGER
END;
VAR
t2: T2;
PROCEDURE P1(VAR t: T1);
VAR
t1: T1;
BEGIN
NEW(t1);
t := t1
END P1;
BEGIN
NEW(t2);
t2.i := 4;
t2.k := 13;
P1(t2); (* error *)
t2.k := 17 (* ouch *)
END M9.
-
cfbsoftware
- Site Admin
- Posts: 525
- Joined: Fri Dec 31, 2010 12:30 pm
-
Contact:
Post
by cfbsoftware » Sun Apr 14, 2019 4:16 am
I can recommend an excellent reference to help you to understand the reasoning behind these sorts of details. It is the book titled
Object-Oriented Programming in Oberon-2 by Hanspeter Mössenböck. It is available as PDF with the friendly permission of Springer-Verlag from :
http://ssw.jku.at/Research/Books/Oberon2.pdf
Keep in mind while you are reading it that Oberon-2 has additional O-O features (e.g. type-bound procedures), and some differences (e.g. WITH instead of CASE) so it is not all relevant to Oberon-07. However, there should still be enough to be useful to you.
-
gray
- Posts: 143
- Joined: Tue Feb 12, 2019 2:59 am
- Location: Mauritius
Post
by gray » Mon Apr 15, 2019 2:30 am
Code: Select all
MODULE M8;
TYPE
T1 = RECORD
i: INTEGER
END;
T2 = RECORD(T1)
k: INTEGER
END;
VAR
t1: T1;
t2: T2;
PROCEDURE P1(VAR t: T1);
VAR
t1: T1;
BEGIN
t1.i := 17;
t := t1
END P1;
BEGIN
t2 := t1; (* illegal *)
t2.i := 13;
t2.k := 4;
P1(t2); (* t2.i = 17, t2.k = 4 *)
END M8.
The t2 := t1 assignment is illegal, as per compiler error as well as the Report. However, P1(t2) and the assignment therein works and yields the results as indicated in the comment. Is this legal code as per the language definition? If yes, what are the rules of the assignment in P1 as regards the record fields in T2 but not in T1?
-
cfbsoftware
- Site Admin
- Posts: 525
- Joined: Fri Dec 31, 2010 12:30 pm
-
Contact:
Post
by cfbsoftware » Mon Apr 15, 2019 8:48 am
That all looks good to me. In this case the assignment:
is equivalent to:
t2.k remains unchanged. If you wanted to modify k as well you would need to use an assignment with a type guard (and a type test to be on the safe side) within the procedure P1.
Code: Select all
PROCEDURE P1(VAR t: T1);
VAR
t1: T1;
BEGIN
t1.i := 17;
t := t1;
IF t IS T2 THEN t(T2).k := 99 END;
END P1;
Alternatively, if you prefer, you can use CASE to handle both the type test and guard:
Code: Select all
PROCEDURE P1(VAR t: T1);
VAR
t1: T1;
BEGIN
t1.i := 17;
t := t1;
CASE t OF T2: t.k := 99 END;
END P1;