September 11, 2007
I always think of "read only" as meaning "a read only VIEW". Examples abound: e.g. opening a file in read-only mode. Even the read-only attribute of a file (which you can change).

Still - another keyword you might consider appropriate to the meaning "read only view" is "in". Now there's a thought;

Oh - and here's something else I'd like to be able to do. Instead of:

 class C
 {
     private int my_n;
     public int n() { return my_n; }

     /* all my private code refers to my_n */
 }

I'd like to be able to do

 class C
 {
     (privately read-write but publicly read-only) int n;

     /* all my private code refers to n */
 }

That would be cool.
Thanks


September 11, 2007
On Tue, 11 Sep 2007 19:10:29 +1000, Daniel Keep wrote:

> Bill Baxter wrote:
>> Janice Caron wrote:
>>> On 9/11/07, *Janice Caron* <caron800@googlemail.com <mailto:caron800@googlemail.com>> wrote:
>>>
>>>     It's simple, but - I would argue - the wrong choice. A better choice
>>>     (in my humble opinion) would be
>>>
>>>     const = constant
>>>     readonly = read-only
>>>
>>>     If it's not too late to change the keywords, that, to me, would be
>>>     the way to go.
>>>
>>>
>>>
>>> By which I mean, if it's at all feasable to consider ditching the keyword "invariant" altogether, and introducing a new keyword "readonly", then let's do it. "readonly" should indicate a read-only view of data which someone else might modify, and "const" should imply that no-one can modify it ever, no way, nohow.
>>>
>>> I'm not quite sure why no one before now has suggested using "readonly" to mean read-only and "const" to mean constant, but seems kind of a no-brainer to me. You know - calling a thing what it is, instead of something it's not. I know I'd be dead confused if int meant float, for example.
>> 
>> It has been suggested before several times.  The problem is there's disagreement over what it should mean.  To some it is obvious that "readonly" should mean permanently unwriteable, just like "read only memory" is unwriteable.  To others it is equally obvious that it should mean a read-only view of data that is writeable through some other means.
>> 
>> --bb
> 
> The problem is that, broadly speaking, all these words mean the same thing.  Once you get down to splitting hairs over exactly how constant/invariant/immutable/readonly/final something is, you're always going to find some (possibly obscure) argument against the way you want it to work.
> 
> Aren't natural languages fun?!

Therefore let's invent some new keywords, ones that are unlikely to clash with user declared identifiers ...

I'll start this ball rolling.


  'rodata' instead of 'invariant'  (Read Only Data)
  'roview' instead of 'const' (Read Only View)


alias string rodata(char)[];

-- 
Derek Parnell
Melbourne, Australia
skype: derek.j.parnell
September 11, 2007
>
> Therefore let's invent some new keywords, ones that are unlikely to clash with user declared identifiers ...
>

Coined words! Wow - now there's a thought!

brillig = invariant data
slithy = head const
mimsy = read-only view

...with apologies to Lewis Carroll

And that would give us lots of other lovely keywords to play with! Oh my -
frumious, vorpal, uffish, whiffling, tulgey. The possibilities are
boundless!
O frabjous day!

/* This post is in jest */


September 11, 2007
On Mon, 10 Sep 2007 23:15:09 +0400, Walter Bright <newshound1@digitalmars.com> wrote:

> o  const and invariant are transitive. There is no way to specify a (pointer to)(const pointer to)(mutable int).
>

What's wrong with such pointers and why they are disabled by language?

-- 
Regards,
Yauheni Akhotnikau
September 11, 2007
On Tue, 11 Sep 2007 12:09:21 +0100, Janice Caron wrote:

>  class C
>  {
>      private int my_n;
>      public int n() { return my_n; }
> 
>      /* all my private code refers to my_n */
>  }
>  }
> I'd like to be able to do
> 
>  class C
>  {
>      (privately read-write but publicly read-only) int n;
> 
>      /* all my private code refers to n */
>  }
>  }

This would translate to something else coming from Delphi, the "property" tag with the read and write options. You could easily translate this to a D-ish way:


private {
  int my_n;
}

public {
  property int my_n: read my_n;
}


so, whenever you're inside your class, you always have the reference onto the private member. Whenever wanting to read the value of my_n from outside the class, you will get the public member that is just a "wrapper" to the internal one.

But that would make it possible for something like:

private {
  int my_n;

  int get_my_n () {
    // do some calculation that may change the responded value of my_n,
    // for example the object wanting to have the information
    return theCorrectValue;
  }

  void set_my_n () {
    // do some calculation, check the range, whatever
    my_n = theCorrectValue;
  }
}

