www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Why the need for an only const ref?

reply Jesse Phillips <jessekphillips gmail.com> writes:
I've been following the const stuff to learn about it and start thinking 
of applications for it. I've made a post about a suggested syntax for 
declaring different parts const, but I'm starting to wander why a 
constant reference with mutable data is needed. Currently const is 
transitive so a const ref would make const data. I do not see a need for 
syntax change if we don't need this.

What is the need for a X const x which lets you change the object in x 
but not reassign it to another X?
Nov 30 2007
next sibling parent Christopher Wright <dhasenan gmail.com> writes:
Jesse Phillips wrote:
 I've been following the const stuff to learn about it and start thinking 
 of applications for it. I've made a post about a suggested syntax for 
 declaring different parts const, but I'm starting to wander why a 
 constant reference with mutable data is needed. Currently const is 
 transitive so a const ref would make const data. I do not see a need for 
 syntax change if we don't need this.
 
 What is the need for a X const x which lets you change the object in x 
 but not reassign it to another X?

It's helpful when you have complex functions that don't want to rebind their arguments but need to modify them, for one. A common example is a shared buffer: you don't want some class replacing the buffer, since you want everyone using the same one all the time, and you might copy the reference for ease of use. But you want to modify its contents.
Nov 30 2007
prev sibling next sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 11/30/07, Jesse Phillips <jessekphillips gmail.com> wrote:
 What is the need for a X const x which lets you change the object in x
 but not reassign it to another X?

It's not needed at all. What you're describing is "head const", and Walter just ditched it. Head-constness is a purely local thing. It's always possible to do without it. For reference-objects (i.e. classes) you only need mutable ref, mutable data mutable ref, const data const ref, const data because const is transitive in D. For non-reference-objects (i.e. everything else) you only need mutable data const data (...and the same holds for invariant)
Nov 30 2007
parent reply Derek Parnell <derek psych.ward> writes:
On Sat, 1 Dec 2007 06:17:16 +0000, Janice Caron wrote:

 On 11/30/07, Jesse Phillips <jessekphillips gmail.com> wrote:
 What is the need for a X const x which lets you change the object in x
 but not reassign it to another X?

It's not needed at all. What you're describing is "head const", and Walter just ditched it. Head-constness is a purely local thing. It's always possible to do without it.

What is a D code example that catches inadverant reallocations at compile time? char[] Buffer = new char[MAXBUFSIZE]; . . . Buffer ~= "abc"; // Oops. This is not allowed because // the designer wanted to avoid // excess memory allocations. . . . -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Nov 30 2007
next sibling parent reply Derek Parnell <derek psych.ward> writes:
On Sat, 1 Dec 2007 08:33:25 +0000, Janice Caron wrote:

 On 12/1/07, Derek Parnell <derek psych.ward> wrote:
 What is a D code example that catches inadverant reallocations at compile
 time?

Just don't do it. Head const is a purely local thing. The designer of a function knows what it's supposed to do, and if they make it do something stupid, it's a bug

(a) D can't to X (b) To try to do X in D is stupid (c) X is a valid paradigm therefore (d) Wanting D to do X is stupid. I get it now.
    char[] Buffer = new char[MAXBUFSIZE];
    . . .
    Buffer ~= "abc";   // Oops. This is not allowed because
                       // the designer wanted to avoid
                       // excess memory allocations.

Const is transitive in D. Walter says that's not going to change. You just have to deal with it.

Walter, the BD of D, has been known to change his mind. -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Dec 01 2007
parent reply Matti Niemenmaa <see_signature for.real.address> writes:
Janice Caron wrote:
 Walter, the BD of D, has been known to change his mind.

Sorry, I don't understand what BD of D means.

BD is presumably short for "benevolent dictator". -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
Dec 02 2007
parent Walter Bright <newshound1 digitalmars.com> writes:
Matti Niemenmaa wrote:
 Janice Caron wrote:
 Walter, the BD of D, has been known to change his mind.


BD is presumably short for "benevolent dictator".

I thought it meant "Brain Damage".
Dec 03 2007
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Janice Caron wrote:
 On 12/1/07, Derek Parnell <derek psych.ward> wrote:
 What is a D code example that catches inadverant reallocations at compile
 time?

Just don't do it. Head const is a purely local thing. The designer of a function knows what it's supposed to do, and if they make it do something stupid, it's a bug

That's right. Const-correctness is a thing that becomes necessary when crossing API boundaries, it is of only minor utility for local references only.
Dec 03 2007
parent reply Christopher Wright <dhasenan gmail.com> writes:
Janice Caron wrote:
 Ooh, ooh - I just figured out - we DO have head constness in D after
 all! You want a mutable buffer you can't move? No problem! Here's how
 it's done...
 
     private char[] buffer_ = new char[MAXBUFSIZE];
     char[] buffer() { return buffer_; }
 	
     buffer[0] = '+'; /* OK */
     buffer ~= '+'; /* Error */

Right...now just make sure your modules are small. People using this tactic don't have many friends.
Dec 03 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Janice Caron wrote:
 On Dec 3, 2007 2:14 PM, Christopher Wright <dhasenan gmail.com> wrote:
 Right...now just make sure your modules are small. People using this
 tactic don't have many friends.

