Discussion:
Procedure type compatibility
(too old to reply)
August Karlstrom
2017-10-03 07:44:07 UTC
Permalink
Is the following module valid Oberon-07?

MODULE test;

TYPE
ProcA = PROCEDURE;
ProcB = PROCEDURE;

VAR
p: ProcA;
q: ProcB;

BEGIN
p := q
END test.

Procedure types have structural equivalence, but does this hold true
even when the types have different names?


-- August
c***@gmail.com
2017-10-03 11:24:48 UTC
Permalink
Post by August Karlstrom
Is the following module valid Oberon-07?
MODULE test;
TYPE
ProcA = PROCEDURE;
ProcB = PROCEDURE;
VAR
p: ProcA;
q: ProcB;
BEGIN
p := q
END test.
Procedure types have structural equivalence, but does this hold true
even when the types have different names?
I believe so. Consider this. If the following procedure P existed:

PROCEDURE P();
BEGIN
END P;

Then
p := P; (* Is valid *)
q := P; (* Is valid *)

so it makes sense to me that

p := q

should also be valid.

I some ways this is similar to:

MODULE AliasTest;

TYPE
Int = INTEGER;
Int32 = INTEGER;

VAR
i: Int;
i32: Int32;

BEGIN
i := i32 (* Is valid *)
END AliasTest.

Note that the type compatibility rules in Oberon-07 are more aligned to structural equivalence rather than the strict name equivalence of earlier versions of Oberon.

For example, two arrays with different type names are assignment compatible as long as they have the same length and base type. I do not see this explicitly allowed or prohibited in the report - it depends on your interpretation of 'same type'. However, I believe structural array equivalence is a logical conclusion following the introduction of the new rule that allows open array parameters to be assigned to arrays of equal base type. There would be little point in having a name-equivalence array assignment rule if it could be so easily bypassed.

Regards,
Chris Burrows
CFB Software
http://www.astrobe.com
Diego Sardina
2017-10-03 13:26:08 UTC
Permalink
Post by August Karlstrom
Procedure types have structural equivalence, but does this hold true
even when the types have different names?
Procedure types have name equivalence.

Structural equivalence is only used in the assignment of a procedure constant to a procedure variable.

Wirth confirmed me that in Project Oberon 2013 the compiler doesn't behave correctly in this case.

--
Diego Sardina
August Karlstrom
2017-10-03 14:23:02 UTC
Permalink
Post by Diego Sardina
Post by August Karlstrom
Procedure types have structural equivalence, but does this hold true
even when the types have different names?
Procedure types have name equivalence.
Structural equivalence is only used in the assignment of a procedure constant to a procedure variable.
Wirth confirmed me that in Project Oberon 2013 the compiler doesn't behave correctly in this case.
That's interesting. This is somewhat analogous to character arrays and
strings; we make an exception just for the purpose of initialization.

If the structural equivalence of arrays (as mentioned by Chris) is also
a "flaw" in the Project Oberon 2013 compiler we have that two types Ta
and Tb are the same if (and only if):

1. Ta and Tb are both denoted by the same type identifier, or
2. Ta is declared to equal Tb in a type declaration of the form Ta = Tb, or
3. a and b appear in the same identifier list in a variable, record
field, or formal parameter declaration and are not open arrays.

(These are the first three paragraphs in the definition of *same type*
in Oberon-2).

Is the equality in paragraph 2 transitive (and reflexive) so that for
instance A = INTEGER and B = INTEGER implies A = B?


-- August
c***@gmail.com
2017-10-03 22:07:56 UTC
Permalink
Post by August Karlstrom
If the structural equivalence of arrays (as mentioned by Chris) is also
a "flaw" in the Project Oberon 2013 compiler
The Project Oberon 2013 compiler should not be treated as a 'reference' compiler. It does include some language extensions (e.g. the treatment of ARRAY OF BYTE) for pragmatic reasons.

However the concept that structural equivalence is used when determining whether arrays are assignment compatible is further reinforced in the tutorial "Programming in Oberon" (2015) when discussing parameter compatibility:

"If a formal parameter type denotes an array structure, its corresponding actual parameter must be an array of the *identical type*. This implies that it must have *elements of identical type* and the *same bounds* of the index range."

A programmer used to strict name equivalence might be surprised that he can do this:

TYPE
Weights = ARRAY 10 OF INTEGER;
Heights = ARRAY 10 OF INTEGER;

VAR
w: Weights;
h: Heights;

w := h;

However, Oberon-07 allows (indisputably I would suggest):

w[0] := h[0];

etc.

So why arbitrarily prohibit the assignment of all elements of the arrays in one statement?

If they wanted type protection of the sort provided by name equivalence then they could declare their items as arrays of records. In my opinion, this is consistent with the notion that typed pointers in Oberon-07 now also only apply to record types.

