www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Immutable arrays for Walter and rest of us.

reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
I would like to discuss one of my previous ideas again
as it seems it was lost in the fire.

I think below is the best compromise we can get. In fact
as more I am looking on it as more I am sure that it
not even compromise - it is "well done immutables".

Idea is to extend typesystem with a new type: immutable (const, readonly)
array and pointer.

Proposed notation of immutable array type is as:

     typename#[]

Proposed notation of immutable pointer is as:

     typename#*

Immutable array as a type has exactly the same set
of properties and methods as array except of mutators:

     opIndexAssign and
     int length(int newlength)

Casting rules between array#[] and array[] are obvious:

char#[] is1;
char[] s1;

is1 = s1; // ok.
s1 = is1; // compile time (CT) err.

Examples:

s1[0] = 'a'; // ok
is1[0] = 'a'; // CT err.

s1.length =  1; // ok
is1.length = 1; // CT err.
--------------------------------
String and array literals are immutable by definition:

char#[] slit1 = "Hello world"; // ok
char[] s1 = "Hello world"; // CT err.

Sidenote:
    In C++, by historical reasons, string literals
    have type char* and not const char* which is
    imho bad and needs to be changed.

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

This approach will give us readonlyness without major changes
in language notation and architecture.

This approach is free from C++ "const syntactical madness" where
const is used for three different things and looks ugly sometimes.

Clear differentiation of built-in reference types (array and struct) onto
mutable and immutable versions will increase "fullness" of D's
balanced type system.

The thing is that char[] is from one side is atomic type
and it is pretty natural to human to interpret it as just lets say
atomic int. But at the same time it is a reference to some
possibly shared data. This is why arrays and pointers shall
exist in two forms.

As a rule char[] is buffer/owner and char#[] is an immutable slice -
consumer has no rights to change it as it will damage
integrity state of the owner.

-------------------------------------------
Possible variations of immutable type notation I've considered:

1) typename#[]
2) typename$[]
3) typename []
4) typename[] const - not good as it conflicts with
                                     C++ cases visually.

typename#[] probably is not the best variant
of notation though. Ideas anyone?

--------------------------------------------
I think it makes sense to add opSliceConst to the list of
overloadable operators.
--------------------------------------------

Having readonlyness interpreted and implemented
this way will finally reconcile const and no-const camps. I hope.

Andrew.
Jun 29 2005
next sibling parent Victor Nakoryakov <nail-mail mail.ru> writes:
Yep, good idea. But you're not the first, and I think not the last who 
suggest some solution for constness. To me suggestion seems to be ignored.

-- 
Victor (aka nail) Nakoryakov
nail-mail<at>mail<dot>ru

Krasnoznamensk, Moscow, Russia
Jun 30 2005
prev sibling next sibling parent reply "Regan Heath" <regan netwin.co.nz> writes:
Not a bad idea. I prefer the solution I've mentioned a few times already.
I just hope Walter gives us some indication of what he's thinking at some  
stage.
(hint, hint)

Regan

On Wed, 29 Jun 2005 23:06:12 -0700, Andrew Fedoniouk  
<news terrainformatica.com> wrote:

 I would like to discuss one of my previous ideas again
 as it seems it was lost in the fire.

 I think below is the best compromise we can get. In fact
 as more I am looking on it as more I am sure that it
 not even compromise - it is "well done immutables".

 Idea is to extend typesystem with a new type: immutable (const, readonly)
 array and pointer.

 Proposed notation of immutable array type is as:

      typename#[]

 Proposed notation of immutable pointer is as:

      typename#*

 Immutable array as a type has exactly the same set
 of properties and methods as array except of mutators:

      opIndexAssign and
      int length(int newlength)

 Casting rules between array#[] and array[] are obvious:

 char#[] is1;
 char[] s1;

 is1 = s1; // ok.
 s1 = is1; // compile time (CT) err.

 Examples:

 s1[0] = 'a'; // ok
 is1[0] = 'a'; // CT err.

 s1.length =  1; // ok
 is1.length = 1; // CT err.
 --------------------------------
 String and array literals are immutable by definition:

 char#[] slit1 = "Hello world"; // ok
 char[] s1 = "Hello world"; // CT err.

 Sidenote:
     In C++, by historical reasons, string literals
     have type char* and not const char* which is
     imho bad and needs to be changed.

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

 This approach will give us readonlyness without major changes
 in language notation and architecture.

 This approach is free from C++ "const syntactical madness" where
 const is used for three different things and looks ugly sometimes.

 Clear differentiation of built-in reference types (array and struct) onto
 mutable and immutable versions will increase "fullness" of D's
 balanced type system.

 The thing is that char[] is from one side is atomic type
 and it is pretty natural to human to interpret it as just lets say
 atomic int. But at the same time it is a reference to some
 possibly shared data. This is why arrays and pointers shall
 exist in two forms.

 As a rule char[] is buffer/owner and char#[] is an immutable slice -
 consumer has no rights to change it as it will damage
 integrity state of the owner.

 -------------------------------------------
 Possible variations of immutable type notation I've considered:

 1) typename#[]
 2) typename$[]
 3) typename []
 4) typename[] const - not good as it conflicts with
                                      C++ cases visually.

 typename#[] probably is not the best variant
 of notation though. Ideas anyone?

 --------------------------------------------
 I think it makes sense to add opSliceConst to the list of
 overloadable operators.
 --------------------------------------------

 Having readonlyness interpreted and implemented
 this way will finally reconcile const and no-const camps. I hope.

 Andrew.

Jun 30 2005
parent Kramer <Kramer_member pathlink.com> writes:
And since it has been suggested so many times and IMO a very worth while
idea/feature, if Walter does not want to add it, then we need some
practices/idioms for D on how to simulate it.

-Kramer

In article <opss6iqfje23k2f5 nrage.netwin.co.nz>, Regan Heath says...
Not a bad idea. I prefer the solution I've mentioned a few times already.
I just hope Walter gives us some indication of what he's thinking at some  
stage.
(hint, hint)

Regan

On Wed, 29 Jun 2005 23:06:12 -0700, Andrew Fedoniouk  
<news terrainformatica.com> wrote:

 I would like to discuss one of my previous ideas again
 as it seems it was lost in the fire.

 I think below is the best compromise we can get. In fact
 as more I am looking on it as more I am sure that it
 not even compromise - it is "well done immutables".

 Idea is to extend typesystem with a new type: immutable (const, readonly)
 array and pointer.

 Proposed notation of immutable array type is as:

      typename#[]

 Proposed notation of immutable pointer is as:

      typename#*

 Immutable array as a type has exactly the same set
 of properties and methods as array except of mutators:

      opIndexAssign and
      int length(int newlength)

 Casting rules between array#[] and array[] are obvious:

 char#[] is1;
 char[] s1;

 is1 = s1; // ok.
 s1 = is1; // compile time (CT) err.

 Examples:

 s1[0] = 'a'; // ok
 is1[0] = 'a'; // CT err.

 s1.length =  1; // ok
 is1.length = 1; // CT err.
 --------------------------------
 String and array literals are immutable by definition:

 char#[] slit1 = "Hello world"; // ok
 char[] s1 = "Hello world"; // CT err.

 Sidenote:
     In C++, by historical reasons, string literals
     have type char* and not const char* which is
     imho bad and needs to be changed.

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

 This approach will give us readonlyness without major changes
 in language notation and architecture.

 This approach is free from C++ "const syntactical madness" where
 const is used for three different things and looks ugly sometimes.

 Clear differentiation of built-in reference types (array and struct) onto
 mutable and immutable versions will increase "fullness" of D's
 balanced type system.

 The thing is that char[] is from one side is atomic type
 and it is pretty natural to human to interpret it as just lets say
 atomic int. But at the same time it is a reference to some
 possibly shared data. This is why arrays and pointers shall
 exist in two forms.

 As a rule char[] is buffer/owner and char#[] is an immutable slice -
 consumer has no rights to change it as it will damage
 integrity state of the owner.

 -------------------------------------------
 Possible variations of immutable type notation I've considered:

 1) typename#[]
 2) typename$[]
 3) typename []
 4) typename[] const - not good as it conflicts with
                                      C++ cases visually.

 typename#[] probably is not the best variant
 of notation though. Ideas anyone?

 --------------------------------------------
 I think it makes sense to add opSliceConst to the list of
 overloadable operators.
 --------------------------------------------

 Having readonlyness interpreted and implemented
 this way will finally reconcile const and no-const camps. I hope.

 Andrew.


