Read-only array reference

Bruno Medeiros brunodomedeirosATgmail at SPAM.com
Sat Jul 8 13:51:06 PDT 2006


Hasan Aljudy wrote:
> 
> 
> kris wrote:
>> Good idea ~ I'll have a go:
>>
>> Derek Parnell wrote:
>>
>>> I'm not from a C++/C#/Java background, so please excuse my lack of  
>>> understanding about the meaning that is being applied to the term 
>>> 'const'  in these recent discussions.
> 
> I am from a C++/Java background, yet I still don't fully understand const!
> The only thing I understand is that Java doesn't need it because it's 
> higher-level than D, doesn't allow pointer manipulation, and has builtin 
> immutable String class.
> 
> I still don't understand why D needs it, or why do some people think so.
> 
>> <snip>
>>> My requirements for 'const' are almost covered by Walter's new 
>>> proposal.  I'm a quite concerned that if I tell Foo() that it can't 
>>> change something,  that Foo() can still tell Bar() to disregard my 
>>> request and tell Bar()  that it's okay to change it anyway.
>>
>>
>>
>> Yes, that is a notable weakness. Using an aggregate (struct or class) 
>> instead would give you the /propogation/ aspect required. This is in 
>> contrast to Walter's proposal, but requires the use of aggregates 
>> rather than, say, an array. BTW: this whole discussion is basically 
>> about array types, since others can happily be passed by value anyway.
> 
> 
> Then how about introducing a new type: read-only array reference.
> (The idea is inspired by Java's immutable string class)
> 
> It would be a distinct type, but built into the language core.
> It has a different declaration syntax from regular arrays.
> It cannot be casted to anything at all, absolutly no pointer 
> manipulation is allowed either.
> The content of the array cannot be modified (further explanation below).
> The reference itself *can* be modified to refer to another array, but it 
> would still be a read-only reference.
> Any type of regular array reference (dynamic/static/associative) can be 
> converted to a read-only array reference.
> 
> For example, the syntax could be:
> int[$] x; //declare x as a readonly reference to an array of "int"s.
> 
> using the $ might not be the best thing, but please bare with me .. 
> that's not the main point.
> 
>  From now on, I'm gonna assume there's a nice syntax that's consistent 
> with the rest of the D language.
> 
> To ensure that the content of the array cannot be modified, some 
> measures must be taken regarding what happens when you read an element 
> from the array.
> 
> Let's agree first on some terminology:
> Contained Type: if <code> T[$] x; </code> declares a read-only array 
> reference to an array of T's, then T is the contained type.
> 
> Now, in theory, the contained type can either be
> - a native type (int, float, byte ... enums .. etc)
> - a struct
> - a class (reference)
> - an array or a pointer.
> 
> When an element is read from the array, what should we do?
> - if the contained type is a native type or an enum, then a copy of the 
> element is returned.
> - if the contained type is a struct, then a copy is returned.
> 
> That's simple .. but what if the contained type is a class or an array?
> 
> Well, if it's a class, then it's a little bit complicated. I don't even 
> know if we /need/ any kind of guarantees with an array of objects, but 
> anyway!
> Let's assume that we do need this guarantee, and let's take a step back.
> The compiler shouldn't allow the contained type of a read-only array 
> reference to be a class; instead, it should only allow it to be an 
> interface that's derived from a generic (empty) interface called IReadOnly.
> 
> This measure will not allow the compiler to always ensure that objects 
> contained in such a way cannot be modified, however, it gives the author 
> of the class a guarantee that if he subclasses IReadOnly the right way, 
> then his objects won't be modifiable.
> 
> Example:
> ------------------
> interface IImmutableCircle : IReadOnly
> {
>     int radius();
> }
> 
> class Circle : IImmutableCircle
> {
>    private int mradius;
> public:
>    int radius() { returm mradius; }
>    void radius( int r ) { mradius = r; }
> }
> 
> .....
> 
> Circle[$] arr; // error, no class allowed as the contained type for a 
> read-only reference
> IImutableCircle[$] arr; //ok, since IImmutableCircle derives from IReadOnly
> ---------------------------
> 
> Of course the coder can mess up his code and add methods in 
> IImmutableCircle that allow the object to be modified, but the important 
> thing is that that's his own reponsibility; no user of his code can mess 
> this up.
> 
> If there's a loop-hole in this approach, then disregard it. I'm starting 
> to think that the whole issue of protecting objects is unneeded.
> 
> A similar approach can be taken if the contained type is an array.
> Either prevent that and require it to be a read-only array reference, or 
> allow it because preventing it is too complicated or just un-needed.
> 
> So, what do you think about this proposal?
> Is it practical? Does it solve most of the const issues?
> Does it even make sense, or is it just stupid all-together?
> 
> I was gonna post this as a new topic in the main D ng, but I thought it 
> might have been proposed before, so I present it here instead.
> 

Indeed, if I understood correctly, I think your proposal is unpractical, 
if not down-right senseless. :p

Why?
Ok, first, what do we want exactly? We want a mechanism that allows us 
to specify a readonly contract for a variable, that is, declare a 
variable (or function parameter) that should be a "read-only view" 
(using Andrei Alexandrescu's term) of another data/object.

Your proposal allows us to do that, but one has to encapsulate/declare 
the var, inside a "constant array of the type of that var"? Why not just 
declare it as a "constant var of it's respective type"? For example, if 
I want to declare a function that receives a readonly pointer to Object, 
I have to:

   ... func(Object[$] obj) {
      obj[0].doStuff();
Have to access obj as an array, even though it is only one?
Why not just:

   ... func(readonly Object obj) {
      obj.doStuff();

Similarly, on the return type:

   Object[$] func(...) {
     obj2 = new Object();
     ...

     // **** Want to return a readonly obj2: ****
     auto objAR = new Object[$]; // how do I even specify the length??
     // Have to allocate an array and encapsulate obj2 inside it? :
     objAR[0] = obj2;
     return objAR;
   }

instead of just:

   readonly Object func(...) {
     obj2 = new Object();
     ...

     // **** Want to return a readonly obj2: ****
     return obj2;
   }


Plus, your proposal is omissive in many important aspects. For example, 
how about the transitive property? If I have:
   int **[$] ptr;
can I change *(ptr[0]) or **(ptr[0])? Similarly for a struct:
   struct Fuu { int[] iar; }
   Fuu[$] cfuu;
can I change (cfuu[0]).iar[ix] ?  (where ix is some index)

And your method for determining how one can use a readonly object seems 
way cumbersome, a likely less efficient. Having to define an interface 
for each class, with the methods that are allowed in the readonly 
object? Compare this to C++ (and Javari), where you just add a keyword 
to the methods that can be called by a readonly instance:

In C++ it is:
   void aMethod(...) const { ... }

In Javari it is:
   void aMethod(...) readonly { ... }

(Note: basically, what is being done above is specifying the constness 
of the 'this' implicit parameter)

I must quote what I've said in the OP:

Implementing a mechanism such as this is actually quite complex (in 
terms of design itself) because of several special cases which need more 
language constructs. It's not just adding the "immutable" keyword as 
some people seem to think.
To know what I'm talking about exactly one should read this quite 
informative paper:
http://pag.csail.mit.edu/pubs/ref-immutability-oopsla2005-abstract.html
I haven't read it all yet, but I plan to do so soon, since everyone is 
talking about const again. And I would say reading it should likely be 
mandatory for anyone who wants to venture thinking and posting how the 
const system should work. It describes the issues one faces when 
implementing such a system, and the reference immutability system 
described there is perhaps a good starting point for a system for D

Oh, Javari is the Java modification described in that paper, which has 
reference immutability added to the Java language.

-- 
Bruno Medeiros - CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D



More information about the Digitalmars-d-learn mailing list