--
Chris Burrows
CFB Software
http://www.astrobe.com
August Karlstrom
2017-10-04 05:35:49 UTC
Permalink
Post by c***@gmail.com
TYPE
Weights = ARRAY 10 OF INTEGER;
Heights = ARRAY 10 OF INTEGER;
VAR
w: Weights;
h: Heights;
w := h;
w[0] := h[0];
etc.
So why arbitrarily prohibit the assignment of all elements of the arrays in one statement?
The same argument can be made for structurally equivalent records with
different names; if we can copy a record field by field, why not allow
structural equivalence in record assignments?

Anyway, it's not that I think structural equivalence for array and
procedure types is a bad idea, but the type compatibility rules need to
be clearly specified like in Oberon-2.
Post by c***@gmail.com
If they wanted type protection of the sort provided by name equivalence then they could declare their items as arrays of records. In my opinion, this is consistent with the notion that typed pointers in Oberon-07 now also only apply to record types.
We can also argue that all pointer types with the same base type should
be assignment compatible, for example

MODULE M;

TYPE
T = RECORD END;

VAR
p: POINTER TO T;
q: POINTER TO T;

BEGIN
p := q
END M.


-- August
c***@gmail.com
2017-10-04 10:14:42 UTC
Permalink
Post by August Karlstrom
We can also argue that all pointer types with the same base type should
be assignment compatible
I thought that they are assignment compatible, aren't they?

--
Chris Burrows
CFB Software
http://www.astrobe.com
August Karlstrom
2017-10-04 11:49:37 UTC
Permalink
Post by c***@gmail.com
Post by August Karlstrom
We can also argue that all pointer types with the same base type should
be assignment compatible
I thought that they are assignment compatible, aren't they?
Again I can't tell by reading the language report. If they are I suggest
the following definition of *same type*:

Two variables a and b with types Ta and Tb are of the same type if
1. Ta and Tb are both denoted by the same type identifier, or
2. Ta is declared to equal Tb in a type declaration of the form Ta = Tb, or
3. a and b appear in the same identifier list in a variable, record
field, or formal parameter declaration and are not open arrays, or
4. Ta and Tb are array types whose element types and lengths are the
same, or
5. Ta and Tb are pointer types whose pointer base types are the same, or
6. Ta and Tb are procedure types whose formal parameter lists match.

What do you think?


-- August
Diego Sardina
2017-10-05 06:18:22 UTC
Permalink
Then all, but except record types, follow structural equivalence and both of you support this.

I would like to see in the report where this is clearly written.

From Modula-2 to Oberon and Oberon-07 the type system hasn't changed so drastically.


--
Diego Sardina
c***@gmail.com
2017-10-05 07:32:33 UTC
Permalink
Post by Diego Sardina
Then all, but except record types, follow structural equivalence and both of you support this.
For additional information refer to section 4. "Assignment of arrays and records" in the document:

"Differences between Revised Oberon and Oberon". You cna download a copy from:

https://www.inf.ethz.ch/personal/wirth/Oberon/Oberon07.pdf

"But now we handle array and record assignments just like other assignments, writing dst := src, and discard the COPY procedure. The destination array must not be shorter than the source array. This is in accordance with the assignment rule for strings and with the compatibility of record types and their extensions."

I see this as a consequence of the need to be able to easily make local copies of array value parameters since they became read-only as described in section 5 of the same document.

Regards,
Chris Burrows
CFB Software
http://www.astrobe.com
Diego Sardina
2017-10-05 07:48:45 UTC
Permalink
[...]
"The destination array must not be shorter than the source array. This is in accordance with the assignment rule for strings and with the compatibility of record types and their extensions."
You should know better than me that this document is out-of-date as Oberon-07 doesn't allow anymore assignment of array by structure.

Oberon-07 report had this statement in section Assignment:

---
2. Arrays must have the same element type, and the length of the
destination array must not be less than the length of the source array.
---

This sentence was removed and doesn't hold anymore.


--
Diego Sardina
c***@gmail.com
2017-10-05 12:29:01 UTC
Permalink
Post by Diego Sardina
[...]
"The destination array must not be shorter than the source array. This is in accordance with the assignment rule for strings and with the compatibility of record types and their extensions."
You should know better than me that this document is out-of-date as Oberon-07 doesn't allow anymore assignment of array by structure.
---
2. Arrays must have the same element type, and the length of the
destination array must not be less than the length of the source array.
---
This sentence was removed and doesn't hold anymore.
Yes - I think you are right. I double-checked and it appears that section of the report was changed about a week after the summary was last updated. The source and destination arrays have to be the same length now unless passed via an open array parameter.

Regards,
Chris Burrows
CFB Software
http://www.astrobe.com
August Karlstrom
2017-10-05 08:25:07 UTC
Permalink
Post by c***@gmail.com
Post by Diego Sardina
Then all, but except record types, follow structural equivalence and both of you support this.
https://www.inf.ethz.ch/personal/wirth/Oberon/Oberon07.pdf
"But now we handle array and record assignments just like other assignments, writing dst := src, and discard the COPY procedure. The destination array must not be shorter than the source array. This is in accordance with the assignment rule for strings and with the compatibility of record types and their extensions."
I see this as a consequence of the need to be able to easily make local copies of array value parameters since they became read-only as described in section 5 of the same document.
That's an interesting observation. Then I guess assignment of open
arrays is also related to this need. Unfortunately, making copies of
open array parameters requires a language extension, namely NEW(a, n).

