June 02, 2005
Here are my thoughts - if people would like to hear them :)

1) Everyone that has posted to this thread agrees that there needs to be a language feature that prevents code from changing the value of a variable/array.  Call it readonly, const, whatever.

2) There have been no suggestions on how to actually enforce immutability in a manner that is 100% correct - there are always loopholes that a devious programmer can go through.  From my point of view, the only truely correct way of enforcing constness is to place the memory in question under the protection of the hardware MMU - which IMHO will be very wasteful on memory & probably non-trivial to implement.

3) C++ errors at compile time for const violations and that is generally what people would like from D also.

I think that we need to face reality - there is no easy solution that is actually 100% correct.  However, since D is a practical language we don't need to be 100% correct, we only need enough protection to prevent accidental bugs.  Given a language that allows pointers, a programmer will be able to break constness.  If you need to write a completely robust library that malicious programmers will _try_ to break, then relying on const will never cut it.  You must add your own protection mechanisms - like always duping memory before returning it.  But I would say that this kind of environment is extremely rare.

So I think that a simple const mechanism that aims only to help prevent bugs, and offers no actual assurances about true constness, ought to be enough to satisfy most people.

I am sure that I don't grasp the full implications of how to implement this, but honestly it doesn't sound that hard.  I've attached a simple example that very nearly does simple protection by only using the built-in type system.  If you could implicitly promote char -> const_char then this would pretty much work.

Does this sound workable - or am I being totally naive?

Brad

import std.stdio;

typedef char const_char;

int main (char[][] arg)
{
    char[] plain = "This is a plain char string";
    const_char[] strange = cast(const_char[])"This is a const_char string";

    plain = foo(plain);
    strange = foo(strange);

    // no implicit casting, so the below doesn't work
    //char[] test = strange;
    //const_char[] test2 = plain;
    return 0;
}

char[] foo(char[] f)
{
    // normally, writefln would only take const_char[]'s
    // but char[] would be allowed to be implicitly promoted to const_char[]
    writefln ("char[] is ", f);
    return f;
}

const_char[] foo(const_char[] f)
{
    // normally, writefln would only take const_char[]'s - so
    // wouldn't need to cast
    writefln ("const_char[] is ", cast(char[])f);
    return f;
}
June 02, 2005
"Thomas Kuehne" <thomas-dloop@kuehne.this-is.spam.cn> wrote in message news:h943n2-na4.ln1@lnews.kuehne.cn...
>
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Andrew Fedoniouk schrieb am Thu, 2 Jun 2005 00:38:54 -0700: <snip>
>> Thomas, I am not proposing here any flags changeable in runtime or
>> existing
>> there.
>> I was thinking aloud before about them but not in this message.
>> I did tests already with flags - indeed they do not work in some cases.
>
> The only way I am aware of to enforce const at runtime could be compared to Java's String pool...
>
>> Let's forget about them and focus on just a const type modifier
>>
>> const T[] and T[] has exactly the same binary layout in runtime.
>>
>> The only difference is on compiler level (as in C++).
>> Lets imagine that we have
>>
>> const char[] t = some_other_array;
>>
>> uint find( const char[] where, const char[] what)
>> {
>> .....
>> }
>>
>> uint replace( char[] where, const char[] from, const char[] to)
>> {
>> .....
>> }
>>
>> find(t, "hello"); // fine
>> replace( t, "c++", "d" ); // bang! compile time error : cannot change
>> const
>> value.
>>
>> const type modifier is not to much complicated
>> currently it is supported for scalars. We need to extend it
>> to arrays and pointers with slightly modified meaning.
>> Close to what C++ has. But not exactly.
>
> Now that is the tricky part. ;)
> What would be the const rules for arrays and pointers/references?
> How/When would those rules be checked and/or enfored?

When: In compile time. How: by generating compile time error.

