February 09, 2006
On Wed, 8 Feb 2006 13:10:19 -0800, Walter Bright wrote:

> The problem with some sort of immutable data type is there are at least a dozen different ways to do it. A lot more thinking has to go into this, less we get stuck with a poor design like C++'s.

This is an encouraging response, Walter. Previously I was under the distinct impression that the whole idea of having the D language help coders deal with concept of immutable data was against your philosophy. This note of yours seems to be saying that you can see it happening in D, but only after the right amount of thinking about 'how to do it well' has occurred.

-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
"Down with mediocracy!"
10/02/2006 10:09:47 AM
February 09, 2006
Andrew Fedoniouk wrote:
> 
> For the team it is a way to reduce needed documentation for example - quite
> opposite to your situation.
> 
> C++ and C99 has "char[]" and "const char[]" which are  two distinct types.

Frankly, I have far more problems with people just not writing meaningful code.  For example:

class C {
public:
    Thing* getThing();
};

Who owns the Thing returned by C?  And is Thing even dynamically allocated?  auto_ptr was designed for this purpose, but no seems to use it correctly:

class C {
public:
    std::auto_ptr<Thing> getThing();
};

Here, the transferral of ownership indicated by the syntax, as is the fact that Thing was allocated on the heap.

The same could be said of const qualifiers.  In my experience, little thought often goes into what is made 'const' and what isn't, and deciphering this later is a maintenance nightmare.  Pointers are another problem area, as many people don't seem aware that "int const *const" is a legal statement, or know what the position of each 'const' implies.

In summary, I agree that 'const' can be useful in Ivory Tower type programming.  But unfortunately, I seem to keep being called out to the docks.  If someone can come up with a form of immutability that is both elegant and meaningful I'll be cheering for its inclusion in D.  But I'm beginning to agree with Walter that the C++ implementation can deceptive, which greatly reduces its utility.


Sean
February 09, 2006
As much as I like the notion of immutable arrays, it is a tough proposition in a language that directly exposes memory to the programmer using pointers.

For an object-oriented language with a GC, I would propose a class-based solution for immutable objects. They are good candidates for sharing, so allocation on the heap will be frequent. In other words, the class overhead is justifiable.

I think I'm on Walter's side regarding const; also for simplicity's sake.

Matthias