-- August
c***@gmail.com
2017-10-05 11:06:24 UTC
Permalink
Post by August Karlstrom
Post by c***@gmail.com
https://www.inf.ethz.ch/personal/wirth/Oberon/Oberon07.pdf
"But now we handle array and record assignments just like other assignments, writing dst := src, and discard the COPY procedure. The destination array must not be shorter than the source array. This is in accordance with the assignment rule for strings and with the compatibility of record types and their extensions."
I see this as a consequence of the need to be able to easily make local copies of array value parameters since they became read-only as described in section 5 of the same document.
That's an interesting observation. Then I guess assignment of open
arrays is also related to this need. Unfortunately, making copies of
open array parameters requires a language extension, namely NEW(a, n).
Open array parameters cannot be assigned to other open array parameters but they can be assigned to normal local arrays without using NEW. i.e. the following is legal:

PROCEDURE P(a: ARRAY OF INTEGER);
VAR
local: ARRAY 20 OF INTEGER;
BEGIN
local := a;
local[0] := 999;
....
....

In this example the actual parameter can be an INTEGER array of any length up to the maximum of 20 elements.

This can be implemented much more efficiently than would otherwise be required:

PROCEDURE P(a: ARRAY OF INTEGER);
VAR
local: ARRAY 20 OF INTEGER;
i: INTEGER;
BEGIN
FOR i := 0 TO LEN(a) - 1 DO local[i] := a[i] END;
local[0] := 999;
....
....

Regards,
Chris Burrows
CFB Software
http://www.astrobe.com
August Karlstrom
2017-10-05 12:09:27 UTC
Permalink
Post by c***@gmail.com
Post by August Karlstrom
Post by c***@gmail.com
I see this as a consequence of the need to be able to easily make local copies of array value parameters since they became read-only as described in section 5 of the same document.
That's an interesting observation. Then I guess assignment of open
arrays is also related to this need. Unfortunately, making copies of
open array parameters requires a language extension, namely NEW(a, n).
Open array parameters cannot be assigned to other open array parameters
Indeed. What I had in mind was rather the assignment of an open array a
to a dynamic array b, stack allocated with NEW(a, LEN(b)). This is a
language extension that NW has used. It implies that a can be of any length.


-- August
c***@gmail.com
2017-10-05 21:16:17 UTC
Permalink
Post by August Karlstrom
Indeed. What I had in mind was rather the assignment of an open array a
to a dynamic array b, stack allocated with NEW(a, LEN(b)). This is a
language extension that NW has used. It implies that a can be of any length.
Understood. We support that extension in the Astrobe for ARM Cortex-M compilers for single-dimensional local array variables. I like it because it doesn't require any corresponding DISPOSE or garbage collection. My previous example then becomes:

PROCEDURE P(a: ARRAY OF INTEGER);
VAR
local: ARRAY OF INTEGER;
BEGIN
NEW(local, LEN(a));
local := a;
local[0] := 999;

I also recall sometime in the past seeing this sort of suggestion:

PROCEDURE P(a: ARRAY OF INTEGER; n: INTEGER);
VAR
local: ARRAY n OF INTEGER;

In which case you wouldn't need the explicit NEW to allocate the memory on the stack.

The next step in this thought process might be:

PROCEDURE P(a: ARRAY OF INTEGER);
VAR
local: ARRAY LEN(a) OF INTEGER;

but somehow I'm not comfortable with that ...

Regards,
Chris

Chris Burrows
CFB Software
http://www.astrobe.com
August Karlstrom
2017-10-06 07:51:21 UTC
Permalink
Post by c***@gmail.com
PROCEDURE P(a: ARRAY OF INTEGER);
VAR
local: ARRAY LEN(a) OF INTEGER;
but somehow I'm not comfortable with that ...
I see what you mean; LEN(a) is not a constant expression. However, in
the global scope an array declaration like this is valid:

MODULE M;

VAR
a: ARRAY 10 OF INTEGER;
b: ARRAY LEN(a) OF INTEGER;

END M.


-- August
August Karlstrom
2017-10-05 08:11:41 UTC
Permalink
Post by Diego Sardina
Then all, but except record types, follow structural equivalence and both of you support this.
I would like to see in the report where this is clearly written.
From Modula-2 to Oberon and Oberon-07 the type system hasn't changed so drastically.
One theory I have is that Niklaus Wirth sometimes specifies things a bit
loosely to be able to try things out which aren't in conflict with the
specification. Then if he is happy with the change he adds it to the report.