How be checked? Exactly as right now. Imagine that
const char[] is just a typedefed char[].
Can compiler check casting problems of typedefed types now? Yes.
This is it. Don't need anything more here.

The only one thing: string literals are const char arrays by their nature and definition.

See I am clearly expressing my intentions - defining contracts on parameters:
--------------------------------
foo(char[] ms)
foo(const char[] ims)
--------------------------------

const char[] s1 = url.hostname;
char[] s2 = url.hostname; // compile time error - cast to non-const

but this should be possible too (my guess):

char[] s2 = cast(char[]) url.hostname; // const is recomendation, not more!

better to have constcast() for such cases but we can live without that.

Andrew.


















June 02, 2005
"Brad Beveridge" <brad@somewhere.net> wrote in message news:d7nbhs$1p2o$1@digitaldaemon.com...
> Here are my thoughts - if people would like to hear them :)
>
> 1) Everyone that has posted to this thread agrees that there needs to be a language feature that prevents code from changing the value of a variable/array.  Call it readonly, const, whatever.
>
> 2) There have been no suggestions on how to actually enforce immutability in a manner that is 100% correct - there are always loopholes that a devious programmer can go through.  From my point of view, the only truely correct way of enforcing constness is to place the memory in question under the protection of the hardware MMU - which IMHO will be very wasteful on memory & probably non-trivial to implement.
>
> 3) C++ errors at compile time for const violations and that is generally what people would like from D also.
>
> I think that we need to face reality - there is no easy solution that is actually 100% correct.  However, since D is a practical language we don't need to be 100% correct, we only need enough protection to prevent accidental bugs.  Given a language that allows pointers, a programmer will be able to break constness.  If you need to write a completely robust library that malicious programmers will _try_ to break, then relying on const will never cut it.  You must add your own protection mechanisms - like always duping memory before returning it.  But I would say that this kind of environment is extremely rare.
>
> So I think that a simple const mechanism that aims only to help prevent bugs, and offers no actual assurances about true constness, ought to be enough to satisfy most people.

Exactly. And again, we don't need it at the scale it made in C++ . Classes can be protected "by hands",  and in fact protection for class instnaces is already there: setter/getters, private/public, etc.

Again just need const for T[] and T*.

See: char[] is atomic type in terms of that it is builtin in D.
But they are implemented differently from other scalars-
they are references to some memory locations. And this referencing adds
one more 'dimension' requirement - readonlyness.

This is exactly as function parameter attributes: in, out.
Walter said A but is shy to say B.
Or I don't understand something.

Andrew.







>
> I am sure that I don't grasp the full implications of how to implement this, but honestly it doesn't sound that hard.  I've attached a simple example that very nearly does simple protection by only using the built-in type system.  If you could implicitly promote char -> const_char then this would pretty much work.
>
> Does this sound workable - or am I being totally naive?
>
> Brad
>
> import std.stdio;
>
> typedef char const_char;
>
> int main (char[][] arg)
> {
>     char[] plain = "This is a plain char string";
>     const_char[] strange = cast(const_char[])"This is a const_char
> string";
>
>     plain = foo(plain);
>     strange = foo(strange);
>
>     // no implicit casting, so the below doesn't work
>     //char[] test = strange;
>     //const_char[] test2 = plain;
>     return 0;
> }
>
> char[] foo(char[] f)
> {
>     // normally, writefln would only take const_char[]'s
>     // but char[] would be allowed to be implicitly promoted to
> const_char[]
>     writefln ("char[] is ", f);
>     return f;
> }
>
> const_char[] foo(const_char[] f)
> {
>     // normally, writefln would only take const_char[]'s - so
>     // wouldn't need to cast
>     writefln ("const_char[] is ", cast(char[])f);
>     return f;
> }


June 02, 2005
In article <d7nbhs$1p2o$1@digitaldaemon.com>, Brad Beveridge says...
>
>I think that we need to face reality - there is no easy solution that is actually 100% correct.  However, since D is a practical language we don't need to be 100% correct, we only need enough protection to prevent accidental bugs.
..
>So I think that a simple const mechanism that aims only to help prevent bugs, and offers no actual assurances about true constness, ought to be enough to satisfy most people.