Jun 30 2005
prev sibling next sibling parent reply Brad Beveridge <brad somewhere.net> writes:
Andrew Fedoniouk wrote:

 typename#[] probably is not the best variant
 of notation though. Ideas anyone?
 
 --------------------------------------------
 I think it makes sense to add opSliceConst to the list of
 overloadable operators.
 --------------------------------------------
 
 Having readonlyness interpreted and implemented
 this way will finally reconcile const and no-const camps. I hope.
 
 Andrew.
 
 

signify immutability though. I've never been opposed to longish names, so my vote would be for "immutable" as a decorator. immutable char[] is1; char[] s1; Brad
Jun 30 2005
parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Brad Beveridge" <brad somewhere.net> wrote in message 
news:da13eo$1ao3$2 digitaldaemon.com...
 Andrew Fedoniouk wrote:

 typename#[] probably is not the best variant
 of notation though. Ideas anyone?

 --------------------------------------------
 I think it makes sense to add opSliceConst to the list of
 overloadable operators.
 --------------------------------------------

 Having readonlyness interpreted and implemented
 this way will finally reconcile const and no-const camps. I hope.

 Andrew.

signify immutability though. I've never been opposed to longish names, so my vote would be for "immutable" as a decorator. immutable char[] is1; char[] s1;

In fact immutable arrays are 80% or so of use cases of arrays in average code. So motivation is to make 'immutable' flag as shorter as possible. What about this: char![] Ideally, default char[] should be immutable and char![] should be mutable. Andrew.
Jun 30 2005
parent Brad Beveridge <brad somewhere.net> writes:
Andrew Fedoniouk wrote:
 "Brad Beveridge" <brad somewhere.net> wrote in message 
 news:da13eo$1ao3$2 digitaldaemon.com...
 
Andrew Fedoniouk wrote:


typename#[] probably is not the best variant
of notation though. Ideas anyone?

--------------------------------------------
I think it makes sense to add opSliceConst to the list of
overloadable operators.
--------------------------------------------

Having readonlyness interpreted and implemented
this way will finally reconcile const and no-const camps. I hope.

Andrew.

I like it and I agree 100%. I don't happen to like # as the token to signify immutability though. I've never been opposed to longish names, so my vote would be for "immutable" as a decorator. immutable char[] is1; char[] s1;

In fact immutable arrays are 80% or so of use cases of arrays in average code. So motivation is to make 'immutable' flag as shorter as possible. What about this: char![] Ideally, default char[] should be immutable and char![] should be mutable. Andrew.

I agree that having a short flag is probably a good idea, but I would personally value absolute clarity over conciseness. Some other choices for "immutable" http://thesaurus.reference.com/search?q=immutable I like "fixed", "stable", "firm" and "solid" in that order. Of course, step 1 is getting Walter to agree that we need _something_ Brad
Jun 30 2005
prev sibling next sibling parent reply Brad Beveridge <brad somewhere.net> writes:
Andrew Fedoniouk wrote:
 I would like to discuss one of my previous ideas again
 as it seems it was lost in the fire.
 
 I think below is the best compromise we can get. In fact
 as more I am looking on it as more I am sure that it
 not even compromise - it is "well done immutables".
 
 Idea is to extend typesystem with a new type: immutable (const, readonly)
 array and pointer.
 

immutable? Or does that open a can of worms that is too large? I think that perhaps they should be allowed to be decorated with "immutable", but I am not certain of the rules that should go along with it - ie, what members can be called etc. I don't really care about this, but it is good to be consistant. Of course, it will probably be a miracle if Walter gives us a straight answer on your original proposal even :) Brad
Jun 30 2005
parent "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Brad Beveridge" <brad somewhere.net> wrote in message 
news:da1534$1cik$1 digitaldaemon.com...
 Andrew Fedoniouk wrote:
 I would like to discuss one of my previous ideas again
 as it seems it was lost in the fire.

 I think below is the best compromise we can get. In fact
 as more I am looking on it as more I am sure that it
 not even compromise - it is "well done immutables".

 Idea is to extend typesystem with a new type: immutable (const, readonly)
 array and pointer.

Or does that open a can of worms that is too large? I think that perhaps they should be allowed to be decorated with "immutable", but I am not certain of the rules that should go along with it - ie, what members can be called etc.

If it is needed anyone can create mutable/immutable state variable for his/her own class. Or create mutable versions of it. This approach was used in mango. A bit overkill, IMO, but works. This # stuff is needed because you cannot override behavior of basic types.
 I don't really care about this, but it is good to be consistant.  Of 
 course, it will probably be a miracle if Walter gives us a straight answer 
 on your original proposal even :)

Hope dies last. And I think we are almost at position to start "Sic transit gloria mundi..."
Jun 30 2005
prev sibling next sibling parent AJG <AJG_member pathlink.com> writes:
Just wanted to put in my vote for this suggested feature. Whatever the actual
syntax ends up being (const / immutable / typename#[] / etc.), we definitely
need this. It's up to Walter now, I guess.

Cheers,
--AJG.

PS: Using hackish class-wrappers for this kind of thing is _way_ too much
trouble and it not worth it IMHO. We need language/compiler level support.


In article <da024r$65o$1 digitaldaemon.com>, Andrew Fedoniouk says...
I would like to discuss one of my previous ideas again
as it seems it was lost in the fire.

I think below is the best compromise we can get. In fact
as more I am looking on it as more I am sure that it
not even compromise - it is "well done immutables".

Idea is to extend typesystem with a new type: immutable (const, readonly)
array and pointer.

Proposed notation of immutable array type is as:

     typename#[]

Proposed notation of immutable pointer is as:

     typename#*

Immutable array as a type has exactly the same set
of properties and methods as array except of mutators:

     opIndexAssign and
     int length(int newlength)

Casting rules between array#[] and array[] are obvious:

char#[] is1;
char[] s1;

is1 = s1; // ok.
s1 = is1; // compile time (CT) err.

Examples:

s1[0] = 'a'; // ok
is1[0] = 'a'; // CT err.

s1.length =  1; // ok
is1.length = 1; // CT err.
--------------------------------
String and array literals are immutable by definition:

char#[] slit1 = "Hello world"; // ok
char[] s1 = "Hello world"; // CT err.

Sidenote:
    In C++, by historical reasons, string literals
    have type char* and not const char* which is
    imho bad and needs to be changed.

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

This approach will give us readonlyness without major changes
in language notation and architecture.

This approach is free from C++ "const syntactical madness" where
const is used for three different things and looks ugly sometimes.

Clear differentiation of built-in reference types (array and struct) onto
mutable and immutable versions will increase "fullness" of D's
balanced type system.

The thing is that char[] is from one side is atomic type
and it is pretty natural to human to interpret it as just lets say
atomic int. But at the same time it is a reference to some
possibly shared data. This is why arrays and pointers shall
exist in two forms.

As a rule char[] is buffer/owner and char#[] is an immutable slice -
consumer has no rights to change it as it will damage
integrity state of the owner.

-------------------------------------------
Possible variations of immutable type notation I've considered:

1) typename#[]
2) typename$[]
3) typename []
4) typename[] const - not good as it conflicts with
                                     C++ cases visually.