What's the problem? Read references to buffer get turned into calls to buffer(), and those get /inlined/ by the compiler back to straightfoward reads of buffer_ (which is private). Write references are syntax errors. Seems to me it works a treat. Why does this not make you happy?

I think his point is that private means nothing *within* a module, only between modules. So if you write your program as one big module with that trick then it's basically like you didn't use it at all. --bb
Dec 03 2007
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Janice Caron wrote:
 On Dec 3, 2007 3:05 PM, Bill Baxter <dnewsgroup billbaxter.com> wrote:
 I think his point is that private means nothing *within* a module, only
 between modules.  So if you write your program as one big module with
 that trick then it's basically like you didn't use it at all.

Hmm. But it will work even /without/ the word private. That's really just there for documentation.

Ah, ok. I missed that. So it's the "not-an-lvalue" error you get then? --bb
Dec 03 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 12/1/07, Derek Parnell <derek psych.ward> wrote:
 What is a D code example that catches inadverant reallocations at compile
 time?

Just don't do it. Head const is a purely local thing. The designer of a function knows what it's supposed to do, and if they make it do something stupid, it's a bug
    char[] Buffer = new char[MAXBUFSIZE];
    . . .
    Buffer ~= "abc";   // Oops. This is not allowed because
                       // the designer wanted to avoid
                       // excess memory allocations.

Const is transitive in D. Walter says that's not going to change. You just have to deal with it.
Dec 01 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 12/1/07, Derek Parnell <derek psych.ward> wrote:
 (a) D can't to X
 (b) To try to do X in D is stupid
 (c) X is a valid paradigm

I think the point is the case for head-const as a useful paradigm is very weak. To use your own example. All you have to do is rewrite it like this: char[MAXBUFSIZE] buffer; ... buffer ~= "abc"; // Error Or, if you're passing it to a function, wrap it in a class or struct class Buffer { char[MAXBUFSIZE] buffer; } f(Buffer b) { buffer ~= "abc"; // Error }
 Walter, the BD of D, has been known to change his mind.

Sorry, I don't understand what BD of D means. In any case, I think Walter will change his mind if there is a strong enough case. If this newsgroup shows near-unanimous support, and real-world test cases can be demonstrated. That doesn't seem to be the case here.
Dec 01 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 12/2/07, Janice Caron <caron800 googlemail.com> wrote:
     f(Buffer b)
     {
         buffer ~= "abc"; // Error
     }

f(Buffer b) { b.buffer ~= "abc"; // Also error :-) }
Dec 01 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On Dec 3, 2007 10:35 AM, Walter Bright <newshound1 digitalmars.com> wrote:
 Janice Caron wrote:
 On 12/1/07, Derek Parnell <derek psych.ward> wrote:
 What is a D code example that catches inadverant reallocations at compile
 time?

Just don't do it. Head const is a purely local thing. The designer of a function knows what it's supposed to do, and if they make it do something stupid, it's a bug

That's right. Const-correctness is a thing that becomes necessary when crossing API boundaries, it is of only minor utility for local references only.

Ooh, ooh - I just figured out - we DO have head constness in D after all! You want a mutable buffer you can't move? No problem! Here's how it's done... private char[] buffer_ = new char[MAXBUFSIZE]; char[] buffer() { return buffer_; } buffer[0] = '+'; /* OK */ buffer ~= '+'; /* Error */
Dec 03 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On Dec 3, 2007 2:14 PM, Christopher Wright <dhasenan gmail.com> wrote:
 Right...now just make sure your modules are small. People using this
 tactic don't have many friends.

What's the problem? Read references to buffer get turned into calls to buffer(), and those get /inlined/ by the compiler back to straightfoward reads of buffer_ (which is private). Write references are syntax errors. Seems to me it works a treat. Why does this not make you happy?
Dec 03 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On Dec 3, 2007 3:05 PM, Bill Baxter <dnewsgroup billbaxter.com> wrote:
 I think his point is that private means nothing *within* a module, only
 between modules.  So if you write your program as one big module with
 that trick then it's basically like you didn't use it at all.

Hmm. But it will work even /without/ the word private. That's really just there for documentation. As I understood it, the goal was to catch reallocation bugs at compile time, so, say you have a function that looks like this: void f(char[] buffer) { /*...*/ } you can just change it to void f(char[] buffer_) { char[] buffer() { return buffer_; } /*...*/ } and immediately you get compile-time checking. It's not whether or not you make the original variable private or not that matters, it's just the fact that you must always refer to it by its function-call-name. That's why I added the underscore to the "real" variable, but if that's not a strong enough deterent then make it void f(char[] WARNING_doNotUseThisBuffer) { char[] buffer() { return WARNING_doNotUseThisBuffer; } /*...*/ } (but personally I think the trailing underscore is enough). There's no need for any of this to "spread" to the outside world, because head-constness is only local anyway.
Dec 03 2007
prev sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 12/3/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:
 Ah, ok.  I missed that.  So it's the "not-an-lvalue" error you get then?

I think the error I got was "cannot append to char[]()". So basically, yes.
Dec 03 2007