public {
  property int my_n: read get_my_n write set_my_n
}


Well this looks like a Delphi declaration with C Syntax, so i I guess it might not make it into D ;-) Apart from that it would cover your problem with "internal RW-access, external R-access only".



-- 
.71
nicolai dot waniek at sphere71 dot com

September 11, 2007
On 9/11/07, Nicolai Waniek <nospam@inval.id> wrote:
>
> Apart from that it would cover your problem
> with "internal RW-access, external R-access only".
>

I think you may have missed the point there. We can already do that with D. I /have/ no problem with "internal RW-access, external R-access only". There is no problem to solve. Nonetheless, it would still be cool if there were a new keyword or some other way to mean:

 privately_readwrite_but_publicly_readonly int x;

See?

I already know how to do it without the "privately_readwrite_but_publicly_readonly" keyword.


September 11, 2007
Daniel Keep wrote:
>> Janice Caron wrote:
>>>
>>>     It's simple, but - I would argue - the wrong choice. A better choice
>>>     (in my humble opinion) would be
>>>
>>>     const = constant
>>>     readonly = read-only
>>>
> 
> The problem is that, broadly speaking, all these words mean the same
> thing.  Once you get down to splitting hairs over exactly how
> constant/invariant/immutable/readonly/final something is, you're always
> going to find some (possibly obscure) argument against the way you want
> it to work.
> 
> Aren't natural languages fun?!

They are. The meaning of words is very domain dependent is often based on convention rather than anything else.

I am sorry, but I can't pass this chance to present my side of the argument once more. :)

To an electrical engineer, "read-only" will surely give an association of memory that is "hard to change quickly or easily" (wikipedia), or maybe read-only pins, or read-only registers.

To a mathematician, "constant" is a fixed value, the opposite of a "variable".

In computer science, read-only could have a number of meanings. The top search results on citeseer for read-only yields the following terms:

* read-only transactions
* read-only memory
* read-only file system
* read-only query
* read-only fields
* read-only methods
* read-only replication
* read-only access
* read-only parameters
* read-only actions
* read-only state
* read-only optimizations
* read-only file

of which "read-only memor(y|ies)" corresponds to a mere 3.7 % of the papers, while "read-only transaction(|s)" corresponds to 29 %.

The prevailing meaning of read-only in CS seems to be that in regard to access. Using read-only in the meaning of access will also not conflict with existing uses (even for an electrical engineer). On the other hand, using "const"(ant) in the meaning of something that may change, or is only access protected does conflict with the mathematical definition.

It is therefore, in my view, obvious that substituting the words (readonly,const) for todays (const,invariant) would result in a much better match between the semantics of D and that of established and natural languages.

The crucial separation here is:
* read-only -> access
* constant -> data

Does the following conversation make sense?

A: "I have a function that requires a read-only reference to some data"
B: "Fine, I can use it for both my variable and my constant data"

-- 
Oskar
September 11, 2007
Bruce Adams wrote:
> Sean Kelly Wrote:
> 
>> Walter Bright wrote:
>>> Bruce Adams wrote:
>>>>>> o  So, we still need a method to declare a constant that will not
>>>>>>  consume memory. We'll co-opt the future macro syntax for that:
>>>>>>
>>>>>> macro x = 3; macro s = "hello";
>>>> I'm not clear why this is even needed. Surely "static const" implies
>>>> some level of don't consume any memory by virtue of meaning
>>>> "available at compile time". If you need more than that, rather than
>>>> trusting the compiler then I second "inline" rather than macro, but
>>>> honestly I can't think of an example where this will give you a
>>>> worthwhile performance gain (unlike an inline function).
>>> windows.h in all its terrifying glory has 10,000 macro declarations. If each one occupied 4 bytes of static data, there's 40K of bloat in every exe.
>> That sounds about right.  When we converted const values to enum values in the Tango Win32 headers, app size dropped by roughly 46k.  But there were issues with some of those enum values having the wrong type (-1 set to int instead of uint), which led to a few strange bugs.
>>
>>
>> Sean
> 
> I seek enlightenmnet for at least two problems with that explanation.
> 
> windows.h is a C binding not a D binding.
> I'm not clear how one translates to the other yet as I've avoided bi-lingual stuff so far. Presumably the D binding is created using htod.

htod works for simple cased.  More complex cases require GregorR's BCD or simply a manual effort.

