Exported pointer variables

Topics related to the use of Oberon language features
augustk
Posts: 54
Joined: Mon Sep 05, 2011 5:21 pm
Location: Sweden

Exported pointer variables

Post by augustk » Mon Jan 30, 2012 3:11 pm

Consider the following two modules:

Code: Select all

MODULE M;

   TYPE
      T* = POINTER TO RECORD
         x*: INTEGER
      END;

   VAR t*: T;

BEGIN
   NEW(t);
   t.x := 0
END M.

MODULE Client;
   
   IMPORT M;

   PROCEDURE P*;
      VAR t1: M.T;
   BEGIN
      (*this line does not compile...*)
      M.t.x := 1;
      
      (*...however, these do*)
      t1 := M.t;
      t1.x := 1
   END P;

END Client.
The compiler tells me that M.t.x is read-only but I reason that only M.t is read-only. Am I missing something or is this a compiler bug?

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

Re: Exported pointer variables

Post by cfbsoftware » Mon Jan 30, 2012 9:23 pm

That is how it is intended to behave. A read-only record is just that. It cannot be modified outside of the module where it is declared - neither by an attempt to modify the entire record in a single assignment, or by attempts to modify elements of the record with separate assignments.

t1 is different. It is a local variable, not an imported variable, so it is not read-only.

If you want to assign a value to M.t.x in a module that imports M you will need to do so in a procedure that is exported from M, for example:

Code: Select all

MODULE M;

   TYPE
      T* = POINTER TO RECORD
         x*: INTEGER
      END;

   VAR t*: T;

   PROCEDURE Setx*(value: INTEGER);
   BEGIN
     t.x := value
   END Setx;

BEGIN
   NEW(t);
   t.x := 0
END M.

MODULE Client;
   
   IMPORT M;

   PROCEDURE P*;
   BEGIN
      (* M.t.x := 1; *)
      M.Setx(1)
   END P;

END Client.

augustk
Posts: 54
Joined: Mon Sep 05, 2011 5:21 pm
Location: Sweden

Re: Exported pointer variables

Post by augustk » Tue Jan 31, 2012 7:22 pm

My last reply in this thread seems to have disappeared. Anyway, my standpoint is that the inability to modify an exported field though an exported pointer (as in my example) represents a minor compiler bug. In a typical scenario, however, I imagine that an exported pointer will refer to a record with no exported fields.

(By the way, when it comes to export of variables I would also have liked to be able to export character arrays which makes sense since strings can be exported.)

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

Re: Exported pointer variables

Post by cfbsoftware » Tue Jan 31, 2012 8:22 pm

Sorry - I accidentally overwrite your reply when attempting to reply to it. Post it again if you like.

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

Re: Exported pointer variables

Post by cfbsoftware » Wed Feb 01, 2012 11:16 am

augustk wrote:... my standpoint is that the inability to modify an exported field though an exported pointer (as in my example) represents a minor compiler bug
That is not correct. Unless I have misunderstood what you are saying I believe you have 'got the wrong end of the stick'. The system is designed to try to prevent you from modifying an element of an exported record variable - that part is working fine.

What is a problem is that you can modify an element of an exported record variable by accessing it via an aliased pointer as you have shown.

My reasoning is as follows:

In general the priciples of 'information hiding' make it undesirable to allow the export of variables from a module. A variable should only be accessible to a client module via an exported 'getter' (read) or 'setter' (write function). The latter allows any changes to the variable to be validated (e.g. check that it is within an allowable range) by the defining module.

However, for Oberon, this was considered to be too cumbersome and / or involved significant processing overhead for the simple case of scalar variables. Hence, the rule was relaxed by allowing scalar variables to be exported so that they could be read. They can still only be modified via an exported 'setter' (write function).

There was no intention to allow any variable or element of a variable to be changed by a client module except via a setter function.

What you have described is a 'loophole' in the system. Fortunately it is unlikely to happen accidentally in practice as it would be expensive to detect at runtime. The best defence is for the programmer to avoid exporting pointers and to always use getter / setter functions.

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

Re: Exported pointer variables

Post by cfbsoftware » Wed Feb 01, 2012 11:29 am

augustk wrote:(By the way, when it comes to export of variables I would also have liked to be able to export character arrays which makes sense since strings can be exported.)
That does not follow. strings are constants character arrays are variables.

In the case of executables created using Astrobe the difference is really accentuated. Strings and other CONST items are stored in flash rom along with the program code so they cannot be modified, accidentally or otherwise, without reprogramming the flash memory.