-- August
August Karlstrom
2017-10-05 15:30:08 UTC
Permalink
Post by August Karlstrom
On Wednesday, October 4, 2017 at 4:05:50 PM UTC+10:30, August
Post by August Karlstrom
We can also argue that all pointer types with the same base type should
be assignment compatible
I thought that they are assignment compatible, aren't they?
Again I can't tell by reading the language report.
Actually, I can. The following module is obviously valid:

MODULE M;

TYPE
T = RECORD END;
T1 = RECORD (T) END;

VAR
x: POINTER TO T;
y: POINTER TO T1;

BEGIN
NEW(y);
x := y
END M.

If y instead is declared with the type POINTER TO T we have a trivial
type extension (T is an extension of T).

-- August
August Karlstrom
2017-10-10 11:21:01 UTC
Permalink
Post by August Karlstrom
1. Ta and Tb are both denoted by the same type identifier, or
2. Ta is declared to equal Tb in a type declaration of the form Ta = Tb, or
3. a and b appear in the same identifier list in a variable, record
field, or formal parameter declaration and are not open arrays.
Given the type declarations

Ta = INTEGER
Tb = INTEGER
Tc = Tb

paragraph two in the above definition of *same type* from the Oberon-2
report suggests that

* Ta and Tb are different types (no declaration of Ta = Tb),
* Ta and Tc are different types (no declaration of Ta = Tc) and
* Tc and INTEGER are different types (no declaration of Tc = INTEGER).

Is this a correct interpretation of *same type* in Oberon-2? As far as I
understand, Oberon-2 is quite strict when it comes to name equivalence,
and in this context the interpretation actually makes sense.


-- August
Diego Sardina
2017-10-10 19:17:07 UTC
Permalink
Post by August Karlstrom
Given the type declarations
Ta = INTEGER
Tb = INTEGER
Tc = Tb
All those types are "the same". Don't forget transitivity.


--
Diego Sardina
c***@gmail.com
2017-10-10 21:17:44 UTC
Permalink
Post by Diego Sardina
Post by August Karlstrom
Given the type declarations
Ta = INTEGER
Tb = INTEGER
Tc = Tb
All those types are "the same". Don't forget transitivity.
--
Diego Sardina
If we have:

Ta = ARRAY 10 OF INTEGER
Tb = ARRAY 10 OF INTEGER

are Ta and Tb "the same"?

--
Chris Burrows
Diego Sardina
2017-10-11 03:49:22 UTC
Permalink
Post by c***@gmail.com
Ta = ARRAY 10 OF INTEGER
Tb = ARRAY 10 OF INTEGER
are Ta and Tb "the same"?
No.

(Copy and paste from Oberon mailing list)

These are different considerations.

In the right part (after "=") of a type definition, ARRAY, RECORD, POINTER TO and PROCEDURE are to be considered *type constructor* for defining new types, while in the case of an identifier denoting an already existing named type (aliasing), you may choose between:

- an alias introduces a distinct type (strict name equivalence, like in Ada), or
- an alias introduces an equivalent type (loose name equivalence, like in Pascal-family languages).



--
Diego Sardina
August Karlstrom
2017-10-11 07:40:35 UTC
Permalink
Post by Diego Sardina
- an alias introduces a distinct type (strict name equivalence, like in Ada), or
- an alias introduces an equivalent type (loose name equivalence, like in Pascal-family languages).
This is very informative. If I understand this correctly my
interpretation is correct under strict name equivalence. As far as I
understand the definition of *same type* in Oberon-2, it doesn't say if
the name equivalence is strict or loose. What is the typical case
against strict name equivalence?


-- August
Diego Sardina
2017-10-11 10:36:17 UTC
Permalink
Post by August Karlstrom
This is very informative. If I understand this correctly my
interpretation is correct under strict name equivalence. As far as I
understand the definition of *same type* in Oberon-2, it doesn't say if
the name equivalence is strict or loose. What is the typical case
against strict name equivalence?
No, loose name equivalence.

That case is covered by 2) in:

1) Ta and Tb are both denoted by the same type identifier, or
2) Ta is declared to equal Tb in a type declaration of the form Ta = Tb, or [...]

Note that Ta and Tb are two different type identifiers (identifiers introduced with TYPE), because 1) is false.

Same types concern only types introduced with a type declaration.

For example:

TYPE
Ta = ARRAY 10 OF INTEGER
Tb = ARRAY 10 OF INTEGER

Are Ta and Tb denoted by the same type identifier?
False, they are two different type identifiers.

Is Ta declared equal to Tb in a type declaration of the form Ta = Tb?
False, they are not.

They are not the same type.

Another example:

TYPE
Ta = INTEGER
Tb = INTEGER
Tc = Tb

Note that Basic types are defined as "predeclared" (type) identifiers.

Are Ta/Tb and INTEGER denoted by the same type identifier?
False, they are two different type identifiers.

Is Ta/Tb declared equal to INTEGER in a type declaration of the form Ta = Tb?
True, they are.

So Ta and Tb are the same type.
The same follows for Tc and Tb.