My impression of Walter is that he doesn't like solutions that are just okay, particularly if they add significant compiler complexity.  And while I think this is probably feasible for arrays, it's a slippery slope from there to logical const-ness for user defined objects.  Personally, I'll take anything I can get, but I think the likelihood we'll see this for 1.0 is quite slim.


Sean


June 02, 2005
"Sean Kelly" <sean@f4.ca> wrote in message news:d7nkra$22fh$1@digitaldaemon.com...
> In article <d7nbhs$1p2o$1@digitaldaemon.com>, Brad Beveridge says...
>>
>>I think that we need to face reality - there is no easy solution that is actually 100% correct.  However, since D is a practical language we don't need to be 100% correct, we only need enough protection to prevent accidental bugs.
> ..
>>So I think that a simple const mechanism that aims only to help prevent bugs, and offers no actual assurances about true constness, ought to be enough to satisfy most people.
>
> My impression of Walter is that he doesn't like solutions that are just
> okay,
> particularly if they add significant compiler complexity.

Ummm... Is it in fact so complex? I think everything needed is already there.

> And while I think
> this is probably feasible for arrays, it's a slippery slope from there to
> logical const-ness for user defined objects.

Don't need this for UDO. Such objects have all needed for encapsulation/ protection already. Basic types in contrary are naked now. You cannot define methods/envelopes for them. const is not 100% solution in terms of real protection. But there are no 100% solutions at all, even in D. It is a compromise and a good one - it costs nothing in runtime and almost nothing in compile time.

>Personally, I'll take anything I
> can get, but I think the likelihood we'll see this for 1.0 is quite slim.
>

Too bad if we will have not this in 1.0. Without const for arrays and
pointers
D feature set is incomplete. You can write word counters spanning two three
pages
but for serious projects with many developers involved const (especially for
strings)
is must have feature. I am managing GUI projects last 10 years and I am
certain.
Fighting with three bugs in Harmonia  took me one week. Two of them
was about stirng/array corruptions. And I was designing it by myself!
I don't want to share this experience with other team members where
probability of such things is higher.

Again D is a good language. I would say D is near perfect especially for
GUI.
But this particular area (constness of builtin types) is not finished
- as there are no workarounds at all to protect references.
Advices to spread .dups everywhere I will left for .NET/Java community -
there they
will be accepted.

Andrew.


June 02, 2005
"Thomas Kuehne" <thomas-dloop@kuehne.this-is.spam.cn> wrote in message news:a333n2-t84.ln1@lnews.kuehne.cn...
>
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> kris schrieb am Thu, 02 Jun 2005 00:15:46 -0700:
>> Thomas Kuehne wrote:
>>> If the array content is by default immutable - that is, once an element is set it can't be changed - the "mutable" attribute could be used to allow the editing of array elements.
>>
>> Now there's a different idea. Talk about CoW enforcement :-)
>>
>>> In difference to the current system
>>> the compiler could only allow those cases where it can _prove_ that the
>>> array is mutable. What happens if you store pointers/object
>>> references in the array?!
>>
>> Doesn't have to prove anything if the mutable aspect is part of the type; right, Thomas?
>
> This isn't sufficent.
>
> class C{
> <immutable> int i;
> }
>
> void bugger(){
> C c = new C;
> c.i = 2; // **ok**
> <mutable> int* i = &c.i;
> *i = 1; // ***bug**
> }
>
>> Aliases upon the array still have to go through the
>> same type-matching procedure; Yes?
>
> In the sense that "<mutable> t" and "<immutable> t" are two distinct types.
>
>> If you cast an immutable type to a mutable type, then all bets are off; just as they are with *cast(void *)0 = 0;
>
> How about enforcing that immutable types can only be casted to immutable types?
>
> <immutable> type[] a;
> <immutable> void* b = cast(<immutable> void*) a; // legal, the target is
> immutable
> <mutable> void* c = cast(<mutable> void*) a; // illegal, the target is
> mutable.
>
> This isn't sufficent. Let's rewrite the sample.
>
> class C{
> <immutable> int i;
> }
>
> void bugger2(){
> C c = new C;
> c.i = 2; // **ok**

> <immutable> size_t ptrI = cast(<immutabe> size_t)(cast(<immutable> void*))
> &c.i);
> <mutable> size_t ptrM = ptrI;
> <mutable> void* v = cast(<mutable> void*) ptrM;
> <mutable> int* i = cast(<mutable> int*) v;
> *i = 1; // **bug, but legal if mutability is a plain attribute**
> }