Andrew Fedoniouk wrote:
> "Charles" <noone@nowhere.com> wrote in message news:dsfnlr$247h$1@digitaldaemon.com...
>> I'd like to add that from my 6 years with C++, I have never been _saved_ (
>> to my knowledge -- knock on wood ) by const.  And I must have typed it
>> thousands of times .
>>
>> Not that Im voting against immutability, only that if it does get added its
>> as non-intrusive as possible.  But I really don't want to start another
>> debate!
>>
> 
> Well it is different point of view and it is perfectly valid. For you and for me.
> 
> The thing is simple: const is a declartion - meta information if you wish.
> const is more collaborative tool than probably anything else.
> 
> It is seems like for Walter too - const worth nothing because he is working
> on his own codebase and he knows *his own* code very well.
> 
> But we have completely different story in team projects.
> 
> See, partner developers from China will send us class:
> 
> class Record
> {
>     Field[] fields();
> }
> 
> Do you have any idea of how you can use this fields?
> Can you change fieldset or not?
> 
> Again, for a lone-code-wolf writing 50000 lines code in three months
> const is (probably) just nothing if not worse - more chars to type.
> 
> For the team it is a way to reduce needed documentation for example - quite
> opposite to your situation.
> 
> C++ and C99 has "char[]" and "const char[]" which are  two distinct types.
> 
> D has only one char[]. Step back? Yes.
> 
> Again, it seems that having readonly array  type (like  char#[] ) will allow
> to reduce problem significantly. For classes and objects you can create
> readonly envelopes, but arrays are naked in this regard.
> 
> You can create as many meta programming features as you wish but
> without such basic feature your type system is just
> 
> 
> Andrew.
> 
> 
> 
February 10, 2006
"Sean Kelly" <sean@f4.ca> wrote in message news:dsgie6$2lap$1@digitaldaemon.com...
> Andrew Fedoniouk wrote:
>>
>> For the team it is a way to reduce needed documentation for example -
>> quite
>> opposite to your situation.
>>
>> C++ and C99 has "char[]" and "const char[]" which are  two distinct types.
>
> Frankly, I have far more problems with people just not writing meaningful code.  For example:
>
> class C {
> public:
>     Thing* getThing();
> };
>
> Who owns the Thing returned by C?  And is Thing even dynamically allocated?  auto_ptr was designed for this purpose, but no seems to use it correctly:
>
> class C {
> public:
>     std::auto_ptr<Thing> getThing();
> };

Let's say you need to create bullet-proof library of the things Then it is just enough to declare:

class Thing
{
    package ~this();
}

Having this no one  auto_ptr will accept it and user will get an idea that this Thing is managed by Things package. No documentation needed and compiler will enforce this.

>
> Here, the transferral of ownership indicated by the syntax, as is the fact that Thing was allocated on the heap.

Yep, "Show me your destructor and I will tell you what policy do you use"

>
> The same could be said of const qualifiers.  In my experience, little thought often goes into what is made 'const' and what isn't, and deciphering this later is a maintenance nightmare.  Pointers are another problem area, as many people don't seem aware that "int const *const" is a legal statement, or know what the position of each 'const' implies.

I understand that this const * (const *) notation in C++ is just a ... you
know what.
Trust me, I understand Walter's concerns and know them too well.

>
> In summary, I agree that 'const' can be useful in Ivory Tower type programming.  But unfortunately, I seem to keep being called out to the docks.  If someone can come up with a form of immutability that is both elegant and meaningful I'll be cheering for its inclusion in D.  But I'm beginning to agree with Walter that the C++ implementation can deceptive, which greatly reduces its utility.

Let me remind that idea of "practical immutability" again:

1) Now in D any user type (structure, class) can be designed to be explictly
immutable -
    if you want some class of the package be immutable outside - declare
    all its mutating methods with package attribute. Simple and is already
there.

2) arrays.  array is a builtin *structure* in D with its own set of
operations:
    There is no mechanism in D to declare readonly array.
    Proposals:  a)  to introduce readonly array type e.g. as type#[].
                      b) -or- provide  another way (e.g. extended typedef)
                           to explicily list operations allowed on the array
type.

3) pointers. The same problem and similar solution:
    Introduce new readonly pointer type, e.g. #*  e.g.
    type#* rop;
    so *rop cannot serve l-value purposes.

Implementation is simple, notation is simple - can be implemented reliably.



Andrew Fedoniouk.
http://terrainformatica.com



February 10, 2006
Walter Bright wrote:
> 
> The problem with some sort of immutable data type is there are at least a dozen different ways to do it. A lot more thinking has to go into this, less we get stuck with a poor design like C++'s. 
> 
> 

Can someone tell more about what's wrong and/or what could be better with C++'s design(const)?


-- 
Bruno Medeiros - CS/E student
"Certain aspects of D are a pathway to many abilities some consider to be... unnatural."
February 10, 2006
In article <dsil1d$1gs8$1@digitaldaemon.com>, Bruno Medeiros says...
>
>Walter Bright wrote:
>> 
>> The problem with some sort of immutable data type is there are at least a dozen different ways to do it. A lot more thinking has to go into this, less we get stuck with a poor design like C++'s.
>> 
>> 
>
>Can someone tell more about what's wrong and/or what could be better with C++'s design(const)?

The issue is quite subjective.  It depends on what you consider 'wrong'.

IMHO, const appears to be the way most of to many developers because that's what its for.  By its very nature, it is purposefully designed to make your life harder all in the name of data integrity.

Now how it accomplishes that job and wether or not its doing it well is totally up to debate.  Personally, I find API authors abusing 'const' nearly as much as API users abusing 'const_cast' so its kind of a toss-up.

---------------

As for D: if there was some way to impose the COW idiom on assigning from const to non-const, then I think we'd have a superior solution.  At a minimum this would require const to only apply to primitive/scalar types which seems acceptable: classes and structs at least have a way to protect their internals via methods.