Of course for transitivity Ta, Tb and Tc are all the same type.


--
Diego Sardina
August Karlstrom
2017-10-11 13:12:39 UTC
Permalink
Post by August Karlstrom
TYPE
Ta = INTEGER
Tb = INTEGER
Tc = Tb
Note that Basic types are defined as "predeclared" (type) identifiers.
Are Ta/Tb and INTEGER denoted by the same type identifier?
False, they are two different type identifiers.
Is Ta/Tb declared equal to INTEGER in a type declaration of the form Ta = Tb?
True, they are.
So Ta and Tb are the same type.
The same follows for Tc and Tb.
Of course for transitivity Ta, Tb and Tc are all the same type.
If we assume transitivity in the definition of *same type* we get
non-strict name equivalence whereas if we interpret it in verbatim we
get strict name equivalence.


-- August
Diego Sardina
2017-10-11 14:43:34 UTC
Permalink
Post by August Karlstrom
If we assume transitivity in the definition of *same type* we get
non-strict name equivalence whereas if we interpret it in verbatim we
get strict name equivalence.
I though that removing 2) was enough.

By the way, here there is a bit of theory: http://web.eecs.utk.edu/~bvz/teaching/cs365Sp12/notes/types.html

In my opinion strict name equivalence is harder to establish.

TYPE
Ta = RECORD i: INTEGER END;
Tb = Ta;

With strict name equivalence Tb and Ta are distinct, but what about the underlying structure of Tb?
Of course in a more elaborate (and complex) type system, a type name is also a type expression that solves to a particular type constructor to define the underlying structure.

Here is an Ada example:

procedure test is
type Ta is record i: integer; end record;
type Tb is new Ta;
type Tc is new Ta;

b: Tb;
c: Tc;
begin
b.i := 1;
c.i := 2;
b := c;
end test;

Tb and Tc share the same structure of Ta, because of course we used it to define them, but they are assignment incompatible, indeed gnat gives an error in b := c.

(Substituting "type" with "subtype" and removing "new", we have the equivalent Pascal/Modula-2/Oberon case.)


So removing 2) is not enough, more elaborate words are required.

A type system with loose name equivalence is a lot simpler.


--
Diego Sardina
August Karlstrom
2017-10-11 15:22:45 UTC
Permalink
Post by Diego Sardina
So removing 2) is not enough, more elaborate words are required.
Isn't it enough to say that in a type declaration Tb = Ta, the type Ta
is compatible with Tb?
Post by Diego Sardina
A type system with loose name equivalence is a lot simpler.
An even simpler approach is of course to exclude the type alias feature
from the language, something which NW did before it was reintroduced.
Without type aliases Oberon uses strict name equivalence.


-- August
d***@eml.cc
2017-10-11 16:37:52 UTC
Permalink
Post by August Karlstrom
Post by Diego Sardina
A type system with loose name equivalence is a lot simpler.
An even simpler approach is of course to exclude the type alias feature
from the language, something which NW did before it was reintroduced.
Without type aliases Oberon uses strict name equivalence.
Yup


--
Diego Sardina
c***@gmail.com
2017-10-03 22:10:05 UTC
Permalink
Post by Diego Sardina
Post by August Karlstrom
Procedure types have structural equivalence, but does this hold true
even when the types have different names?
Procedure types have name equivalence.
Structural equivalence is only used in the assignment of a procedure constant to a procedure variable.
Wirth confirmed me that in Project Oberon 2013 the compiler doesn't behave correctly in this case.
Were those his exact words or is that your interpretation of what he said?
August Karlstrom
2017-10-05 14:37:12 UTC
Permalink
Post by c***@gmail.com
Post by Diego Sardina
Post by August Karlstrom
Procedure types have structural equivalence, but does this hold true
even when the types have different names?
Procedure types have name equivalence.
Structural equivalence is only used in the assignment of a procedure constant to a procedure variable.
Wirth confirmed me that in Project Oberon 2013 the compiler doesn't behave correctly in this case.
Were those his exact words or is that your interpretation of what he said?
I have been in contact with Niklaus Wirth and he wrote that using
structural equivalence in assignment of (non-open) array, pointer and
procedure variables should be seen as "an addition to the language
definition". So to summarize, the module `test' (from the first message
in this thread) is accepted by the PO2013 compiler but we can not rely
on that it will compile on a different (conforming) implementation of
Oberon-07.

MODULE test;

TYPE
ProcA = PROCEDURE;
ProcB = PROCEDURE;

VAR
p: ProcA;
q: ProcB;

BEGIN
p := q
END test.


-- August
August Karlstrom
2017-10-05 15:14:03 UTC
Permalink
Post by August Karlstrom
I have been in contact with Niklaus Wirth and he wrote that using
structural equivalence in assignment of (non-open) array, pointer and
procedure variables should be seen as "an addition to the language
definition"
Sorry, it should be "(non-open) array and procedure variables".