class C {
   const int i = 20; // works now and perfectly. it is a compile time
                           // constant and such variable may not have even
                          // location in runtime.
}

The only one:

<immutable> int* ptrI = &someintvar;
*ptrI = 20 ; // here compiler must generate error - is not an l-value.

And this is it. Enough for most cases. Casting, slicing and dicing to remove constness shall be also possible for masochistic use cases.

We shall help good people instead of fighting with bad ones. Only in this case we will have a chance to see transformation of bad guys into good guys.  ( Pure Canadian statement :-)

Andrew.


>
>>> In addition this has some negative impact for mixed closed-open source projects as the compiler would have to treat all arrays comming from the closed source part as immutable.
>>
>> Is it still an issue if third-party code can be declared/proto-typed appropriately?
>
> This would reduce the the protection to a suggestion.
>
> As can be seen: a simple <mutable> attribute isn't a sufficent protection.
>
> The compiler would have to do a quite extensive flow analysis to provide even very limited mutable access.
>
> If the "default <immutable>" is limited to arrays, how deep would the array be protected? What about pointers as array elements?
>
> class D{
> <mutable> int i;
> }
>
> <immutable> D[] o;
> o.length=1;
> o[0]= new D; // **ok**
>
> o[0]= new D; // **bug**
>
> o[0].i = 1; // legal or illegal?
>
> Thomas
>
>
> -----BEGIN PGP SIGNATURE-----
>
> iD8DBQFCnt1K3w+/yD4P9tIRAuebAKCAgW0XGeL7/5QkZ+GmZnwefI+hzQCfdv6B
> isJeMx63fCvqJgoxpQhzKAk=
> =Q3ak
> -----END PGP SIGNATURE----- 


June 02, 2005
In article <d7nmto$24n4$1@digitaldaemon.com>, Andrew Fedoniouk says...
>
>"Sean Kelly" <sean@f4.ca> wrote in message news:d7nkra$22fh$1@digitaldaemon.com...
>> In article <d7nbhs$1p2o$1@digitaldaemon.com>, Brad Beveridge says...
>>>
>>>I think that we need to face reality - there is no easy solution that is actually 100% correct.  However, since D is a practical language we don't need to be 100% correct, we only need enough protection to prevent accidental bugs.
>> ..
>>>So I think that a simple const mechanism that aims only to help prevent bugs, and offers no actual assurances about true constness, ought to be enough to satisfy most people.
>>
>> My impression of Walter is that he doesn't like solutions that are just
>> okay,
>> particularly if they add significant compiler complexity.
>
>Ummm... Is it in fact so complex? I think everything needed is already there.

I don't think it is complex.  I was thinking of object const-ness when I wrote this.  Sorry for the confusion.
>
>> And while I think
>> this is probably feasible for arrays, it's a slippery slope from there to
>> logical const-ness for user defined objects.
>
>Don't need this for UDO. Such objects have all needed for encapsulation/ protection already. Basic types in contrary are naked now. You cannot define methods/envelopes for them. const is not 100% solution in terms of real protection. But there are no 100% solutions at all, even in D. It is a compromise and a good one - it costs nothing in runtime and almost nothing in compile time.