I'd also like to see 'readonly' used in favor of 'const'.  A 'writable' modifier would also make template programming easier, due to its symmetry (see below)

> // to summarize the above:
>
> readonly char[] x = "hello world";
> char[] y = cast(char[])x; // Explicit cast from readonly triggers COW idiom
> 
> y[0..$] = "byebye world"; // legal (working with a copy of x)
> x[0..$] = "byebye world"; // illegal (readonly)
> 
> readonly Foobar a = new Foobar(); // illegal: readonly not applicable to classes
> 
> // example of using 'writable' (spoof of the ol' const-cast)
> template(writable T) const_cast{
>   T foobar(readonly T arg){
>     return cast(writable)arg;
>   }
> }

- Eric Anderton at yahoo
February 11, 2006
"Bruno Medeiros" <daiphoenixNO@SPAMlycos.com> wrote in message news:dsil1d$1gs8$1@digitaldaemon.com...
> Walter Bright wrote:
>> The problem with some sort of immutable data type is there are at least a dozen different ways to do it. A lot more thinking has to go into this, less we get stuck with a poor design like C++'s.
> Can someone tell more about what's wrong and/or what could be better with C++'s design(const)?

"const" has many possible meanings:

1) is the data immutable and set at compile time, so it could be put in ROM?
2) is the pointer itself const, or is the data it points to const?
3) does const mean write-once, i.e. can it be initialized at runtime?
4) can other references to the same data change it?
5) can "constness" be cast away?
6) if one has a "const" array of objects, is the array reference const, the
array contents const, or are the object contents const? What about what
those objects refer to?
7) what about "logical" constness, where data can appear to be constant but
has, in actuallity, "mutable" state? (see C++ "mutable" keyword)

And, of course, every combination of the above.


February 11, 2006
"Walter Bright" <newshound@digitalmars.com> wrote in message news:dsjq1j$5rv$2@digitaldaemon.com...
>
> "Bruno Medeiros" <daiphoenixNO@SPAMlycos.com> wrote in message news:dsil1d$1gs8$1@digitaldaemon.com...
>> Walter Bright wrote:
>>> The problem with some sort of immutable data type is there are at least a dozen different ways to do it. A lot more thinking has to go into this, less we get stuck with a poor design like C++'s.
>> Can someone tell more about what's wrong and/or what could be better with C++'s design(const)?
>
> "const" has many possible meanings:
>
> 1) is the data immutable and set at compile time, so it could be put in
> ROM?
> 2) is the pointer itself const, or is the data it points to const?

In C/C++ declaration of const pointer is like this:

const typename *  -or-
typename const *

this is just bad - two tokens used in arbitrary order (who invented this?) for declaration of const-ptr.

Proposed schema of readonly pointers uses single token '#*' type #* p;

> 3) does const mean write-once, i.e. can it be initialized at runtime?

void foo( bar #* p )

means that in scope of function foo
 '*p' cannot be an l-value.

> 4) can other references to the same data change it?

yes.

> 5) can "constness" be cast away?

yes. cast is a brute force and last resort but usable. Even Prof. Niklaus Wirth agree with this.

> 6) if one has a "const" array of objects, is the array reference const, the array contents const, or are the object contents const? What about what those objects refer to?

bar #[] ar;

means that type 'bar #[]' has no operations changing content of the array's raw data (in range ptr...ptr+length ) and pseudo fields ptr and length cannot be changed.

Implication:  its pseudo variable ptr is type of bar #*


> 7) what about "logical" constness, where data can appear to be constant but has, in actuallity, "mutable" state? (see C++ "mutable" keyword)

This is not applicable in D. All objects (instances of some class) are
mutable
by definition.

>
> And, of course, every combination of the above.

Well, not too much left.
The only problem I see is what to do
with structures:

struct myst
{
   int a;
   void m(int b) {  a = b; }
}

myst# *pms = ...;
myst ms = ...;

I think this would be enough:

pms.a = 1; // compile time error - attempt to modify data at location
pointed by readonly pointer.
- but -
pms.m(2); // is fine - author of the type provided explicit mutator.