-- August
August Karlstrom
2017-10-18 15:23:21 UTC
Permalink
Post by Diego Sardina
Procedure types have name equivalence.
Structural equivalence is only used in the assignment of a procedure constant to a procedure variable.
Somewhat surprising this implies that a procedure variable cannot be
compared to a procedure constant (using = or #).


-- August
Diego Sardina
2017-10-20 06:59:26 UTC
Permalink
Post by August Karlstrom
Somewhat surprising this implies that a procedure variable cannot be
compared to a procedure constant (using = or #).
Yup, the same holds for strings in Oberon-07.

Oh, about strings, this wasn't true in Oberon.
Oberon had this sentence: "Strings can be assigned to and *compared* with arrays of characters". This was a sort of concession because string literals are allocated in memory as array of characters, so at the end they could be used that way.
But this assumption was considered wrong because it reflects a particular underlying implementation.

In general this makes sense, because constants are untyped in Oberon, so structural equivalence is necessary.

Just by casuality some days ago I found something interesting in Project Oberon 1992 (page 345):

Assignment of procedures to variables (and parameters) of a procedural type is handled by constructing a procedure descriptor and assigning it to the destination. The descriptor consists of a module descriptor address and an entry offset. Also, the check for type compatibility is fairly complex in this case, because the language admits structural equivalence instead of name equivalence, which is necessary because the type of a declared procedure bears no name. Therefore, both result type and parameter types must be checked for compatibility.


--
Diego Sardina
August Karlstrom
2017-10-20 09:42:21 UTC
Permalink
Post by Diego Sardina
Post by August Karlstrom
Somewhat surprising this implies that a procedure variable cannot be
compared to a procedure constant (using = or #).
Yup, the same holds for strings in Oberon-07.
I didn't know that. Are comparisons of character variables and
single-character strings also rejected?
Post by Diego Sardina
Oh, about strings, this wasn't true in Oberon.
Oberon had this sentence: "Strings can be assigned to and *compared* with arrays of characters". This was a sort of concession because string literals are allocated in memory as array of characters, so at the end they could be used that way.
But this assumption was considered wrong because it reflects a particular underlying implementation.
Even if string constants are not null-terminated, comparing strings with
character arrays will not be less efficient. You just need a little more
code to handle the different cases. Do you have an example of a
hypothetical implementation of string constants that would make it hard
to compare strings with character arrays?
Post by Diego Sardina
In general this makes sense, because constants are untyped in Oberon, so structural equivalence is necessary.
I don't understand what you mean? The only untyped constant is NIL.


-- August
c***@gmail.com
2017-10-20 23:05:44 UTC
Permalink
Post by August Karlstrom
Are comparisons of character variables and
single-character strings also rejected?
Character variables and single-character strings can be compared. There are specific examples in the Oberon-07 Report confirming this.

--
Chris Burrows
CFB Software
http://www.astrobe.com
August Karlstrom
2017-10-22 20:45:50 UTC
Permalink
Post by Diego Sardina
Oberon had this sentence: "Strings can be assigned to and *compared* with arrays of characters". This was a sort of concession because string literals are allocated in memory as array of characters, so at the end they could be used that way.
But this assumption was considered wrong because it reflects a particular underlying implementation.
But once a string is passed to a procedure it can be compared with a
character array:

PROCEDURE Equal(s, t: ARRAY OF CHAR): BOOLEAN;
RETURN s = t
END Equal

If string constants are not null terminated I guess the parameter
substitution needs to be call by value, e.g. copying the string to the
array parameter.


-- August
Diego Sardina
2017-10-22 22:32:12 UTC
Permalink
Post by August Karlstrom
But once a string is passed to a procedure it can be compared with a
PROCEDURE Equal(s, t: ARRAY OF CHAR): BOOLEAN;
RETURN s = t
END Equal
If string constants are not null terminated I guess the parameter
substitution needs to be call by value, e.g. copying the string to the
array parameter.
I think you can't pass anymore a string literal as a value parameter in Oberon-07.

Oberon had this in 10.1:
"For value parameters, the rule of assignment holds (see 9.1)".

That rule also includes the case of a string literal assigned to an array of characters.

Oberon-07 removed that sentence and with it the general semantic of value parameter as assignment (except in the case the actual is an expression where the result is assigned to the value parameter, of course only in the case of a basic type, as stated 9.2 and 10.1).

Oberon-07 during 2008 had this in 10.1 because CONST was introduced:
"Value parameters must not be of an array or record type".

That was removed later (with CONST parameters), introducing read-only structured value parameters (that are references).

Then Equal("ABC", "abc"); wont't work. You have to assign both strings to variables.

str1 := "ABC";
str2 := "abc;
Equal(str1, str2);

If you have followed Oberon Mailing list, in Oberon-07 there is no copy of structured parameters in any case.


--
Diego Sardina
c***@gmail.com
2017-10-23 07:45:47 UTC
Permalink
Post by Diego Sardina
Then Equal("ABC", "abc"); wont't work. You have to assign both strings to variables.
str1 := "ABC";
str2 := "abc;
Equal(str1, str2);
If you are suggesting that you cannot pass a string constant as an actual value to a value parameter defined as ARRAY OF CHAR then I have to disagree with you. There are numerous examples of this in the tutorial 'Programming in Oberon' (last updated in 2014).

Note the quote that applies to the Report: 'Make it as simple as possible, *but not simpler*'

Regards,
Chris Burrows
CFB Software
http://www.astrobe.com
August Karlstrom
2017-10-23 09:56:54 UTC
Permalink
Post by c***@gmail.com
Post by Diego Sardina
Then Equal("ABC", "abc"); wont't work. You have to assign both strings to variables.
str1 := "ABC";
str2 := "abc;
Equal(str1, str2);
If not being able to compare strings with character arrays is
inconvenient, this is unacceptably inconvenient. The new "hello world"
program:

MODULE hello;

IMPORT Out;

VAR
message: ARRAY 16 OF CHAR;

BEGIN
message := "hello, world";
Out.String(message);
Out.Ln
END hello.

Short and sweet!
Post by c***@gmail.com
Note the quote that applies to the Report: 'Make it as simple as possible, *but not simpler*'
Exactly.


-- August
Diego Sardina
2017-10-23 10:53:33 UTC
Permalink
Post by c***@gmail.com
If you are suggesting that you cannot pass a string constant as an actual value to a value parameter defined as ARRAY OF CHAR then I have to disagree with you. There are numerous examples of this in the tutorial 'Programming in Oberon' (last updated in 2014).
PIO has been inconsistent for years and still is because it uses LONGINT that doesn't exist in Oberon-07 (plus other things I don't remember in this moment).
Post by c***@gmail.com
Note the quote that applies to the Report: 'Make it as simple as possible, *but not simpler*'
That doesn't mean being free to misinterpret.

Could you explain me in the transition from Oberon to Oberon-07 where this rule still holds?


--
Diego Sardina
August Karlstrom
2017-10-23 11:37:35 UTC
Permalink
Post by Diego Sardina
Post by c***@gmail.com
Note the quote that applies to the Report: 'Make it as simple as possible, *but not simpler*'
That doesn't mean being free to misinterpret.
Section 9.2 of the language report:

"If the parameter is a value parameter, the corresponding actual
parameter must be an expression. This expression is evaluated prior to
the procedure activation, and the resulting value is assigned to the
formal parameter which now constitutes a local variable."

The word "assigned" suggests that the rules of assignment applies.
Post by Diego Sardina
Could you explain me in the transition from Oberon to Oberon-07 where this rule still holds?
It's impossible to say since the language report is underspecified.
Personally, I think the line is crossed when the language becomes
embarrassingly inconvenient to use.


-- August
c***@gmail.com
2017-10-23 22:03:34 UTC
Permalink
Post by Diego Sardina
Post by c***@gmail.com
If you are suggesting that you cannot pass a string constant as an actual value to a value parameter defined as ARRAY OF CHAR then I have to disagree with you. There are numerous examples of this in the tutorial 'Programming in Oberon' (last updated in 2014).
PIO has been inconsistent for years and still is because it uses LONGINT that doesn't exist in Oberon-07 (plus other things I don't remember in this moment).
WAS inconsistent for years perhaps. The latest version was significantly updated. What are the 'other things'? Have you reported them to Prof Wirth? He can't fix them if he is not aware of them. I have found him to be very grateful whenever I have reported any proofreading corrections.
August Karlstrom
2017-10-23 10:05:24 UTC
Permalink
Post by Diego Sardina
Oberon had this sentence: "Strings can be assigned to and *compared* with arrays of characters". This was a sort of concession because string literals are allocated in memory as array of characters, so at the end they could be used that way.
But this assumption was considered wrong because it reflects a particular underlying implementation.
You can also say "so what". Yes, it reflects a particular implementation
but what is the problem with that?


-- August
Diego Sardina
2017-10-23 11:36:28 UTC
Permalink
Post by August Karlstrom
You can also say "so what". Yes, it reflects a particular implementation
but what is the problem with that?
I don't know, but I'm not the one that defined this as a problem :-) once Wirth replied to me: "The problem is, of course, that strings are (implicitely) regarded and implemented as arrays of characters."