I disagree that UDO have what's needed in terms of protection.  Though logical const-ness is far from simple to implement.


Sean


June 02, 2005
"Sean Kelly" <sean@f4.ca> wrote in message news:d7nod5$263o$1@digitaldaemon.com...
> In article <d7nmto$24n4$1@digitaldaemon.com>, Andrew Fedoniouk says...
>>
>>"Sean Kelly" <sean@f4.ca> wrote in message news:d7nkra$22fh$1@digitaldaemon.com...
>>> In article <d7nbhs$1p2o$1@digitaldaemon.com>, Brad Beveridge says...
>>>>
>>>>I think that we need to face reality - there is no easy solution that is actually 100% correct.  However, since D is a practical language we don't need to be 100% correct, we only need enough protection to prevent accidental bugs.
>>> ..
>>>>So I think that a simple const mechanism that aims only to help prevent bugs, and offers no actual assurances about true constness, ought to be enough to satisfy most people.
>>>
>>> My impression of Walter is that he doesn't like solutions that are just
>>> okay,
>>> particularly if they add significant compiler complexity.
>>
>>Ummm... Is it in fact so complex? I think everything needed is already there.
>
> I don't think it is complex.  I was thinking of object const-ness when I
> wrote
> this.  Sorry for the confusion.

Why sorry? Anyway...

>>
>>> And while I think
>>> this is probably feasible for arrays, it's a slippery slope from there
>>> to
>>> logical const-ness for user defined objects.
>>
>>Don't need this for UDO. Such objects have all needed for encapsulation/ protection already. Basic types in contrary are naked now. You cannot define methods/envelopes for them. const is not 100% solution in terms of real protection. But there are no 100% solutions at all, even in D. It is a compromise and a good one - it costs nothing in runtime and almost nothing in compile time.
>
> I disagree that UDO have what's needed in terms of protection.  Though
> logical
> const-ness is far from simple to implement.

In user defined objects at least you can say 'protect'. Protect
some operations and functions from outside
This is compile time protection and not runtime! . In runtime you can
relatively easy get a pointer to private variable and change it outside.

Following logic that we cannot reach 100% protection we shall remove this 'private', 'package' etc. What for they were introduced? They are not 100% protecting!.

You can do dynamic protection for UDO : you can naturally
implement:
"in this particular state of object
this particular property is immutable, etc." Right?

What we all want to have is simple:
"by using const for arrays and pointers we want to make
some methods of const types 'private' - not accessible". This is it.


>
>
> Sean
>
> 


June 02, 2005
Ok, side question, assume we're going to use 'const' (or any keyword) for array contents (something I've asked for in the past), how do we write it?

As it stands:
  const char[] bob;

'currently' makes the "array reference" constant. Would we then need:
  char[] const bob;

or perhaps
  char[const] bob;

or maybe as it's const it has to have an initialiser:
  char[] bob = "test";

(assuming of course that "test" is automatically constant)
or would that give an error and require the const keyword somewhere, as in one of the first two ideas.

Regan