typename#[] probably is not the best variant
of notation though. Ideas anyone?

--------------------------------------------
I think it makes sense to add opSliceConst to the list of
overloadable operators.
--------------------------------------------

Having readonlyness interpreted and implemented
this way will finally reconcile const and no-const camps. I hope.

Andrew.

======================= I sync, therefore I am.
Jun 30 2005
prev sibling next sibling parent reply Vathix <chris dprogramming.com> writes:
On Thu, 30 Jun 2005 02:06:12 -0400, Andrew Fedoniouk  
<news terrainformatica.com> wrote:

 I would like to discuss one of my previous ideas again
 as it seems it was lost in the fire.

 I think below is the best compromise we can get. In fact
 as more I am looking on it as more I am sure that it
 not even compromise - it is "well done immutables".

 Idea is to extend typesystem with a new type: immutable (const, readonly)
 array and pointer.

 Proposed notation of immutable array type is as:

      typename#[]

 Proposed notation of immutable pointer is as:

      typename#*

I don't like it. Not just the syntax. I think immutable is so common that it should be the default. Right now we have to enforce it ourselves using COW. I don't have much of a problem with it but it seems many others do. What if arrays and pointers were immutable by default? The only way to make something mutable is to use a mutable keyword. I think it would be much more productive and sounds a lot more relaxing than specifying immutable. There would have to be a way to force something that is immutable to be mutable (?). Perhaps using cast(mutable char[]) for char[]. Here is an example: char[] foo = "hi"; // Good, immutable. mutable char[] bar = new char[30]; char[] baz = bar; // Mutable to immutable. mutable char[] bat = "hey"; // ERROR, string literal is immutable. mutable char[] qux = cast(mutable char[])bar; // Force immutable to mutable. Not recommended. It would break a lot of existing code, but I believe supporting the current style could still be supported using -deprecated. - Chris
Jun 30 2005
parent reply Brad Beveridge <brad somewhere.net> writes:
Vathix wrote:
 On Thu, 30 Jun 2005 02:06:12 -0400, Andrew Fedoniouk  
 <news terrainformatica.com> wrote:

 I don't like it. Not just the syntax. I think immutable is so common 
 that  it should be the default. Right now we have to enforce it 
 ourselves using  COW. I don't have much of a problem with it but it 
 seems many others do.

 - Chris

Would you still fall into the category of "we need _something_ to protect immutable data"? I think I might start a voting thread to see who need/want this feeture :) Brad
Jun 30 2005
parent Vathix <chris dprogramming.com> writes:
On Thu, 30 Jun 2005 13:40:26 -0400, Brad Beveridge <brad somewhere.net>  
wrote:

 Would you still fall into the category of "we need _something_ to  
 protect immutable data"?

No, but I'm willing to compromise.
Jun 30 2005
prev sibling next sibling parent reply "Walter" <newshound digitalmars.com> writes:
What is the difference between that and C++'s const as a type modifier?

C++:
    typename const *
Proposal:
    typename # *
Jun 30 2005
next sibling parent reply =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Walter wrote:

 What is the difference between that and C++'s const as a type modifier?
 
 C++:
     typename const *
 Proposal:
     typename # *

Or the other proposal, "readonly", seeing as how const is overloaded... (or the newly proposed variant thereof, which seems to be "immutable") BTW; There seems to be a lot of weird syntax lately: [$], !is and now char#[] Another note: There was an old suggestion (I think) that an explicit "in" would mean readonly for the array contents too, and not just for the array pointer. But it's a bit "unclear" for declarations, I think ? "in typename *" --anders
Jun 30 2005
parent reply AJG <AJG_member pathlink.com> writes:
Hi,

Or the other proposal, "readonly", seeing as how const is overloaded...
(or the newly proposed variant thereof, which seems to be "immutable")

The shorter the better, in my opinion. I prefer const or # over the other ones.
BTW; There seems to be a lot of weird syntax lately: [$], !is and now char#[]

I agree, but I don't think it's a bad thing at all. The more the merrier, I say. Oh, and what is [$]? I've never seen that one before...
Another note:
There was an old suggestion (I think) that an explicit "in" would mean
readonly for the array contents too, and not just for the array pointer.

I like this a lot. This is the way it should be, IMHO, by default at all times; at least the explicit "in" would give us the option to enforce it. I can't decide which one I like better, the explicit in or immutability; either one would be a great improvement. I guess both would be even better? Cheers, --AJG. ======================= I sync, therefore I am.
Jun 30 2005
parent reply =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
AJG wrote:

 Oh, and what is [$]? I've never seen that one before...

"length", for arrays. As in this "remove": array = array[0 .. i-1] ~ array[i+1 .. $]; --anders
Jun 30 2005
parent reply AJG <AJG_member pathlink.com> writes:
Awesome, thanks. I use length a lot, so $ is great.

Anybody have any concerns about this usage?:

// Easy way to get last element.
int lastItem = someArray[--$];

Cheers,
--AJG.


In article <da1q3p$26jr$1 digitaldaemon.com>,
=?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= says...
AJG wrote:

 Oh, and what is [$]? I've never seen that one before...

"length", for arrays. As in this "remove": array = array[0 .. i-1] ~ array[i+1 .. $]; --anders

======================== if (!sin) throw rock[0];
Jun 30 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Fri, 1 Jul 2005 02:46:41 +0000 (UTC), AJG <AJG_member pathlink.com>  
wrote:
 Awesome, thanks. I use length a lot, so $ is great.

 Anybody have any concerns about this usage?:

 // Easy way to get last element.
 int lastItem = someArray[--$];