I guess that if you use an implementation that is different from the simple array of characters, then it is better to isolate this costly operation (of conversion) only in assignment.


--
Diego Sardina
August Karlstrom
2017-10-23 11:53:16 UTC
Permalink
Post by Diego Sardina
Post by August Karlstrom
You can also say "so what". Yes, it reflects a particular implementation
but what is the problem with that?
I don't know, but I'm not the one that defined this as a problem :-) once Wirth replied to me: "The problem is, of course, that strings are (implicitely) regarded and implemented as arrays of characters."
I guess that if you use an implementation that is different from the simple array of characters, then it is better to isolate this costly operation (of conversion) only in assignment.
I don't buy this. If we cannot compare a character array with a string,
we need to introduce an auxiliary variable and make sure it has the
right size:

s1: ARRAY 12 OF CHAR

s1 := "some string";
IF s = s1 THEN ... END

This is artificially verbose and less efficient than

IF s = "some string" THEN ... END


-- August
d***@eml.cc
2017-10-23 14:40:26 UTC
Permalink
Post by August Karlstrom
"If the parameter is a value parameter, the corresponding actual
parameter must be an expression. This expression is evaluated prior to
the procedure activation, and the resulting value is assigned to the
formal parameter which now constitutes a local variable."
The word "assigned" suggests that the rules of assignment applies.
This holds only if a value parameter is of a basic type, as stated in 10.1. There is no copy rule applied here.