Character arrays are stored separately in RAM. If you could export them it would be difficult to detect attempts to modify them particularly as elements of the array can be accessed individually.

augustk
Posts: 54
Joined: Mon Sep 05, 2011 5:21 pm
Location: Sweden

Re: Exported pointer variables

Post by augustk » Wed Feb 01, 2012 4:06 pm

That is not correct. Unless I have misunderstood what you are saying I believe you have 'got the wrong end of the stick'. The system is designed to try to prevent you from modifying an element of an exported record variable - that part is working fine.

What is a problem is that you can modify an element of an exported record variable by accessing it via an aliased pointer as you have shown.
You are correct in that there are two different viewpoints here. My interpretation of the language report is that pointer variables are exported as constants but not the records they point to (a pointer is a scalar but a record is not). Your interpretation is that the constantness also applies to any exported fields in the record that the exported pointer references.
My reasoning is as follows:

In general the priciples of 'information hiding' make it undesirable to allow the export of variables from a module. A variable should only be accessible to a client module via an exported 'getter' (read) or 'setter' (write function). The latter allows any changes to the variable to be validated (e.g. check that it is within an allowable range) by the defining module.

However, for Oberon, this was considered to be too cumbersome and / or involved significant processing overhead for the simple case of scalar variables. Hence, the rule was relaxed by allowing scalar variables to be exported so that they could be read. They can still only be modified via an exported 'setter' (write function).

There was no intention to allow any variable or element of a variable to be changed by a client module except via a setter function.
With this I agree 100%. The solution, as I see it, is to either somehow prevent modification of aliased records or (if the implementation effort is too big) disallow export of pointer variables.

augustk
Posts: 54
Joined: Mon Sep 05, 2011 5:21 pm
Location: Sweden

Re: Exported pointer variables

Post by augustk » Wed Feb 01, 2012 4:36 pm

That does not follow. strings are constants character arrays are variables.
The same can be said about numbers too (literals versus variables). For every basic type an exported constant can be turned into an exported variable if needed. Unfortunately an exported string cannot be turned into an exported character array. For example if we need to change the value of an exported string constant to include double quotes say, it will lead to some code explosion.
Character arrays are stored separately in RAM. If you could export them it would be difficult to detect attempts to modify them particularly as elements of the array can be accessed individually.
I can't see how it would be much harder to keep track of the read-only aspect for an imported (character) array compared to an imported scalar; its identifier will always be present in the designator.

dsar
Posts: 8
Joined: Wed Oct 10, 2012 9:12 pm

Re: Exported pointer variables

Post by dsar » Wed Oct 10, 2012 11:00 pm

Hi,
I've studied the Oberon-07/11 report in depth and my interpretation about the export mark is different.

The report talks about the export mark in three places, in Declarations and scope rules (Ch. 4), Record Types (Ch. 6.3) and Modules (Ch. 11).
In the first one, the export mark refers only to the identifiers of the global scope of the module (no record scope). The Record Types chapter is the only place where the export mark refers to the scope of a record type and the declaration of these elements are called field identifiers more than once (and not just identifiers).
The only place where the report speaks of read only export is the Modules chapter and it refers to identifiers (no field identifiers) of module's scope, and in the case of variables only ones of scalar type, there is no mention to field identifiers or record scope.
In addition, chapters 4 and 6.3 are not semantically changed from Oberon(-1).

I concluded that field identifiers of record types are assignable in the client module, then the statement M.t.x := 1; in the first example should compile, or am I missing something?
Last edited by dsar on Tue Mar 11, 2014 7:15 pm, edited 1 time in total.

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

Re: Exported pointer variables

Post by cfbsoftware » Thu Oct 11, 2012 1:49 am

dsar wrote:The only place where the report speaks of read only export is the Modules chapter
That is the relevant section. It differs from the original Oberon report.
Variables cannot be exported, with the exception of those of scalar types in read-only mode.
What that means is:

1. The only variables that can be exported are those that are defined as scalar types. i.e. variables that are arrays or records cannot be exported.

2. Variables that are defined as scalar types are the only exception. However, even then, they can only be exported in read-only mode.

Also refer to Section 6 Read-only import of variables in Differences between Revised Oberon and Oberon Niklaus Wirth, 22.03.2008 / 15.7.2011

https://www.astrobe.com/wirth/Oberon07.pdf
According to the guidelines of modular programming and information hiding, it is recommended in general to export and import constant objects only. These are constants, data types, and procedures.

Locked