On Thu, 2 Jun 2005 13:48:06 -0700, Andrew Fedoniouk <news@terrainformatica.com> wrote:
> "Sean Kelly" <sean@f4.ca> wrote in message
> news:d7nod5$263o$1@digitaldaemon.com...
>> In article <d7nmto$24n4$1@digitaldaemon.com>, Andrew Fedoniouk says...
>>>
>>> "Sean Kelly" <sean@f4.ca> wrote in message
>>> news:d7nkra$22fh$1@digitaldaemon.com...
>>>> In article <d7nbhs$1p2o$1@digitaldaemon.com>, Brad Beveridge says...
>>>>>
>>>>> I think that we need to face reality - there is no easy solution that is
>>>>> actually 100% correct.  However, since D is a practical language we
>>>>> don't need to be 100% correct, we only need enough protection to prevent
>>>>> accidental bugs.
>>>> ..
>>>>> So I think that a simple const mechanism that aims only to help prevent
>>>>> bugs, and offers no actual assurances about true constness, ought to be
>>>>> enough to satisfy most people.
>>>>
>>>> My impression of Walter is that he doesn't like solutions that are just
>>>> okay,
>>>> particularly if they add significant compiler complexity.
>>>
>>> Ummm... Is it in fact so complex? I think everything needed is already
>>> there.
>>
>> I don't think it is complex.  I was thinking of object const-ness when I
>> wrote
>> this.  Sorry for the confusion.
>
> Why sorry? Anyway...
>
>>>
>>>> And while I think
>>>> this is probably feasible for arrays, it's a slippery slope from there
>>>> to
>>>> logical const-ness for user defined objects.
>>>
>>> Don't need this for UDO. Such objects have all needed for encapsulation/
>>> protection already. Basic types in contrary are naked now. You cannot
>>> define methods/envelopes for them. const is not 100% solution in terms
>>> of real protection. But there are no 100% solutions at all, even in D.
>>> It is a compromise and a good one - it costs nothing in runtime and
>>> almost nothing in compile time.
>>
>> I disagree that UDO have what's needed in terms of protection.  Though
>> logical
>> const-ness is far from simple to implement.
>
> In user defined objects at least you can say 'protect'. Protect
> some operations and functions from outside
> This is compile time protection and not runtime! . In runtime you can
> relatively easy get a pointer to private variable and change it outside.
>
> Following logic that we cannot reach 100% protection we shall remove
> this 'private', 'package' etc. What for they were introduced? They
> are not 100% protecting!.
>
> You can do dynamic protection for UDO : you can naturally
> implement:
> "in this particular state of object
> this particular property is immutable, etc." Right?
>
> What we all want to have is simple:
> "by using const for arrays and pointers we want to make
> some methods of const types 'private' - not accessible". This is it.
>
>
>>
>>
>> Sean
>>
>>
>
>

June 02, 2005
In article <d7nra6$291a$1@digitaldaemon.com>, Andrew Fedoniouk says...
>
>In user defined objects at least you can say 'protect'. Protect
>some operations and functions from outside
>This is compile time protection and not runtime! . In runtime you can
>relatively easy get a pointer to private variable and change it outside.
>
>Following logic that we cannot reach 100% protection we shall remove this 'private', 'package' etc. What for they were introduced? They are not 100% protecting!.

I was thinking more of something like this:

# class C
# {
#     int getVal() { return val; }
#     void setVal( int v ) { val = v; }
# private:
#     int val;
# }
#
# void doNotChangeC( C c )
# {
#     c.setVal( 5 );
# }

'val' might be protected, but it can still be altered by calling setVal.  Since D has no concept of logical const-ness, there is no way to verify at compile-time that doNotChangeC actually did not change C.  Though as I demonstrated in another thread, it is possible to verify this somewhat at compile-time using DBC.

>You can do dynamic protection for UDO : you can naturally
>implement:"in this particular state of object
>this particular property is immutable, etc." Right?

Along those lines, I suppose this is an option:

# class C
# {
#     this() { mutable = true; }
#
#     void setMutable( bit m ) { mutable = m; }
#     bit isMutable() { return mut; }
#
#     int getVal() { return val; }
#     void setVal( int v )
#         in { assert( isMutable() ); }
#         body { val = v; }
# private:
#     int val;
#     bit mut;
# }
#
# void doNotChangeC( C c )
# {
#     c.setVal( 5 );
# }
#
# c.setMutable( false );
# doNotChangeC( c );
# c.setMutable( true );

>What we all want to have is simple:
>"by using const for arrays and pointers we want to make
>some methods of const types 'private' - not accessible". This is it.

True enough.  And this shouldn't be very hard to do.


Sean