I neither consider a string an expression, because in Expression 8.1 only variables are considered as operand (I guess that constant designators are considered to be propagated as literal values).
He left "string" in the grammar because it includes single character constants.
Post by August Karlstrom
I don't buy this. If we cannot compare a character array with a string,
we need to introduce an auxiliary variable and make sure it has the
I don't buy it either, I prefer the Component Pascal approach for strings.


--
Diego Sardina
August Karlstrom
2017-10-23 15:20:22 UTC
Permalink
Post by d***@eml.cc
Post by August Karlstrom
"If the parameter is a value parameter, the corresponding actual
parameter must be an expression. This expression is evaluated prior to
the procedure activation, and the resulting value is assigned to the
formal parameter which now constitutes a local variable."
The word "assigned" suggests that the rules of assignment applies.
This holds only if a value parameter is of a basic type, as stated in 10.1. There is no copy rule applied here.
It is still an assignment in an abstract sense.
Post by d***@eml.cc
I neither consider a string an expression,
You mean a multi-character string, right?
Post by d***@eml.cc
because in Expression 8.1 only variables are considered as operand (I guess that constant designators are considered to be propagated as literal values).
This makes no sense to me.
Post by d***@eml.cc
He left "string" in the grammar because it includes single character constants.
Section 8.1 says:

"With the exception of sets and literal constants, i.e. numbers and
strings, operands are denoted by designators."

It doesn't say "single-character strings".


-- August
c***@gmail.com
2017-10-23 21:57:14 UTC
Permalink
Post by d***@eml.cc
I neither consider a string an expression, because in Expression 8.1 only variables are considered as operand (I guess that constant designators are considered to be propagated as literal values).
He left "string" in the grammar because it includes single character constants.
Are you serious?
Diego Sardina
2017-10-24 16:55:08 UTC
Permalink
Post by c***@gmail.com
Are you serious?
Yes, what is the type of "abc"? What operations are defined for it? If you know nothing about it, how do you put something like this in an expression?

The only known operation is the compatibility in assignment with array of characters.

What allowed the possibility of passing literal strings as parameters was the assignment rule for value parameters, that was ruled out in Oberon-07 (except for basic types).


But I'm happy that you don't have doubts about it, for me reasoning and understanding are important.


--
Diego Sardina
c***@gmail.com
2017-10-24 21:28:22 UTC
Permalink
Post by Diego Sardina
Yes, what is the type of "abc"?
As you quoted earlier:

'...strings are (implicitely) regarded and implemented as arrays of characters"
August Karlstrom
2017-10-25 07:51:53 UTC
Permalink
Post by Diego Sardina
Post by c***@gmail.com
Are you serious?
Yes, what is the type of "abc"?
I think of a string literal as having type `string'. It's like the
opposite of BYTE in the sense that there are only constants of this type
but no variables.
Post by Diego Sardina
What operations are defined for it?
We can't tell simply by reading the language report. In my book, except
being assigned to character array variables, string literals must be
allowed to be passed as actual value parameters and be compared with
character array variables. This is how strings work in Oberon-2.
Anything less makes the language artificially inconvenient to use and is
more in line with "Make it as simple ass possible and then simpler".

If you know nothing about it, how do you put something like this in an
expression?

The same argument can be applied to NIL. It is never mentioned
explicitly that NIL can be compared with pointer or procedure variables.


-- August
Diego Sardina
2017-10-25 09:25:14 UTC
Permalink
Post by c***@gmail.com
'...strings are (implicitely) regarded and implemented as arrays of characters"
Indeed this doesn't mean strings ARE array of characters.
Post by c***@gmail.com
The same argument can be applied to NIL. It is never mentioned
explicitly that NIL can be compared with pointer or procedure variables.
You are right here, indeed in Oberon-2 they added at the end:
"The relations = and # also apply to BOOLEAN and SET, as well as to pointer and procedure types (including the value NIL)."


Guys, there is a reason why they improved Oberon-2 report in term of definitions and clarity in a lot of points. That means there was a *concrete problem* while reading the report.


--
Diego Sardina
c***@gmail.com
2017-10-25 12:23:55 UTC
Permalink
Post by Diego Sardina
Indeed this doesn't mean strings ARE array of characters.
Loading...