And pull it off, so to speak (you're decrementing the length, or trying to). Does that work? AFAIK you cannot say "--someArray.length" as length is a property i.e not an lvalue I write someArray[$-1] to get the last element. Regan
 Cheers,
 --AJG.


 In article <da1q3p$26jr$1 digitaldaemon.com>,
 =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= says...
 AJG wrote:

 Oh, and what is [$]? I've never seen that one before...

"length", for arrays. As in this "remove": array = array[0 .. i-1] ~ array[i+1 .. $]; --anders

======================== if (!sin) throw rock[0];

Jun 30 2005
parent reply Trevor Parscal <trevorparscal hotmail.com> writes:
 
 I write someArray[$-1] to get the last element.
 

Personally, I think using # is way more descriptive than $... $ looks like a php variable.. some might say # looks like a cold fusion varaible, but honestly, cold fusion is crap, so I just ignore it... # also seems like "number of elements"... $ has no other natural meaning... list[# - 5 .. #] should give you the last 5 elements of the array. Also, I have another idea. using "..." should mean, to the end. so list[4 ...] means, from 4 on. so... list[# - 5 ...] means, the last 5 :) Just an idea. Won't break existing code. -- Thanks, Trevor Parscal www.trevorparscal.com trevorparscal hotmail.com
Jul 05 2005
parent reply AJG <AJG_member pathlink.com> writes:
Hi,

In article <daf0km$umn$1 digitaldaemon.com>, Trevor Parscal says...
 I write someArray[$-1] to get the last element.

like a php variable.. some might say # looks like a cold fusion varaible, but honestly, cold fusion is crap, so I just ignore it... # also seems like "number of elements"... $ has no other natural meaning... list[# - 5 .. #] should give you the last 5 elements of the array.

You have my vote. I agree wholeheartedly.
Also, I have another idea. using "..." should mean, to the end. so

list[4 ...]
means, from 4 on. so...
list[# - 5 ...]
means, the last 5 :)

Just an idea. Won't break existing code.

I also like this idea. To make it simpler we could just use .. and leave one (or both) of the ends blank. So that: array[a ..] == array[a .. #]; array[.. b] == array[0 .. b]; array[..] == array[0 .. #] == array; Just thinking out loud. --AJG.
-- 
Thanks,
Trevor Parscal
www.trevorparscal.com
trevorparscal hotmail.com

Jul 05 2005
parent "Regan Heath" <regan netwin.co.nz> writes:
On Wed, 6 Jul 2005 01:05:17 +0000 (UTC), AJG <AJG_member pathlink.com>  
wrote:
 In article <daf0km$umn$1 digitaldaemon.com>, Trevor Parscal says...
 I write someArray[$-1] to get the last element.

like a php variable.. some might say # looks like a cold fusion varaible, but honestly, cold fusion is crap, so I just ignore it... # also seems like "number of elements"... $ has no other natural meaning... list[# - 5 .. #] should give you the last 5 elements of the array.

You have my vote. I agree wholeheartedly.

I dont mind $, that said, I don't mind # either.
 Also, I have another idea. using "..." should mean, to the end. so

 list[4 ...]
 means, from 4 on. so...
 list[# - 5 ...]
 means, the last 5 :)

 Just an idea. Won't break existing code.

I also like this idea. To make it simpler we could just use .. and leave one (or both) of the ends blank. So that: array[a ..] == array[a .. #]; array[.. b] == array[0 .. b]; array[..] == array[0 .. #] == array; Just thinking out loud.

This idea has been proposed before, along with many others. Do a search, you'll see what I mean. Regan
Jul 05 2005
prev sibling next sibling parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Thu, 30 Jun 2005 11:19:38 -0700, Walter <newshound digitalmars.com>  
wrote:
 What is the difference between that and C++'s const as a type modifier?

 C++:
     typename const *
 Proposal:
     typename # *

Nothing, which is why I prefer the idea I've been bandying (sp?) around here for the past month. Please read carefully this is _not_ the same thing. A readonly compile time, and perhaps also runtime (disabled for -release) readonly bit flag for all variables. Initialised to 'false'. Set to 'true' in the presence of "readonly" as a type modifier. Set to 'true' when passed as an 'in' parameter. Compiler errors on all operations that mutate a readonly flagged variable. Example usage: class Foo { char[] data; readonly char[] get() { return data; } } void foo(inout char[] data) { data[0] = 'a'; } Foo f = new Foo(); char[] p = f.get(); p[0] = 'a'; //error cannot mutate readonly foo(p); //error passing readonly as mutable void foo(char[] data) { data[0] = 'a'; } //error cannot mutate readonly IMPORTANT: this does not create a seperate distinct type, "readonly char[]" is not a different type to "char[]" it's the same type with it's readonly flag set to 'true'. The reason this is important is that it stops this situation... char[] s; ..s used as temp var here.. readonly char[] p = f.get(); s = p; //error s is not readonly Which is just plain irritating. People typically solve the above by casting the readonly away. Not good. In the above 's's readonly flag is set on assignment, it becomes readonly. The readonly flag would be set to false when passed as 'out', or on assignment to a rhs which has readonly=false (including null). A runtime flag is required for cases like: char[] p = test ? some_string : f.get(); p[1] = 'd'; //is 'p' readonly if some_string isn't? where the compiler cannot tell at compile time. The runtime flag would be present in every single variable, disabled by -release and/or it's own compile time flag (perhaps disabled by default like -unittest) Regan
Jun 30 2005
parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
Regan,
Readonly flag is technicaly difficult and inefficient to implement.

Any access to the pointer(sic!) and array shall check first this flag
in runtime. Second problem is that you need to store somewhere
this bit. Where?

Proposed solution is just static (compile time)  test.

Moving conditions which can be checked in compile to runtime
is generally not a good idea - non-efficient and difficult
to verify in full.

To be short, in runtime you may get following:

<quote>
Ariane 5 Rocket Disaster

The Ariane 5 Rocket was made by the European Space Agency. In simple terms 
Navigational software was used from the Ariane 4 in the more powerful Ariane 
5. The computer was programmed with a safety feature which aborted the 
mission and caused the rocket to self destruct if it went off course.

Due to an error in the navigation calculations, however, the Arian 5 self 
destructed - even though it was on course to its planned destination.
Investigators later discovered that the cause of the Ariane 5 disaster was 
attributed to calculations based on the Ariane 4 dimensions and power.

</quote>

If it is possible to verify conditions in CT you'd better do it there.

PS: Ariane software is written in ADA, afaik.

Andrew.


"Regan Heath" <regan netwin.co.nz> wrote in message 
news:opss7fh6dr23k2f5 nrage.netwin.co.nz...
 On Thu, 30 Jun 2005 11:19:38 -0700, Walter <newshound digitalmars.com> 
 wrote:
 What is the difference between that and C++'s const as a type modifier?

 C++:
     typename const *
 Proposal:
     typename # *

Nothing, which is why I prefer the idea I've been bandying (sp?) around here for the past month. Please read carefully this is _not_ the same thing. A readonly compile time, and perhaps also runtime (disabled for -release) readonly bit flag for all variables. Initialised to 'false'. Set to 'true' in the presence of "readonly" as a type modifier. Set to 'true' when passed as an 'in' parameter. Compiler errors on all operations that mutate a readonly flagged variable. Example usage: class Foo { char[] data; readonly char[] get() { return data; } } void foo(inout char[] data) { data[0] = 'a'; } Foo f = new Foo(); char[] p = f.get(); p[0] = 'a'; //error cannot mutate readonly foo(p); //error passing readonly as mutable void foo(char[] data) { data[0] = 'a'; } //error cannot mutate readonly IMPORTANT: this does not create a seperate distinct type, "readonly char[]" is not a different type to "char[]" it's the same type with it's readonly flag set to 'true'. The reason this is important is that it stops this situation... char[] s; ..s used as temp var here.. readonly char[] p = f.get(); s = p; //error s is not readonly Which is just plain irritating. People typically solve the above by casting the readonly away. Not good. In the above 's's readonly flag is set on assignment, it becomes readonly. The readonly flag would be set to false when passed as 'out', or on assignment to a rhs which has readonly=false (including null). A runtime flag is required for cases like: char[] p = test ? some_string : f.get(); p[1] = 'd'; //is 'p' readonly if some_string isn't? where the compiler cannot tell at compile time. The runtime flag would be present in every single variable, disabled y -release and/or it's own compile time flag (perhaps disabled by default like -unittest) Regan

Jun 30 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Thu, 30 Jun 2005 19:52:53 -0700, Andrew Fedoniouk  
<news terrainformatica.com> wrote:
 Readonly flag is technicaly difficult and inefficient to implement.

The runtime or the compile time one? (you seem not to realise I am talking about *both*)
 Any access to the pointer(sic!) and array shall check first this flag
 in runtime.

Yes. When you enable the runtime DBC feature you'll get this, just like array bounds checks.
 Second problem is that you need to store somewhere
 this bit. Where?

1 bit in every single variable.
 Proposed solution is just static (compile time)  test.

Mine is first a compile time suggestion, followed by a runtime one (as it's been shown that some cases exist where compile time check is impossible)
 Moving conditions which can be checked in compile to runtime
 is generally not a good idea - non-efficient and difficult
 to verify in full.

Like I said above, my primary suggestion is a compile time one, it has been shown not all cases can be verified at compile time, as such a runtime solution is required.
 To be short, in runtime you may get following:

<snip> I can't see how this is even relevant. Regan
 Andrew.


 "Regan Heath" <regan netwin.co.nz> wrote in message
 news:opss7fh6dr23k2f5 nrage.netwin.co.nz...
 On Thu, 30 Jun 2005 11:19:38 -0700, Walter <newshound digitalmars.com>
 wrote:
 What is the difference between that and C++'s const as a type modifier?

 C++:
     typename const *
 Proposal:
     typename # *

Nothing, which is why I prefer the idea I've been bandying (sp?) around here for the past month. Please read carefully this is _not_ the same thing. A readonly compile time, and perhaps also runtime (disabled for -release) readonly bit flag for all variables. Initialised to 'false'. Set to 'true' in the presence of "readonly" as a type modifier. Set to 'true' when passed as an 'in' parameter. Compiler errors on all operations that mutate a readonly flagged variable. Example usage: class Foo { char[] data; readonly char[] get() { return data; } } void foo(inout char[] data) { data[0] = 'a'; } Foo f = new Foo(); char[] p = f.get(); p[0] = 'a'; //error cannot mutate readonly foo(p); //error passing readonly as mutable void foo(char[] data) { data[0] = 'a'; } //error cannot mutate readonly IMPORTANT: this does not create a seperate distinct type, "readonly char[]" is not a different type to "char[]" it's the same type with it's readonly flag set to 'true'. The reason this is important is that it stops this situation... char[] s; ..s used as temp var here.. readonly char[] p = f.get(); s = p; //error s is not readonly Which is just plain irritating. People typically solve the above by casting the readonly away. Not good. In the above 's's readonly flag is set on assignment, it becomes readonly. The readonly flag would be set to false when passed as 'out', or on assignment to a rhs which has readonly=false (including null). A runtime flag is required for cases like: char[] p = test ? some_string : f.get(); p[1] = 'd'; //is 'p' readonly if some_string isn't? where the compiler cannot tell at compile time. The runtime flag would be present in every single variable, disabled y -release and/or it's own compile time flag (perhaps disabled by default like -unittest) Regan


Jun 30 2005
parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Regan Heath" <regan netwin.co.nz> wrote in message 
news:opss7xxlgs23k2f5 nrage.netwin.co.nz...
 On Thu, 30 Jun 2005 19:52:53 -0700, Andrew Fedoniouk 
 <news terrainformatica.com> wrote:
 Readonly flag is technicaly difficult and inefficient to implement.

The runtime or the compile time one? (you seem not to realise I am talking about *both*)
 Any access to the pointer(sic!) and array shall check first this flag
 in runtime.

Yes. When you enable the runtime DBC feature you'll get this, just like array bounds checks.
 Second problem is that you need to store somewhere
 this bit. Where?

1 bit in every single variable.

The question is: where this bit is located? array variable is 32bit ptr (64bit) and 32bit (64bit) length. pointer variable is 32bit (64bit). So where is the place for it? In additional machine word which will be assosiated with each variable?
 Proposed solution is just static (compile time)  test.

Mine is first a compile time suggestion, followed by a runtime one (as it's been shown that some cases exist where compile time check is impossible)
 Moving conditions which can be checked in compile to runtime
 is generally not a good idea - non-efficient and difficult
 to verify in full.

Like I said above, my primary suggestion is a compile time one, it has been shown not all cases can be verified at compile time, as such a runtime solution is required.

Universal solution is to have opAssign, etc. So extreme cases can be handled by declaring your own structures/classes. Having hidden bit (if it is possible at all) for only arrays and pointers is little bit unnatural, imho.
 To be short, in runtime you may get following:

<snip> I can't see how this is even relevant. Regan
 Andrew.


 "Regan Heath" <regan netwin.co.nz> wrote in message
 news:opss7fh6dr23k2f5 nrage.netwin.co.nz...
 On Thu, 30 Jun 2005 11:19:38 -0700, Walter <newshound digitalmars.com>
 wrote:
 What is the difference between that and C++'s const as a type modifier?

 C++:
     typename const *
 Proposal:
     typename # *

Nothing, which is why I prefer the idea I've been bandying (sp?) around here for the past month. Please read carefully this is _not_ the same thing. A readonly compile time, and perhaps also runtime (disabled or -release) readonly bit flag for all variables. Initialised to 'false'. Set to 'true' in the presence of "readonly" as a type modifier. Set to 'true' when passed as an 'in' parameter. Compiler errors on all operations that mutate a readonly flagged variable. Example usage: class Foo { char[] data; readonly char[] get() { return data; } } void foo(inout char[] data) { data[0] = 'a'; } Foo f = new Foo(); char[] p = f.get(); p[0] = 'a'; //error cannot mutate readonly foo(p); //error passing readonly as mutable void foo(char[] data) { data[0] = 'a'; } //error cannot mutate readonly IMPORTANT: this does not create a seperate distinct type, "readonly char[]" is not a different type to "char[]" it's the same type with it's readonly flag set to 'true'. The reason this is important is that it stops this situation... char[] s; ..s used as temp var here.. readonly char[] p = f.get(); s = p; //error s is not readonly Which is just plain irritating. People typically solve the above by casting the readonly away. Not good. In the above 's's readonly flag is set on assignment, it becomes readonly. The readonly flag would be set to false when passed as 'out', or on assignment to a rhs which has readonly=false (including null). A runtime flag is required for cases like: char[] p = test ? some_string : f.get(); p[1] = 'd'; //is 'p' readonly if some_string isn't? where the compiler cannot tell at compile time. The runtime flag would be present in every single variable, disabled y -release and/or it's own compile time flag (perhaps disabled by default like -unittest) Regan



Jun 30 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Thu, 30 Jun 2005 23:10:00 -0700, Andrew Fedoniouk  
<news terrainformatica.com> wrote:
 "Regan Heath" <regan netwin.co.nz> wrote in message
 news:opss7xxlgs23k2f5 nrage.netwin.co.nz...
 On Thu, 30 Jun 2005 19:52:53 -0700, Andrew Fedoniouk
 <news terrainformatica.com> wrote:
 Readonly flag is technicaly difficult and inefficient to implement.

The runtime or the compile time one? (you seem not to realise I am talking about *both*)
 Any access to the pointer(sic!) and array shall check first this flag
 in runtime.

Yes. When you enable the runtime DBC feature you'll get this, just like array bounds checks.
 Second problem is that you need to store somewhere
 this bit. Where?

1 bit in every single variable.

The question is: where this bit is located? array variable is 32bit ptr (64bit) and 32bit (64bit) length. pointer variable is 32bit (64bit). So where is the place for it? In additional machine word which will be assosiated with each variable?

If that is what is required, yes.
 Proposed solution is just static (compile time)  test.

Mine is first a compile time suggestion, followed by a runtime one (as it's been shown that some cases exist where compile time check is impossible)
 Moving conditions which can be checked in compile to runtime
 is generally not a good idea - non-efficient and difficult
 to verify in full.

Like I said above, my primary suggestion is a compile time one, it has been shown not all cases can be verified at compile time, as such a runtime solution is required.

Universal solution is to have opAssign, etc.

That doesn't give us immutable char[].
 So extreme cases can be handled by declaring
 your own structures/classes.
 Having hidden bit (if it is possible at all) for only
 arrays and pointers is little bit unnatural, imho.

Not just arrays and pointers, everything, even UDT's. Regan
Jun 30 2005
parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Regan Heath" <regan netwin.co.nz> wrote in message 
news:opss714rpw23k2f5 nrage.netwin.co.nz...
 On Thu, 30 Jun 2005 23:10:00 -0700, Andrew Fedoniouk 
 <news terrainformatica.com> wrote:
 "Regan Heath" <regan netwin.co.nz> wrote in message
 news:opss7xxlgs23k2f5 nrage.netwin.co.nz...
 On Thu, 30 Jun 2005 19:52:53 -0700, Andrew Fedoniouk
 <news terrainformatica.com> wrote:
 Readonly flag is technicaly difficult and inefficient to implement.

The runtime or the compile time one? (you seem not to realise I am talking about *both*)
 Any access to the pointer(sic!) and array shall check first this flag
 in runtime.

Yes. When you enable the runtime DBC feature you'll get this, just like array bounds checks.
 Second problem is that you need to store somewhere
 this bit. Where?

1 bit in every single variable.

The question is: where this bit is located? array variable is 32bit ptr (64bit) and 32bit (64bit) length. pointer variable is 32bit (64bit). So where is the place for it? In additional machine word which will be assosiated with each variable?

If that is what is required, yes.

So -release will have sizeof(void*) == 32 and otherwise sizeof(void*) == 64. Do you *really* think this is a solution?
 Proposed solution is just static (compile time)  test.

Mine is first a compile time suggestion, followed by a runtime one (as it's been shown that some cases exist where compile time check is impossible)
 Moving conditions which can be checked in compile to runtime
 is generally not a good idea - non-efficient and difficult
 to verify in full.

Like I said above, my primary suggestion is a compile time one, it has been shown not all cases can be verified at compile time, as such a runtime solution is required.

Universal solution is to have opAssign, etc.

That doesn't give us immutable char[].

It will give you an option: struct chars { private char[] data; bit mutableBit; void opAssign(chars rightSide) { if(!mutableBit) throw new WellKnownAndExpectedExceptionAndNotAnError; ... } }
 So extreme cases can be handled by declaring
 your own structures/classes.
 Having hidden bit (if it is possible at all) for only
 arrays and pointers is little bit unnatural, imho.

Not just arrays and pointers, everything, even UDT's. Regan

Jul 01 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Fri, 1 Jul 2005 00:35:38 -0700, Andrew Fedoniouk  
<news terrainformatica.com> wrote:
 1 bit in every single variable.

The question is: where this bit is located? array variable is 32bit ptr (64bit) and 32bit (64bit) length. pointer variable is 32bit (64bit). So where is the place for it? In additional machine word which will be assosiated with each variable?

If that is what is required, yes.

So -release will have sizeof(void*) == 32 and otherwise sizeof(void*) == 64. Do you *really* think this is a solution?

Yes. Almost all cases are handled at *compile* time, there are very few cases which cannot be handled at compile time. As such the runtime solution is a very small piece of the overall solution. It's optional, can be disabled by a switch, and would *only* be used during the design stage just like the other DBC features.
 Proposed solution is just static (compile time)  test.

Mine is first a compile time suggestion, followed by a runtime one (as it's been shown that some cases exist where compile time check is impossible)
 Moving conditions which can be checked in compile to runtime
 is generally not a good idea - non-efficient and difficult
 to verify in full.

Like I said above, my primary suggestion is a compile time one, it has been shown not all cases can be verified at compile time, as such a runtime solution is required.

Universal solution is to have opAssign, etc.

That doesn't give us immutable char[].

It will give you an option: struct chars { private char[] data; bit mutableBit; void opAssign(chars rightSide) { if(!mutableBit) throw new WellKnownAndExpectedExceptionAndNotAnError; ... } }

D does not need a string class. Regan
Jul 01 2005
parent "Regan Heath" <regan netwin.co.nz> writes:
I recently forgot my 'other' option for runtime 'readonly' checking of  
"in" parameters, this solution uses in/out contracts, eg.

import std.stdio;
import std.string;
import std.c.stdlib;

void main()
{
	char[] a = "regan";	
	foo(a);
}

void* cmp = null;

void foo(char[] string)
in {
	cmp = realloc(cmp,string.sizeof);
	memcpy(cmp,&string,string.sizeof);
}
out {
	assert(memcmp(cmp,&string,string.sizeof) == 0);
}
body {
       //this causes the assert, remove it, no assert.
	string.length = 20;
}



As you can see it simply makes a duplicate of the 'in' parameter then  
compares the parameter with the duplicate upon completion of the function.

This is better than a readonly flag in every object as it saves memory  
overall. It is worse in that it doesn't tell you exactly where it was  
modified, just that it was modified somewhere in that function.

This idea doesn't necessarily help us with "const" labelled returns eg.

class Foo {
   private char[] data;
   const char[] get() { return data[0..5]; }
}

char[] p = f.get();
char[] s = b ? p : "foo"; //where b is determined at runtime.
s[0] = 'a';

However a copy could be setup when f.get() returned and checked when 'p'  
went out of scope. This sounds difficult ot implement to me however.

Regan

On Fri, 01 Jul 2005 19:46:23 +1200, Regan Heath <regan netwin.co.nz> wrote:
 On Fri, 1 Jul 2005 00:35:38 -0700, Andrew Fedoniouk  
 <news terrainformatica.com> wrote:
 1 bit in every single variable.

The question is: where this bit is located? array variable is 32bit ptr (64bit) and 32bit (64bit) length. pointer variable is 32bit (64bit). So where is the place for it? In additional machine word which will be assosiated with each variable?

If that is what is required, yes.

So -release will have sizeof(void*) == 32 and otherwise sizeof(void*) == 64. Do you *really* think this is a solution?

Yes. Almost all cases are handled at *compile* time, there are very few cases which cannot be handled at compile time. As such the runtime solution is a very small piece of the overall solution. It's optional, can be disabled by a switch, and would *only* be used during the design stage just like the other DBC features.
 Proposed solution is just static (compile time)  test.

Mine is first a compile time suggestion, followed by a runtime one (as it's been shown that some cases exist where compile time check is impossible)
 Moving conditions which can be checked in compile to runtime
 is generally not a good idea - non-efficient and difficult
 to verify in full.

Like I said above, my primary suggestion is a compile time one, it has been shown not all cases can be verified at compile time, as such a runtime solution is required.

Universal solution is to have opAssign, etc.

That doesn't give us immutable char[].

It will give you an option: struct chars { private char[] data; bit mutableBit; void opAssign(chars rightSide) { if(!mutableBit) throw new WellKnownAndExpectedExceptionAndNotAnError; ... } }

D does not need a string class. Regan

Jul 01 2005
prev sibling parent "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Walter" <newshound digitalmars.com> wrote in message 
news:da1d5u$1kdf$1 digitaldaemon.com...
 What is the difference between that and C++'s const as a type modifier?

 C++:
    typename const *
 Proposal:
    typename # *

typename # * is eqiuvalent of C++'s const typename * -or- typename const * It is a 'mutable pointer to immutable data.' I think that proposed singular form typename #* where '#' means 'no = ' is a bit better. But again it is a personal matter. Andrew.
Jun 30 2005
prev sibling parent reply "Walter" <newshound digitalmars.com> writes:
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message
news:da024r$65o$1 digitaldaemon.com...
 I would like to discuss one of my previous ideas again
 as it seems it was lost in the fire.

I've been discussing this issue with Andrei (of Modern C++ Design fame). He points out that there are numerous different "const" semantics, each having their uses and disadvantages. He suggests that all should be supported in one way or another, and I agree that that would have some advantages. One of my (several) dislikes with "const" is that most (90% ?) of a function's parameters are likely to be "const". So one winds up with the C++ aesthetically ugly consequence of "const" here, there, everywhere. And you can't use it casually here and there, once you start down the road of making a few functions have "const" parameters, you've got to do it throughout the program. So perhaps one could turn that inside out, and make "const" the default for function parameters. If the parameter was to be changed, it'd be explicitly marked as "mutable" or some such. But that runs into another problem. Function local variables, on the other hand, one would want to be "mutable" by default. There's also the issue that "const" already exists as a variable storage class. So far, I haven't thought of anything that makes consistent sense, and doesn't look like an ugly hack. One thing I have thought of is a compromise. Change the semantics of explicitly "in" parameters to be what Andrei calls "deep immutable". Deep immutable parameters would have unchanging values for the scope of that parameter, and also every sub-object reachable by that parameter would also be unchangeable. The values wouldn't change even by another reference or another thread. (This is quite unlike C++ "const".) "in" would be a promise by the programmer, and could not be guaranteed by the compiler - but - the optimizer can take advantage of this promise to generate perhaps significantly better code. (With C++ "const", values can change at any momen t by another reference or another thread, making optimizations based on "const" impossible.) C++ "const" is enforced by the compiler, but is useless semantic information. "in" is not enforced by the compiler beyond the trivial, but is useful semantic information.
Jul 01 2005
next sibling parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Fri, 1 Jul 2005 01:34:31 -0700, Walter <newshound digitalmars.com>  
wrote:
 But that runs into another problem. Function local variables, on the  
 other hand, one would want to be "mutable" by default.

By function local do you mean "a" or "b" below? void foo(char[] a) { char[] b; } Regan
Jul 01 2005
parent reply AJG <AJG_member pathlink.com> writes:
I think he means "b". As opposed to parameter in variables, like "a".
--AJG.

In article <opss8aohii23k2f5 nrage.netwin.co.nz>, Regan Heath says...
On Fri, 1 Jul 2005 01:34:31 -0700, Walter <newshound digitalmars.com>  
wrote:
 But that runs into another problem. Function local variables, on the  
 other hand, one would want to be "mutable" by default.

By function local do you mean "a" or "b" below? void foo(char[] a) { char[] b; } Regan

Jul 01 2005
parent "Regan Heath" <regan netwin.co.nz> writes:
If he does, then why can't all 'in' parameters be immutable. 'in' is the  
default parameter type, so all variables would be immutable by default. No  
'const' (or whatever keyword is used) everywhere. I've always thought 'in'  
was part of the function contract stating "I only need read access to  
this", this change would actually enforce that.

If a mutable copy was required then:

void foo(char[] a)
{
   char[] b = a.dup;
}

would work. It could even be optimised by the compiler. I imagine the  
compiler is already making a dup of the variable which is passed (as it  
does for value types), this would make a second one, it could optimise one  
of those duplicates away.

Regan

On Fri, 1 Jul 2005 13:20:18 +0000 (UTC), AJG <AJG_member pathlink.com>  
wrote:
 I think he means "b". As opposed to parameter in variables, like "a".
 --AJG.

 In article <opss8aohii23k2f5 nrage.netwin.co.nz>, Regan Heath says...
 On Fri, 1 Jul 2005 01:34:31 -0700, Walter <newshound digitalmars.com>
 wrote:
 But that runs into another problem. Function local variables, on the
 other hand, one would want to be "mutable" by default.

By function local do you mean "a" or "b" below? void foo(char[] a) { char[] b; } Regan


Jul 01 2005
prev sibling next sibling parent AJG <AJG_member pathlink.com> writes:
Hi,

One of my (several) dislikes with "const" is that most (90% ?) of a
function's parameters are likely to be "const". So one winds up with the C++
aesthetically ugly consequence of "const" here, there, everywhere. And you
can't use it casually here and there, once you start down the road of making
a few functions have "const" parameters, you've got to do it throughout the
program.

Very true.
One thing I have thought of is a compromise. Change the semantics of
explicitly "in" parameters to be what Andrei calls "deep immutable". Deep
immutable parameters would have unchanging values for the scope of that
parameter, and also every sub-object reachable by that parameter would also
be unchangeable. 

This would be fantastic, IMHO. It makes perfect sense, and we get the best of both worlds. [a] Immutable variables exactly where we need them; and [b] the simple aesthetic syntax. This should have always been the default, and it definitely gets my vote by far. Cheers, --AJG. ======================= I sync, therefore I am.
Jul 01 2005
prev sibling next sibling parent reply Kevin Bealer <Kevin_member pathlink.com> writes:
In article <da2v7t$b9b$1 digitaldaemon.com>, Walter says...
One thing I have thought of is a compromise. Change the semantics of
explicitly "in" parameters to be what Andrei calls "deep immutable". Deep
immutable parameters would have unchanging values for the scope of that
parameter, and also every sub-object reachable by that parameter would also
be unchangeable. The values wouldn't change even by another reference or
another thread. (This is quite unlike C++ "const".) "in" would be a promise
by the programmer, and could not be guaranteed by the compiler - but - the
optimizer can take advantage of this promise to generate perhaps
significantly better code. (With C++ "const", values can change at any momen
t by another reference or another thread, making optimizations based on
"const" impossible.)

This sounds great. In this scenario, can I store the in object (or its sub objects) to a local variable? If so it would be immutable too I would guess, but is there a special syntax? (Or is slicing, etc forbidden in these cases?) :void foo(in int[] x) :{ : int[] middle1 = x[1..$-1]; // is middle implicitely immutable? : in int[] middle2 = x[1..$-1]; // explicitly marked as immutable? : middle[0] = middle1[1]; // this should fail to compile right? :}
C++ "const" is enforced by the compiler, but is useless semantic
information. "in" is not enforced by the compiler beyond the trivial, but is
useful semantic information.

Kevin
Jul 01 2005
parent reply "Walter" <newshound digitalmars.com> writes:
"Kevin Bealer" <Kevin_member pathlink.com> wrote in message
news:da3ppb$1h97$1 digitaldaemon.com...
 This sounds great.  In this scenario, can I store the in object (or its

 objects) to a local variable?  If so it would be immutable too I would

 but is there a special syntax?  (Or is slicing, etc forbidden in these

 :void foo(in int[] x)
 :{
 :    int[] middle1 = x[1..$-1];    // is middle implicitely immutable?

I don't see how to make that work right. The only thing I can think of is to allow middle1 to modify x, but that such modification would be undefined behavior. Not so hot.
 :    in int[] middle2 = x[1..$-1]; // explicitly marked as immutable?

There I hate using 'in' as a storage class. It's confusing with 'const'.
 :    middle[0] = middle1[1];       // this should fail to compile right?

Yes. That's one case the compiler should pick up.
Jul 01 2005
parent Sean Kelly <sean f4.ca> writes:
In article <da3ug1$1n4l$1 digitaldaemon.com>, Walter says...
"Kevin Bealer" <Kevin_member pathlink.com> wrote in message
news:da3ppb$1h97$1 digitaldaemon.com...
 This sounds great.  In this scenario, can I store the in object (or its

 objects) to a local variable?  If so it would be immutable too I would

 but is there a special syntax?  (Or is slicing, etc forbidden in these

 :void foo(in int[] x)
 :{
 :    int[] middle1 = x[1..$-1];    // is middle implicitely immutable?

I don't see how to make that work right. The only thing I can think of is to allow middle1 to modify x, but that such modification would be undefined behavior. Not so hot.

I think in this case a copy would need to be made. ie. int[] middle1 = x[1..$-1].dup; This is no different than when a programmer wants to modify a const parameter in C++. I'm not sure that there's a good way to enforce this in the compiler, though it might be nice if there were a way to verify that a parameter is unchanged via DBC. Perhaps something like this? void fn( in int[] x ) in { preserve int[] p = x.dup; } out { assert( x == p ); } or perhaps: void fn( in int[] x ) int[] p; in { p = x.dup; } .. Sean
Jul 01 2005
prev sibling next sibling parent reply Carlos Santander <csantander619 gmail.com> writes:
Walter escribió:
 
 One thing I have thought of is a compromise. Change the semantics of
 explicitly "in" parameters to be what Andrei calls "deep immutable". Deep
 immutable parameters would have unchanging values for the scope of that
 parameter, and also every sub-object reachable by that parameter would also
 be unchangeable. The values wouldn't change even by another reference or
 another thread. (This is quite unlike C++ "const".) "in" would be a promise
 by the programmer, and could not be guaranteed by the compiler - but - the
 optimizer can take advantage of this promise to generate perhaps
 significantly better code. (With C++ "const", values can change at any momen
 t by another reference or another thread, making optimizations based on
 "const" impossible.)
 

I think that's similar to what Pascal does, and that's something I agree with. One point that isn't addressed yet (I think) is returning something: can it be modified? What happens if it's modified? etc. -- Carlos Santander Bernal
Jul 01 2005
parent "Walter" <newshound digitalmars.com> writes:
"Carlos Santander" <csantander619 gmail.com> wrote in message
news:da4e0i$27v9$1 digitaldaemon.com...
 One point that isn't addressed yet (I think) is returning something: can
 it be modified? What happens if it's modified? etc.

With the 'in' compromise, it doesn't address return values.
Jul 02 2005
prev sibling next sibling parent "Dave" <Dave_member pathlink.com> writes:
"Walter" <newshound digitalmars.com> wrote in message 
news:da2v7t$b9b$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:da024r$65o$1 digitaldaemon.com...
 I would like to discuss one of my previous ideas again
 as it seems it was lost in the fire.

So far, I haven't thought of anything that makes consistent sense, and doesn't look like an ugly hack. One thing I have thought of is a compromise. Change the semantics of explicitly "in" parameters to be what Andrei calls "deep immutable". Deep immutable parameters would have unchanging values for the scope of that parameter, and also every sub-object reachable by that parameter would also be unchangeable. The values wouldn't change even by another reference or another thread. (This is quite unlike C++ "const".) "in" would be a promise by the programmer, and could not be guaranteed by the compiler - but - the optimizer can take advantage of this promise to generate perhaps significantly better code. (With C++ "const", values can change at any momen t by another reference or another thread, making optimizations based on "const" impossible.)

One other thought - Make it so that an "explicit in" makes a copy as it does now, and the default (non-specified) param. storage class is "deep immutable". Pointer params would act the same as they do now regardless, and functions with extern(...) would be exempt as well. If pointers were taken out of the picture, why couldn't the compiler catch cases like below? class C { ... } void foo(C c, int[] arr) { // Errors c = new C; c.i = 10; int* z = &c.i; bar(c); C x = c; arr = new int[20]; arr[10] = 10; arr[] = 0; int[] b = arr; int[] b4 = arr[0..10]; int* y = &a[5]; // Ok int[] b2 = arr.dup; int[] b3 = arr[]; int[] b5 = arr[0..10].dup; int* p = cast(int*)&a[6]; void* v = cast(void*)&a[6]; *(cast(int*)v) = 700; baz(c); } void bar(inout C x) { ... } void baz(C x) { ... } In all those cases either the param is directly an lvalue /or/ the address of the param is directly taken, or the same for a member of an aggregate. The spec. would explicitly say "the compiler is responsible for checking /only/ for cases where "either the param (or one of it's aggragate members) is directly assigned to, the address of the param (or one of its aggragate members) is directly taken or the param (or an aggregate member) is directly passed into a function via an out or inout parameter. All other cases are undefined."
Jul 02 2005
prev sibling parent "Dave" <Dave_member pathlink.com> writes:
"Walter" <newshound digitalmars.com> wrote in message 
news:da2v7t$b9b$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:da024r$65o$1 digitaldaemon.com...
 I would like to discuss one of my previous ideas again
 as it seems it was lost in the fire.

I've been discussing this issue with Andrei (of Modern C++ Design fame). He points out that there are numerous different "const" semantics, each having their uses and disadvantages. He suggests that all should be supported in one way or another, and I agree that that would have some advantages. One of my (several) dislikes with "const" is that most (90% ?) of a function's parameters are likely to be "const". So one winds up with the C++ aesthetically ugly consequence of "const" here, there, everywhere. And you can't use it casually here and there, once you start down the road of making a few functions have "const" parameters, you've got to do it throughout the program. So perhaps one could turn that inside out, and make "const" the default for function parameters. If the parameter was to be changed, it'd be explicitly marked as "mutable" or some such. But that runs into another problem. Function local variables, on the other hand, one would want to be "mutable" by default. There's also the issue that "const" already exists as a variable storage class.

I guess I don't understand why this is a problem because there has always been a 'seperation' and distinction between locals and params to me. I realize there is a union of scope inside the function and they share many of the same syntax and semantic rules as variables, but I've always considered them two seperate and distinct groups of vars. I think most non-newbie programmers realize this and recognize that any params passed by reference also 'live' outside of the function. Why do you think a typical programmer would be completely put off by the idea that an 'implicit in' param couldn't be modified, while by default a local variable could (especially if the compiler would constantly reinforce the idea that "hey - D's default params are different" by reporting trivial-case errors)? Thanks, - Dave
Jul 04 2005