> I thought D followed the you only pay for what you use philosophy.
> So if I import my windows.d module I will only pay the cost of the
> variables I actually use. My friendly neighbourhoold compiler, being clever, mightl also make an effort to minimise the cost of those too.

D currently links at the file level, so if you use anything in a file you get the whole thing.  Some linkers are able to link at the section level (a piece of a file), but D does not support this yet (see comments regarding gc-sections using ld, I believe--there's an issue in BugTracker about this).

> While we're on the subject of windows. 40K means nothing. In an embedded system yes. Windows is bloated to the point where 40K in a user application means de nada. (I shudder at the 4Gb games that follow in its wake too). I have know idea where the windows mobile / CE / pocket PC api falls here.

It matters to some people, particularly those coming from C and comparing EXE sizes.  It may not be relevant as far as general development on Windows is concerned, but it's something library developers must take into consideration.


Sean
September 11, 2007
Overall, I like this solution MUCH better than before.  I have some points to make, but let me say thanks for working on this and taking everyone's opinion into account.

"Walter Bright" wrote
> Const, final, invariant, head const, tail const, it's grown into a monster. It tries to cover all the bases, but in doing so is simply not understandable.

Hear hear.

> o  const and invariant now mean "fully const" and "fully invariant", where fully means "head and tail combined":
>
> const int x = 0;   // x is constant
> const int* p = &x;  // neither p nor *p can be changed
> const(int*) p = &x;  // neither p nor *p can be changed
> const(int)* p = &x;  // p can change, *p cannot be changed

What about const(int) x = 0?  I'm guessing the same as const int x = 0?
Is it safe to say that const(T) x is equivalent to const T x?  What about
classes?

> o  tail const of a struct would have to be done by making the struct a template:
>
>   struct S(T) { T member; }
>   S!(int)   // tail mutable
>   S!(const(int)) // tail const
>

I didn't see it brought up by anyone else, so I'll ask.  Did you mean:
struct S(T) { T * member; }
???

Because I always thought tail const had to do with pointers.  If not, can someone please explain the difference between the two structs in Walter's example?

> o  one can construct a template to generically produce tail const or tail invariant versions of a type.

This prevents casting, which from what I can interpret from the previous 2.0 proposal (the monster), you could do.

i.e.

struct MyNiftyPointer(T) {T * ptr; int someOtherCoolValue;}

void myGreatFunction(MyNiftyPointer!(const(int)) x)
{
  // do something that doesn't modify *x.ptr
}

void test()
{
  MyNiftyPointer!(int) p;
  // set up p
  ...
  myGreatFunction(p); // will this compile?
}

Not that I really care much.  You may be able to implement an opImplicitCast that worked around this problem.  Really, I only see this feature being useful for a smart-pointer/array type, so I'm pretty sure I'll never use it.

> o  So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that:
>
>     macro x = 3;
>     macro s = "hello";

First, I don't like the syntax.  I understand it's roots, as #define is now being replaced by macro, but #define seems a more descriptive keyword than macro when trying to define something as being something else.  I agree with Daniel Keep when he said he expected alias.

Second, I'm trying to understand what the real purpose of this is.  Could someone define the different types of memory and why we need different declarations to put things in those different types?  For example, "doesn't consume memory" doesn't make sense to me.  The bytes gotta go somewhere!

Third, how would you define constants that are not implicitly typed, like a structure?  I can see this being useful for something like a configuration table, or a table of CRC values.

-Steve


September 11, 2007
This is a mess!

The examples given do not indicate how references will be taken care of nor do they indicate how to deal with templated functions/methods that change behaviour based on type.

In this method, I want to make toValue final (like Java) if it is a reference, and const if it is a primitive/structure, how do I do that?

void doSomthing(T) (*declare final* T toValue) {

   *whole bunch of common code*

   static if (is(T : someobject)) {
     work with someobject
   }

   static if (is(T == int)) {
     work with int
   }

   static if (is(T == char[])) {
     work with char[]
   }

   ...

   *whole bunch of other common code*
}

In D, there are five main type classes:

1. Primitives (including pointers)
2. Structs - value type
3. Classes - reference semantics
4. Arrays - reference semantics
5. Delegates/Function pointers

Until constness can deal with all types simply (and elegantly), then it should not be introduced. This way leads to C++ and the kitchen sink approach. Java does well because it is not a kitchen sink.

Please demote D2.0 from the front-page and revert back to D1.0 so that new people are not confused with experimental versions.

Regards,

Myron.