ms = *pms; // is fine - creation of local copy of the variable with
                    // possible modification of that copy.

Andrew Fedoniouk.
http://terrainformatica.com












February 11, 2006
>
> I'd also like to see 'readonly' used in favor of 'const'.  A 'writable'
> modifier
> would also make template programming easier, due to its symmetry (see
> below)
>
>> // to summarize the above:
>>
>> readonly char[] x = "hello world";
>> char[] y = cast(char[])x; // Explicit cast from readonly triggers COW
>> idiom
>>
>> y[0..$] = "byebye world"; // legal (working with a copy of x)
>> x[0..$] = "byebye world"; // illegal (readonly)
>>
>> readonly Foobar a = new Foobar(); // illegal: readonly not applicable to classes
>>
>> // example of using 'writable' (spoof of the ol' const-cast)
>> template(writable T) const_cast{
>>   T foobar(readonly T arg){
>>     return cast(writable)arg;
>>   }
>> }
>

Exactly.

Thought about decorations:

In phrase 'readonly char[]'  readonly is in fact a part of array type
modifier ([])
so semanticly speaking it should look like 'char readonly []' -
in short : "char #[]" where '#' means exactly "no-assignment allowed".

Second one about "Explicit cast from readonly triggers COW idiom"

I think that cast should be a cast as it is now.
dup is already there for that purposes. No?

Andrew.










February 11, 2006
In article <dsk7ch$qmm$1@digitaldaemon.com>, Andrew Fedoniouk says...
>
>>
>> I'd also like to see 'readonly' used in favor of 'const'.  A 'writable'
>> modifier
>> would also make template programming easier, due to its symmetry (see
>> below)
>>
>>> // to summarize the above:
>>>
>>> readonly char[] x = "hello world";
>>> char[] y = cast(char[])x; // Explicit cast from readonly triggers COW
>>> idiom
>>>
>>> y[0..$] = "byebye world"; // legal (working with a copy of x)
>>> x[0..$] = "byebye world"; // illegal (readonly)
>>>
>>> readonly Foobar a = new Foobar(); // illegal: readonly not applicable to classes
>>>
>>> // example of using 'writable' (spoof of the ol' const-cast)
>>> template(writable T) const_cast{
>>>   T foobar(readonly T arg){
>>>     return cast(writable)arg;
>>>   }
>>> }
>>
>
>Exactly.
>
>Thought about decorations:
>
>In phrase 'readonly char[]'  readonly is in fact a part of array type
>modifier ([])
>so semanticly speaking it should look like 'char readonly []' -
>in short : "char #[]" where '#' means exactly "no-assignment allowed".
>
>Second one about "Explicit cast from readonly triggers COW idiom"
>
>I think that cast should be a cast as it is now.
>dup is already there for that purposes. No?

I disagree.  Readonly means more than "don't assign to me".  It should also mean, "the data I point to is protected".  Sure, you could emulate this with a dup but its much cleaner if it is an assumed operation when casting to and from readonly*.

One of the pitfalls of the C's const design was that the best that could possibly be accomplished by the complier is a static cast.  In D, we have a garbage collector, so we can automatically enforce the readonly integrity of the original const data by performing a copy on cast.  This will lead to fewer errors and make things more failsafe by strictly maintaining readonly and writable sets of data.**

Also, the '#' symbol is reserved by the lexer for compiler directives.  Using it in the way you suggest makes D's syntax context-sensitive; something that Walter has been quite adamant about avoiding.  For instance, how would you expect the following to compile?

> char
> #[] foobar;

IMO, we're better off using no-nonsense modifiers like 'readonly' and 'writeable' as there's zero room to debate what they actually mean, or how to parse them.

* Casting from writable to readonly should also copy as to ensure that writable and readable data remain distinct and protected.  I'd anticipate that .dup on array operations would also inherit the parent's readonly/writable attributes, so slices would have to be cast in a similar way.  This would ensure that aliases to readonly data would in themselves be readonly.

** Of course you can always throw caution to the wind by casting through void*, which would avoid any copying by not explicitly casting to/from readonly.

- Eric Anderton at yahoo