www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Round II, Re: Immutable arrays for Walter and rest of us.

reply "Andrew Fedoniouk" <news terrainformatica.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. 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.

I think that "deep immutables" ((C) Andrei Alexandrescu, I guess) are ideal but too deep to be considered as a solution for practical (read fast) compiler. L-value analysis in this case might be a) cyclic (not sure but highly suspect this) and b) too complex - depth of trees. ----------------------------- I would like to emphasize my proposal again: First of all: D already has mechanism to force (to implement) deep immutability. class Immutable { public int prop() { ... } [private] int prop(int v) { assert(false); } SomeObject propO() { return ([this is immutable])? new Immutable(): new Mutable(); } } As you can see mutating properties/methods can be disabled at compile time ( private accessor ) and/or at runtime ( assert-throw ) Main logical/design conflict is: there is no such (available to developer) mechanism for arrays and pointers. They are 'naked' - always mutable. Main idea of my proposal is in defining new array and pointer types: immutable array and immutable pointer. typename #[] typename #* Please pay attention that there is no whitespace between # and [ Here # is not a shortcut for const ! It is part of #[] declaration. Let's say that D array type internally declared as primitive "[ ]" (T) { private T *_ptr; private uint _length; T * ptr() { return _ptr; } private void ptr(T *) { } // ptr is not an L-value. uint length() { return _length; } uint length(uint nl) { resize(); return _length; } void opIndexAssign(int index, T v) { _ptr[ index ] = v; } void opAssign(struct "[ ]" (T) r) { _ptr = r._ptr; _length = r._length; } } Then #[] - immutable array type will be (internally) declared as: primitive "#[ ]" (T) { private T #*_ptr; private uint _length; T #* ptr() { return _ptr; } uint length() { return _length; } private uint length(uint nl) { resize(); return _length; } // no such op available private void opIndexAssign(int index, T v); // no such op available private void opAssign(struct "[ ]" (T) r); // no such op available // but this one is here - immutable <- immutable : void opAssign(struct "#[ ]" (T) r) { _ptr = r._ptr; _length = r._length; } } As you may see implementation of #[] is pretty straightforward and simple. Having it you'll close the only one "immutability hole" left in D. Again, structs and classes already have a protection layer availbale - you can always create a protecting perimeter for your classes/structs: public property-methods and just methods of any needed depth. You can return from functions mutable or immutable struct and class instances using various policies. If you will implement #[] and #* then type system will be complete (almost perfect) - *all* D types will have an option to be immutable. Andrew.
Jul 01 2005
parent reply "Ben Hinkle" <bhinkle mathworks.com> writes:
 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.

I think that "deep immutables" ((C) Andrei Alexandrescu, I guess) are ideal but too deep to be considered as a solution for practical (read fast) compiler. L-value analysis in this case might be a) cyclic (not sure but highly suspect this) and b) too complex - depth of trees. ----------------------------- I would like to emphasize my proposal again: First of all: D already has mechanism to force (to implement) deep immutability. class Immutable { public int prop() { ... } [private] int prop(int v) { assert(false); } SomeObject propO() { return ([this is immutable])? new Immutable(): new Mutable(); } } As you can see mutating properties/methods can be disabled at compile time ( private accessor ) and/or at runtime ( assert-throw )

How would this cover the following case that Walter's proposal covers: class A { int x; } void foo(in A obj){ int y = obj.x; // do whatever you want... assert( obj.x == y ); } void main() { A obj = new A; foo(obj); // says it doesn't change obj } Is it practical to force A to implement some immutability just because foo doesn't change its inputs? I'm not saying Walter's proposal is prefect. It's very strong for foo to say no other thread or reference will change obj since it has no control over what other threads are doing. I would be taking pretty much blind leap of faith when declaring an object reference as 'in' and saying that no other thread is stepping on that object during the call lifetime.
 Main logical/design conflict is: there is no such (available to developer)
 mechanism for arrays and pointers. They are 'naked' - always mutable.

 Main idea of my proposal is in defining new array and pointer types:

 immutable array and immutable pointer.

 typename #[]
 typename #*

 Please pay attention that there is no whitespace between # and [
 Here # is not a shortcut for const !  It is part of #[] declaration.

Why is the lack of whitespace between the # and the [ significant?
 Let's say that D array type internally declared as

 As you may see implementation of #[] is pretty straightforward and simple.

The complexity of the implementation is one thing - another is the impact of introducing a new array type (and pointer type) on existing and future user code.
 Having it you'll close the only one "immutability hole" left in D.

 Again, structs and classes already have a protection layer availbale -
 you can always create a protecting perimeter for your classes/structs:
 public property-methods and just methods of any needed depth.
 You can return from functions mutable or immutable struct and class 
 instances
 using various policies.

 If you will implement #[] and #* then type system will be complete (almost 
 perfect) -
 *all* D types will have an option to be immutable.

 Andrew.

Jul 01 2005
next sibling parent "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Ben Hinkle" <bhinkle mathworks.com> wrote in message 
news:da4afr$24jc$1 digitaldaemon.com...
 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.

I think that "deep immutables" ((C) Andrei Alexandrescu, I guess) are ideal but too deep to be considered as a solution for practical (read fast) compiler. L-value analysis in this case might be a) cyclic (not sure but highly suspect this) and b) too complex - depth of trees. ----------------------------- I would like to emphasize my proposal again: First of all: D already has mechanism to force (to implement) deep immutability. class Immutable { public int prop() { ... } [private] int prop(int v) { assert(false); } SomeObject propO() { return ([this is immutable])? new Immutable(): new Mutable(); } } As you can see mutating properties/methods can be disabled at compile time ( private accessor ) and/or at runtime ( assert-throw )

How would this cover the following case that Walter's proposal covers: class A { int x; } void foo(in A obj){ int y = obj.x; // do whatever you want... assert( obj.x == y ); } void main() { A obj = new A; foo(obj); // says it doesn't change obj } Is it practical to force A to implement some immutability just because foo doesn't change its inputs? I'm not saying Walter's proposal is prefect. It's very strong for foo to say no other thread or reference will change obj since it has no control over what other threads are doing. I would be taking pretty much blind leap of faith when declaring an object reference as 'in' and saying that no other thread is stepping on that object during the call lifetime.

in/inout/out describes mechanism of passing parameters - by ref or by value. foo( in char[] str ) means that value of str will not be changed after return from function. But it does not disallow you to change the value of str is pointing to. This makes perfect sense for me. foo( in char#[] str ) means that str will not be changed after return and as by definition of immutable array content pointed by str.ptr will not be changed. foo( in char#[] str ) foo( inout char#[] str ) foo( out char#[] str ) all have usable sense as do foo( in char[] str ) foo( inout char[] str ) foo( out char[] str ) Please don't change this. in is not a const in any sense. 'in' does not allow you to have immutable arrays as properties - and this is imho most valueable thing. One more: as char[] and char#[] are friendly but distinct types thus they allow you and compiler to distinguish cases: foo( char#[] str ) foo( char[] str ) thus to build more optimal code structure. With just 'in' it is impossible. Remeber duscussed problem with stream.scanf parameters?
 Main logical/design conflict is: there is no such (available to 
 developer)
 mechanism for arrays and pointers. They are 'naked' - always mutable.

 Main idea of my proposal is in defining new array and pointer types:

 immutable array and immutable pointer.

 typename #[]
 typename #*

 Please pay attention that there is no whitespace between # and [
 Here # is not a shortcut for const !  It is part of #[] declaration.

Why is the lack of whitespace between the # and the [ significant?

Because '#' is not a keyword like const as it is part of lexical sequence: #[]. In short #[ and #* accepted as one symbol by lexer making '#' free to use for other purposes. Pretty much as '+ =' and '+='
 Let's say that D array type internally declared as

 As you may see implementation of #[] is pretty straightforward and 
 simple.

The complexity of the implementation is one thing - another is the impact of introducing a new array type (and pointer type) on existing and future user code.

Existing code will not be impacted heavily. It depends of what static array will be. For statics char#[] makes perfect sense. If only typename#[] variables can have static initializers - this will significantly simplify life and make D clear. Now it is just sequence of "why's" - why it allowed here and not there. Considering Harmonia switch to use of char#[] : First step - to make it compileable is 15 minutes - exactly the same amount of time it took me to replace all inner classes with static inner classes.
 Having it you'll close the only one "immutability hole" left in D.

 Again, structs and classes already have a protection layer availbale -
 you can always create a protecting perimeter for your classes/structs:
 public property-methods and just methods of any needed depth.
 You can return from functions mutable or immutable struct and class 
 instances
 using various policies.

 If you will implement #[] and #* then type system will be complete 
 (almost perfect) -
 *all* D types will have an option to be immutable.

 Andrew.


Jul 01 2005
prev sibling parent reply "Walter" <newshound digitalmars.com> writes:
"Ben Hinkle" <bhinkle mathworks.com> wrote in message
news:da4afr$24jc$1 digitaldaemon.com...
 How would this cover the following case that Walter's proposal covers:
 class A { int x; }
 void foo(in A obj){
   int y = obj.x;
   // do whatever you want...
   assert( obj.x == y );
 }
 void main() {
   A obj = new A;
   foo(obj); // says it doesn't change obj
 }
 Is it practical to force A to implement some immutability just because foo
 doesn't change its inputs? I'm not saying Walter's proposal is prefect.

 very strong for foo to say no other thread or reference will change obj
 since it has no control over what other threads are doing. I would be

 pretty much blind leap of faith when declaring an object reference as 'in'
 and saying that no other thread is stepping on that object during the call
 lifetime.

You're right. I have misgivings about it for that reason. On the other hand, look at C++ "const". Nothing about "const" says that some other thread or reference cannot change the value out from under you at any moment. Furthermore, it can be cast away and modified anyway. The semantic value of C++ "const" is essentially zip. This is why I am often flummoxed why it is given such weight in C++.
Jul 02 2005
next sibling parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
"Walter" <newshound digitalmars.com> wrote in message 
news:da6k71$11rs$1 digitaldaemon.com...
 "Ben Hinkle" <bhinkle mathworks.com> wrote in message
 news:da4afr$24jc$1 digitaldaemon.com...
 How would this cover the following case that Walter's proposal covers:
 class A { int x; }
 void foo(in A obj){
   int y = obj.x;
   // do whatever you want...
   assert( obj.x == y );
 }
 void main() {
   A obj = new A;
   foo(obj); // says it doesn't change obj
 }
 Is it practical to force A to implement some immutability just because 
 foo
 doesn't change its inputs? I'm not saying Walter's proposal is prefect.

 very strong for foo to say no other thread or reference will change obj
 since it has no control over what other threads are doing. I would be

 pretty much blind leap of faith when declaring an object reference as 
 'in'
 and saying that no other thread is stepping on that object during the 
 call
 lifetime.

You're right. I have misgivings about it for that reason. On the other hand, look at C++ "const". Nothing about "const" says that some other thread or reference cannot change the value out from under you at any moment. Furthermore, it can be cast away and modified anyway. The semantic value of C++ "const" is essentially zip. This is why I am often flummoxed why it is given such weight in C++.

Personally I'm also surprised people are so paranoid in D about possible COW violations. What's the phrase from Spiderman ... "with great power comes great responsibility" :-) It's funny that Java and C# don't have const and people seem to survive. Granted in Java people IMO overcompensate by dup'ing too often so I hope D users don't go that route.
Jul 02 2005
parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Ben Hinkle" <ben.hinkle gmail.com> wrote in message 
news:da7fo5$bje$1 digitaldaemon.com...
 "Walter" <newshound digitalmars.com> wrote in message 
 news:da6k71$11rs$1 digitaldaemon.com...
 "Ben Hinkle" <bhinkle mathworks.com> wrote in message
 news:da4afr$24jc$1 digitaldaemon.com...
 How would this cover the following case that Walter's proposal covers:
 class A { int x; }
 void foo(in A obj){
   int y = obj.x;
   // do whatever you want...
   assert( obj.x == y );
 }
 void main() {
   A obj = new A;
   foo(obj); // says it doesn't change obj
 }
 Is it practical to force A to implement some immutability just because 
 foo
 doesn't change its inputs? I'm not saying Walter's proposal is prefect.

 very strong for foo to say no other thread or reference will change obj
 since it has no control over what other threads are doing. I would be

 pretty much blind leap of faith when declaring an object reference as 
 'in'
 and saying that no other thread is stepping on that object during the 
 call
 lifetime.

You're right. I have misgivings about it for that reason. On the other hand, look at C++ "const". Nothing about "const" says that some other thread or reference cannot change the value out from under you at any moment. Furthermore, it can be cast away and modified anyway. The semantic value of C++ "const" is essentially zip. This is why I am often flummoxed why it is given such weight in C++.

Personally I'm also surprised people are so paranoid in D about possible COW violations. What's the phrase from Spiderman ... "with great power comes great responsibility" :-) It's funny that Java and C# don't have const and people seem to survive. Granted in Java people IMO overcompensate by dup'ing too often so I hope D users don't go that route.

"Java and C# don't have const" Umm... Java has 'final' keyword. You define an entity once and cannot change it or derive from it later. More specifically: a final class cannot be subclassed, a final method cannot be overridden and a final variable cannot change from its initialized value. Function parameters can also be declared as final. C# has 'readonly' keyword. It can be used in declaration of class fields and in declaration of function parameters. C# has also const keyword which is pretty much D keyword except of C#::const is protecting also references. E.g. you cannot say "hello"[0] = 'b'; And more regarding strings in these systems: Java/.NET String "package" consist of 1) String class (immutable) and 2) StringBuffer (mutable) class Literal strings there are instances of String class which is immutable, sic! I would like to highlight this again: In modern programming systems string implementation is a bundle of friendly value classes (immutable) and buffer (mutable) classes. D currently has only StringBuffer (sort of). Only char#[] and char[] *together* can be considered as "string in D" by C++, Java or C# programmers.
Jul 02 2005
next sibling parent reply Stefan Zobel <Stefan_member pathlink.com> writes:
In article <da7i52$cv9$1 digitaldaemon.com>, Andrew Fedoniouk says...
"Ben Hinkle" <ben.hinkle gmail.com> wrote in message 
news:da7fo5$bje$1 digitaldaemon.com...

"Java and C# don't have const"

Umm...

Java has 'final' keyword. You define an entity once and cannot change it or 
derive from it later. More specifically: a final class cannot be subclassed, 
a final method cannot be overridden and a final variable cannot change from 
its initialized value. Function parameters can also be declared as final.

C# has 'readonly' keyword. It can be used in declaration of class fields and 
in declaration of function parameters.
C# has also const keyword which is pretty much D keyword except of C#::const 
is protecting also references. E.g. you cannot
say "hello"[0] = 'b';

And more regarding strings in these systems:

Java/.NET String "package" consist of

1) String class (immutable) and
2) StringBuffer (mutable) class

Literal strings there are instances of String class
which is immutable, sic!

I would like to highlight this again:

In modern programming systems string implementation is a bundle
of friendly value classes (immutable) and buffer (mutable) classes.

D currently has only StringBuffer (sort of).

Only char#[] and char[] *together* can be considered as "string in D" by
C++, Java or C# programmers.

Hi Andrew, hhm, I agree with most of your points here. You once said in this discussion that it is impossible to implement something like Java String in D. Apart from D string literals (char[]), I fail to see why. Could you please explain? Kind regards, Stefan (Of course, I think, we all agree that unnecessary dup'ing is undesirable, but that doesn't render it "impossible").
Jul 02 2005
parent "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Stefan Zobel" <Stefan_member pathlink.com> wrote in message 
news:da7jlk$dtk$1 digitaldaemon.com...
 In article <da7i52$cv9$1 digitaldaemon.com>, Andrew Fedoniouk says...
"Ben Hinkle" <ben.hinkle gmail.com> wrote in message
news:da7fo5$bje$1 digitaldaemon.com...

"Java and C# don't have const"

Umm...

Java has 'final' keyword. You define an entity once and cannot change it 
or
derive from it later. More specifically: a final class cannot be 
subclassed,
a final method cannot be overridden and a final variable cannot change 
from
its initialized value. Function parameters can also be declared as final.

C# has 'readonly' keyword. It can be used in declaration of class fields 
and
in declaration of function parameters.
C# has also const keyword which is pretty much D keyword except of 
C#::const
is protecting also references. E.g. you cannot
say "hello"[0] = 'b';

And more regarding strings in these systems:

Java/.NET String "package" consist of

1) String class (immutable) and
2) StringBuffer (mutable) class

Literal strings there are instances of String class
which is immutable, sic!

I would like to highlight this again:

In modern programming systems string implementation is a bundle
of friendly value classes (immutable) and buffer (mutable) classes.

D currently has only StringBuffer (sort of).

Only char#[] and char[] *together* can be considered as "string in D" by
C++, Java or C# programmers.

Hi Andrew, hhm, I agree with most of your points here. You once said in this discussion that it is impossible to implement something like Java String in D. Apart from D string literals (char[]), I fail to see why. Could you please explain? Kind regards, Stefan (Of course, I think, we all agree that unnecessary dup'ing is undesirable, but that doesn't render it "impossible").

(Sorry, missed your message initially) Strictly speaking it is possible to define String in D with exact set of methods and behavior as Java string. Mea culpa - I was not exact in terms. I mean it is almost impossible to use such String effectively. System and OS functions demands char* which you cannot get from String by its specification. Powerfull mechanism of slices is also lost here. Yes, as you mentioned, you can dup on each opSlice call but this is not a practical option. Again beg my pardon. Andrew.
Jul 04 2005
prev sibling parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message 
news:da7i52$cv9$1 digitaldaemon.com...
 "Ben Hinkle" <ben.hinkle gmail.com> wrote in message 
 news:da7fo5$bje$1 digitaldaemon.com...
 "Walter" <newshound digitalmars.com> wrote in message 
 news:da6k71$11rs$1 digitaldaemon.com...
 "Ben Hinkle" <bhinkle mathworks.com> wrote in message
 news:da4afr$24jc$1 digitaldaemon.com...
 How would this cover the following case that Walter's proposal covers:
 class A { int x; }
 void foo(in A obj){
   int y = obj.x;
   // do whatever you want...
   assert( obj.x == y );
 }
 void main() {
   A obj = new A;
   foo(obj); // says it doesn't change obj
 }
 Is it practical to force A to implement some immutability just because 
 foo
 doesn't change its inputs? I'm not saying Walter's proposal is prefect.

 very strong for foo to say no other thread or reference will change obj
 since it has no control over what other threads are doing. I would be

 pretty much blind leap of faith when declaring an object reference as 
 'in'
 and saying that no other thread is stepping on that object during the 
 call
 lifetime.

You're right. I have misgivings about it for that reason. On the other hand, look at C++ "const". Nothing about "const" says that some other thread or reference cannot change the value out from under you at any moment. Furthermore, it can be cast away and modified anyway. The semantic value of C++ "const" is essentially zip. This is why I am often flummoxed why it is given such weight in C++.

Personally I'm also surprised people are so paranoid in D about possible COW violations. What's the phrase from Spiderman ... "with great power comes great responsibility" :-) It's funny that Java and C# don't have const and people seem to survive. Granted in Java people IMO overcompensate by dup'ing too often so I hope D users don't go that route.

"Java and C# don't have const" Umm... Java has 'final' keyword. You define an entity once and cannot change it or derive from it later. More specifically: a final class cannot be subclassed, a final method cannot be overridden and a final variable cannot change from its initialized value. Function parameters can also be declared as final.

Currently D's final is more limited than Java's but I have always assumed D's final will eventually match Java's. It still isn't the same as C++'s const, though.
 C# has 'readonly' keyword. It can be used in declaration of class fields 
 and in declaration of function parameters.
 C# has also const keyword which is pretty much D keyword except of 
 C#::const is protecting also references. E.g. you cannot
 say "hello"[0] = 'b';

Sure, but this, too, isn't const. D has getters and setters so one can make readonly properties. I know about C#'s const vaguely but I'm not sure what you mean by "is protecting also references". The example you give is of a string but strings are immutable and are independent of C#'s const keyword as far as I know. How does one make a non-string reference const?
 And more regarding strings in these systems:

 Java/.NET String "package" consist of

 1) String class (immutable) and
 2) StringBuffer (mutable) class

 Literal strings there are instances of String class
 which is immutable, sic!

Immutable strings is really the only place where D diverges from Java/C#. It's also probably the most common use of const in C++. To me that isn't enough reason to introduce const, though.
 I would like to highlight this again:

 In modern programming systems string implementation is a bundle
 of friendly value classes (immutable) and buffer (mutable) classes.

 D currently has only StringBuffer (sort of).

 Only char#[] and char[] *together* can be considered as "string in D" by
 C++, Java or C# programmers.

Why bother with multiple types/classes when D already spanks the competition with one? We should keep things as simple as possible.
Jul 02 2005
parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Ben Hinkle" <ben.hinkle gmail.com> wrote in message 
news:da7mmr$fjl$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message 
 news:da7i52$cv9$1 digitaldaemon.com...
 "Ben Hinkle" <ben.hinkle gmail.com> wrote in message 
 news:da7fo5$bje$1 digitaldaemon.com...
 "Walter" <newshound digitalmars.com> wrote in message 
 news:da6k71$11rs$1 digitaldaemon.com...
 "Ben Hinkle" <bhinkle mathworks.com> wrote in message
 news:da4afr$24jc$1 digitaldaemon.com...
 How would this cover the following case that Walter's proposal covers:
 class A { int x; }
 void foo(in A obj){
   int y = obj.x;
   // do whatever you want...
   assert( obj.x == y );
 }
 void main() {
   A obj = new A;
   foo(obj); // says it doesn't change obj
 }
 Is it practical to force A to implement some immutability just because 
 foo
 doesn't change its inputs? I'm not saying Walter's proposal is 
 prefect.

 very strong for foo to say no other thread or reference will change 
 obj
 since it has no control over what other threads are doing. I would be

 pretty much blind leap of faith when declaring an object reference as 
 'in'
 and saying that no other thread is stepping on that object during the 
 call
 lifetime.

You're right. I have misgivings about it for that reason. On the other hand, look at C++ "const". Nothing about "const" says that some other thread or reference cannot change the value out from under you at any moment. Furthermore, it can be cast away and modified anyway. The semantic value of C++ "const" is essentially zip. This is why I am often flummoxed why it is given such weight in C++.

Personally I'm also surprised people are so paranoid in D about possible COW violations. What's the phrase from Spiderman ... "with great power comes great responsibility" :-) It's funny that Java and C# don't have const and people seem to survive. Granted in Java people IMO overcompensate by dup'ing too often so I hope D users don't go that route.

"Java and C# don't have const" Umm... Java has 'final' keyword. You define an entity once and cannot change it or derive from it later. More specifically: a final class cannot be subclassed, a final method cannot be overridden and a final variable cannot change from its initialized value. Function parameters can also be declared as final.

Currently D's final is more limited than Java's but I have always assumed D's final will eventually match Java's. It still isn't the same as C++'s const, though.

Yes, Java::final is not a C::const (it cannot protect references). Java::final is exactly D::const now except of Java::final can be used in function parameters declaration and D's counterpart - cannot. I have no idea of what D::final means. It is defined as a keyword but have no meaning so far, AFAIK. (correct me.)
 C# has 'readonly' keyword. It can be used in declaration of class fields 
 and in declaration of function parameters.
 C# has also const keyword which is pretty much D keyword except of 
 C#::const is protecting also references. E.g. you cannot
 say "hello"[0] = 'b';

Sure, but this, too, isn't const. D has getters and setters so one can make readonly properties. I know about C#'s const vaguely but I'm not sure what you mean by "is protecting also references". The example you give is of a string but strings are immutable and are independent of C#'s const keyword as far as I know. How does one make a non-string reference const?

Mea culpa, C# example and my statement about it is terribly wrong. C# cannot implement 'const correctnes' ( http://en.wikipedia.org/wiki/Const_correctness ) too. Neither do Java. But they do have immutable strings, you are right higlighting this.
 And more regarding strings in these systems:

 Java/.NET String "package" consist of

 1) String class (immutable) and
 2) StringBuffer (mutable) class

 Literal strings there are instances of String class
 which is immutable, sic!

Immutable strings is really the only place where D diverges from Java/C#. It's also probably the most common use of const in C++. To me that isn't enough reason to introduce const, though.

std.openrj.d: class Record { Field[] fields() { return m_fields.dup; } } Do you like this dup? class Field { final char[] name() { return m_name; } } Pay attention that std.openrj is an attempt to create OOP, reusable, effective and robust library module in D. Lack of constness is seen in each class of it.
 I would like to highlight this again:

 In modern programming systems string implementation is a bundle
 of friendly value classes (immutable) and buffer (mutable) classes.

 D currently has only StringBuffer (sort of).

 Only char#[] and char[] *together* can be considered as "string in D" by
 C++, Java or C# programmers.

Why bother with multiple types/classes when D already spanks the competition with one? We should keep things as simple as possible.

Agreed in principle, but "simple as possible" does not mean "sancta simplicitas", right? "I'll give you my slice and don't forget to dup it as it is not yours." This does not work in serious programming as slice creation happens in one place and its consuming in galaxy far far away and code of three developers happens in between. It is EXTREMELY difficult to debug. I know. It happened to me once in Harmonia and I wasted almost three days to catch it. Sigh... And I was designing it by myself - not even in team... Andrew.
Jul 02 2005
parent reply "Walter" <newshound digitalmars.com> writes:
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message
news:da7s6r$jcd$1 digitaldaemon.com...
 "I'll give you my slice and don't forget to dup it as it is not yours."
 This does not work in serious programming as
 slice creation happens in one place and its consuming
 in galaxy far far away and code of three developers
 happens in between. It is EXTREMELY difficult to debug.
 I know. It happened to me once in Harmonia and I wasted
 almost three days to catch it. Sigh...
 And I was designing it by myself - not even in team...

The COW rule for when to .dup is: When you're going to change the data, and you're not *sure* you're the sole handle to it. I don't see why the need is there for m_fields.dup in openrj.d. Preemptively duping something by the provider is the wrong approach to COW. Duping should be done by the consumer of it, and then only if the consumer modifies it.
Jul 02 2005
parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Walter" <newshound digitalmars.com> wrote in message 
news:da7u7k$kkh$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:da7s6r$jcd$1 digitaldaemon.com...
 "I'll give you my slice and don't forget to dup it as it is not yours."
 This does not work in serious programming as
 slice creation happens in one place and its consuming
 in galaxy far far away and code of three developers
 happens in between. It is EXTREMELY difficult to debug.
 I know. It happened to me once in Harmonia and I wasted
 almost three days to catch it. Sigh...
 And I was designing it by myself - not even in team...

The COW rule for when to .dup is: When you're going to change the data, and you're not *sure* you're the sole handle to it.

In real projects and in real life this *not sure* is almost always.
 I don't see why the need is there for m_fields.dup in openrj.d. 
 Preemptively
 duping something by the provider is the wrong approach to COW. Duping 
 should
 be done by the consumer of it, and then only if the consumer modifies it.

I know this theory. The whole team are C++ programmers. They get used to const. And you know.... this is really a "code culture" thing - respect of developers who are working with you and using your code. const - it is mine - don't touch it. no const - it is yours. And C++ compiler helps us a lot here to prevent stupid mistakes. All most respectfull C++ guys are unified in 'const is good'' http://artima.com/intv/const.html Shall I tell my team that const is wrong because: "it is useless for optimizing"? I'll never will do that, sorry. pointers are so effective but dangerous. without const they are dangerous in order of magnitude. The same apply to D slices. Andrew.
Jul 02 2005
parent reply "Walter" <newshound digitalmars.com> writes:
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message
news:da818n$md2$1 digitaldaemon.com...
 "Walter" <newshound digitalmars.com> wrote in message
 news:da7u7k$kkh$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:da7s6r$jcd$1 digitaldaemon.com...
 "I'll give you my slice and don't forget to dup it as it is not yours."
 This does not work in serious programming as
 slice creation happens in one place and its consuming
 in galaxy far far away and code of three developers
 happens in between. It is EXTREMELY difficult to debug.
 I know. It happened to me once in Harmonia and I wasted
 almost three days to catch it. Sigh...
 And I was designing it by myself - not even in team...

The COW rule for when to .dup is: When you're going to change the data, and you're not *sure* you're


 sole handle to it.

In real projects and in real life this *not sure* is almost always.

True, but it's also true that most of the time, one doesn't care because one has no need to modify the data.
 I don't see why the need is there for m_fields.dup in openrj.d.
 Preemptively
 duping something by the provider is the wrong approach to COW. Duping
 should
 be done by the consumer of it, and then only if the consumer modifies


 I know this theory.

 The whole team are C++ programmers. They get used to const.
 And you know.... this is really a "code culture" thing -
 respect of developers who are working with you and using
 your code.
 const - it is mine - don't touch it. no const - it is yours.
 And C++ compiler helps us a lot here to prevent stupid mistakes.

 All most respectfull C++ guys are unified in 'const is good''
 http://artima.com/intv/const.html
 Shall I tell my team that const is wrong because:
 "it is useless for optimizing"?
 I'll never will do that, sorry.

C++ const benefits are greater than zero, even though it is useless to the optimizer as it gives no meaningful semantic information.
 pointers are so effective but dangerous. without const they are
 dangerous in order of magnitude. The same apply to D slices.

I find it curious that many features of C++ have leaked out into other languages, but not const. I agree with you that C++ has a culture of "const is good". I'd like to find something better, something that works (i.e. that gives useful semantic information). I also am not understanding how const would help with COW mistakes.
Jul 03 2005
parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Walter" <newshound digitalmars.com> wrote in message 
news:da888e$rhs$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:da818n$md2$1 digitaldaemon.com...
 "Walter" <newshound digitalmars.com> wrote in message
 news:da7u7k$kkh$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:da7s6r$jcd$1 digitaldaemon.com...
 "I'll give you my slice and don't forget to dup it as it is not 
 yours."
 This does not work in serious programming as
 slice creation happens in one place and its consuming
 in galaxy far far away and code of three developers
 happens in between. It is EXTREMELY difficult to debug.
 I know. It happened to me once in Harmonia and I wasted
 almost three days to catch it. Sigh...
 And I was designing it by myself - not even in team...

The COW rule for when to .dup is: When you're going to change the data, and you're not *sure* you're


 sole handle to it.

In real projects and in real life this *not sure* is almost always.

True, but it's also true that most of the time, one doesn't care because one has no need to modify the data.

Absolutely true. This is why e.g. string literals shall have type const char[] and not just a char[] by default. This is stupid design mistake in C++: "hello"[0] = 0; will compile and run on one machines and will not on others.
 I don't see why the need is there for m_fields.dup in openrj.d.
 Preemptively
 duping something by the provider is the wrong approach to COW. Duping
 should
 be done by the consumer of it, and then only if the consumer modifies


 I know this theory.

 The whole team are C++ programmers. They get used to const.
 And you know.... this is really a "code culture" thing -
 respect of developers who are working with you and using
 your code.
 const - it is mine - don't touch it. no const - it is yours.
 And C++ compiler helps us a lot here to prevent stupid mistakes.

 All most respectfull C++ guys are unified in 'const is good''
 http://artima.com/intv/const.html
 Shall I tell my team that const is wrong because:
 "it is useless for optimizing"?
 I'll never will do that, sorry.

C++ const benefits are greater than zero, even though it is useless to the optimizer as it gives no meaningful semantic information.
 pointers are so effective but dangerous. without const they are
 dangerous in order of magnitude. The same apply to D slices.

I find it curious that many features of C++ have leaked out into other languages, but not const.

Walter, need of const appears together with raw pointers. It is critical to have pointers (slices included) together with const. If some language takes ++ from C but not pointers then it does not need const so much. There is no language in active use which has raw pointers and has no concept of pointers to const data. Even C. It had no const from the very beginning. But C99 (year of 1999, sic) has it. const is simply a type designator: const typename* and typename* *are* different types - with different behavior. Combining them in one entity as you did in D design is exactly the same as having only one int type without unsigned counterpart.
 I agree with you that C++ has a culture of "const is good".

 I'd like to find something better, something that works (i.e. that gives
 useful semantic information).

 I also am not understanding how const would help with COW mistakes.

What are the "COW mistakes"? I don't understand this exactly.... Anyway.... void toLower(in char[] str) char[] toLower(in const char[] str) Having them both is a matter of optimization. First does transformation in place, second allocates new string. Do these two together make sense? Definitely, yes.
Jul 03 2005
parent reply "Walter" <newshound digitalmars.com> writes:
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message
news:da97g2$1l30$1 digitaldaemon.com...
 "Walter" <newshound digitalmars.com> wrote in message
 news:da888e$rhs$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:da818n$md2$1 digitaldaemon.com...
 "Walter" <newshound digitalmars.com> wrote in message
 news:da7u7k$kkh$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:da7s6r$jcd$1 digitaldaemon.com...
 "I'll give you my slice and don't forget to dup it as it is not
 yours."
 This does not work in serious programming as
 slice creation happens in one place and its consuming
 in galaxy far far away and code of three developers
 happens in between. It is EXTREMELY difficult to debug.
 I know. It happened to me once in Harmonia and I wasted
 almost three days to catch it. Sigh...
 And I was designing it by myself - not even in team...

The COW rule for when to .dup is: When you're going to change the data, and you're not *sure* you're


 sole handle to it.

In real projects and in real life this *not sure* is almost always.

True, but it's also true that most of the time, one doesn't care because one has no need to modify the data.

Absolutely true. This is why e.g. string literals shall have type const char[] and not just a char[] by default. This is stupid design mistake in C++: "hello"[0] = 0; will compile and run on one machines and will not on others.

It is an error in C++ to do that, though it is allowed by some compilers for backwards compatibility. In C++, string literals are const char*.
 Walter, need of const appears together with raw pointers.
 It is critical to have pointers (slices included) together
 with const.

 If some language takes ++ from C but not pointers then
 it does not need const so much.

 There is no language in active use which has raw pointers
 and has no concept of pointers to const data.

I don't know of any language that even allows raw pointers other than C, C++ and D!
 I agree with you that C++ has a culture of "const is good".

 I'd like to find something better, something that works (i.e. that gives
 useful semantic information).

 I also am not understanding how const would help with COW mistakes.

What are the "COW mistakes"? I don't understand this exactly....

A COW mistake would be, for example, modifying a reference when you aren't sure you're the owner of it.
 Anyway....

 void  toLower(in char[] str)
 char[]  toLower(in const char[] str)


 Having them both is a matter of optimization.
 First does transformation in place, second allocates
 new string.

 Do these two together make sense? Definitely, yes.

See my comments on this example in another post here.
Jul 03 2005
parent "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Walter" <newshound digitalmars.com> wrote in message 
news:da9dc2$1r5s$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:da97g2$1l30$1 digitaldaemon.com...
 "Walter" <newshound digitalmars.com> wrote in message
 news:da888e$rhs$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:da818n$md2$1 digitaldaemon.com...
 "Walter" <newshound digitalmars.com> wrote in message
 news:da7u7k$kkh$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:da7s6r$jcd$1 digitaldaemon.com...
 "I'll give you my slice and don't forget to dup it as it is not
 yours."
 This does not work in serious programming as
 slice creation happens in one place and its consuming
 in galaxy far far away and code of three developers
 happens in between. It is EXTREMELY difficult to debug.
 I know. It happened to me once in Harmonia and I wasted
 almost three days to catch it. Sigh...
 And I was designing it by myself - not even in team...

The COW rule for when to .dup is: When you're going to change the data, and you're not *sure* you're


 sole handle to it.

In real projects and in real life this *not sure* is almost always.

True, but it's also true that most of the time, one doesn't care because one has no need to modify the data.

Absolutely true. This is why e.g. string literals shall have type const char[] and not just a char[] by default. This is stupid design mistake in C++: "hello"[0] = 0; will compile and run on one machines and will not on others.

It is an error in C++ to do that, though it is allowed by some compilers for backwards compatibility. In C++, string literals are const char*.
 Walter, need of const appears together with raw pointers.
 It is critical to have pointers (slices included) together
 with const.

 If some language takes ++ from C but not pointers then
 it does not need const so much.

 There is no language in active use which has raw pointers
 and has no concept of pointers to const data.

I don't know of any language that even allows raw pointers other than C, C++ and D!

Delphi: function CopyStr(const aSourceString : string; aStart, aLength : Integer) : string;
 I agree with you that C++ has a culture of "const is good".

 I'd like to find something better, something that works (i.e. that 
 gives
 useful semantic information).

 I also am not understanding how const would help with COW mistakes.

What are the "COW mistakes"? I don't understand this exactly....

A COW mistake would be, for example, modifying a reference when you aren't sure you're the owner of it.

See, I even don't know about these errors as I am using void foo(const char[] s) { s[0] = 0; // here compiler rises an error - warnig me.... } Is it bad?
 Anyway....

 void  toLower(in char[] str)
 char[]  toLower(in const char[] str)


 Having them both is a matter of optimization.
 First does transformation in place, second allocates
 new string.

 Do these two together make sense? Definitely, yes.

See my comments on this example in another post here.

Jul 03 2005
prev sibling next sibling parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Walter" <newshound digitalmars.com> wrote in message 
news:da6k71$11rs$1 digitaldaemon.com...
 "Ben Hinkle" <bhinkle mathworks.com> wrote in message
 news:da4afr$24jc$1 digitaldaemon.com...
 How would this cover the following case that Walter's proposal covers:
 class A { int x; }
 void foo(in A obj){
   int y = obj.x;
   // do whatever you want...
   assert( obj.x == y );
 }
 void main() {
   A obj = new A;
   foo(obj); // says it doesn't change obj
 }
 Is it practical to force A to implement some immutability just because 
 foo
 doesn't change its inputs? I'm not saying Walter's proposal is prefect.

 very strong for foo to say no other thread or reference will change obj
 since it has no control over what other threads are doing. I would be

 pretty much blind leap of faith when declaring an object reference as 
 'in'
 and saying that no other thread is stepping on that object during the 
 call
 lifetime.

You're right. I have misgivings about it for that reason. On the other hand, look at C++ "const". Nothing about "const" says that some other thread or reference cannot change the value out from under you at any moment. Furthermore, it can be cast away and modified anyway. The semantic value of C++ "const" is essentially zip. This is why I am often flummoxed why it is given such weight in C++.

"This is why I am often flummoxed why it is given such weight in C++." Walter, consider 'const' as just any other access specifier: private, public, protected, etc. "const" has pretty much the same usability weight as these. const is not a physical protection. And never was. It is logical declaration of intention: I am not going to change this parameter or value it is refereing, so, compiler, please, warn me if I'll do this accidentally.
Jul 02 2005
next sibling parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
One more:

Java, C#, C, C++ and Pascal (Delphi)
has concept of const (parameters and references)
and these are the most popular languages so far.
Jul 02 2005
parent reply "Walter" <newshound digitalmars.com> writes:
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message
news:da7jil$dsm$1 digitaldaemon.com...
 One more:

 Java, C#, C, C++ and Pascal (Delphi)
 has concept of const (parameters and references)
 and these are the most popular languages so far.

Java only has top level const (final). Any data referred to by a final reference can be changed through that reference (or any other reference to the same object). About the only value it has other than simple constant folding (as pointed out by Matthew) is that any uninitialized finals must be initialized exactly once in the constructors. As far as preventing a function from modifying the fields of a 'final' reference parameter, it is useless.
Jul 02 2005
parent "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Walter" <newshound digitalmars.com> wrote in message 
news:da7t1t$jth$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:da7jil$dsm$1 digitaldaemon.com...
 One more:

 Java, C#, C, C++ and Pascal (Delphi)
 has concept of const (parameters and references)
 and these are the most popular languages so far.

Java only has top level const (final). Any data referred to by a final reference can be changed through that reference (or any other reference to the same object). About the only value it has other than simple constant folding (as pointed out by Matthew) is that any uninitialized finals must be initialized exactly once in the constructors. As far as preventing a function from modifying the fields of a 'final' reference parameter, it is useless.

Mea culpa. Was too optimistic about Java/C# . Working horses C, C++, Delphi still there though.
Jul 02 2005
prev sibling parent reply "Walter" <newshound digitalmars.com> writes:
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message
news:da7j26$dkb$1 digitaldaemon.com...
 const is not a physical protection. And never was.
 It is logical declaration of intention:

      I am not going to change this parameter or
      value it is refereing, so, compiler, please,
      warn me if I'll do this accidentally.

Yet the value can change anyway. Another reference can change it, and another thread can change it. It isn't "constant" at all, and cannot be relied on to be constant, even if your program is 100% "const-correct". The C++ const is *completely useless* to the compiler optimizer for that reason. A const thing that instead, is a guarantee that the underlying values won't change, is actually useful. An optimizer can do a lot with it.
Jul 02 2005
next sibling parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Walter" <newshound digitalmars.com> wrote in message 
news:da7pp5$i06$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:da7j26$dkb$1 digitaldaemon.com...
 const is not a physical protection. And never was.
 It is logical declaration of intention:

      I am not going to change this parameter or
      value it is refereing, so, compiler, please,
      warn me if I'll do this accidentally.

Yet the value can change anyway. Another reference can change it, and another thread can change it. It isn't "constant" at all, and cannot be relied on to be constant, even if your program is 100% "const-correct". The C++ const is *completely useless* to the compiler optimizer for that reason.

Right! Let's throw out private, protected, etc. As they are: (here goes citation of your statement above) Who the hell started this 'canard' (hoax, fr.) that const is for compiler optimization? const is a basic of DbC. It is a contrct. Not more not less. const references allows to mininimize needless memory allocations in design. This is true. And this is how 'const' helps optimization. Best optimizer is you and me - not a compiler. Table at bottom of http://www.terrainformatica.com/htmlayout/ It is not about const but const was a significant part of it.
 A const thing that instead, is a guarantee that the underlying values 
 won't
 change, is actually useful. An optimizer can do a lot with it.

ooohh... could you first provide me an option to *declare* e.g. slice as immutable thus I'll be able to return it from function without duping it? *That* would be optimization. Walter, again, what language are you going to substitute by D? What is the main target? C/C++? If yes then they have const references. If Java or C# then show how to implement String in D and very desireable with slices - they are extremely useful and are making D so attractive (among other good and useful features). Again, in my opinion 1) const references - const arrays and pointers 2) opAssign/dtors in structures are the *only* things left in D not-implemented from C++ feature set. If they will be there you and anyone can honestly say "D is next letter after C and C++" as it allows you to do *everything* that you can in C++ and it has much more "well done" features - true next step. Andrew.
Jul 02 2005
parent reply "Walter" <newshound digitalmars.com> writes:
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message
news:da7ulp$kub$1 digitaldaemon.com...
 ooohh... could you first provide me an option to *declare*
 e.g. slice as immutable thus I'll be able to return it from
 function without duping it? *That* would be optimization.

In following COW principles, you do not need to dup the slice when returning it. The producer of the value doesn't need to dup it, the *consumer* does, and only if the *consumer* modifies it. Taking a slice of an array does not modify it in any way, so no dup is required. So I am not understanding why const or immutable is needed for D strings. I've written a number of string processing programs in D (including a macro text processor, and the silly program that transforms newsgroup postings into the "archive" pages), and didn't have any difficulty with D strings. They went together with much less effort and far fewer bugs than their C++ counterparts.
 Walter, again, what language are you going to substitute
 by D? What is the main target? C/C++?
 If yes then they have const references.
 If Java or C# then show how to implement String in D
 and very desireable with slices - they are extremely useful
 and are making D so attractive (among other good and
 useful features).

 Again, in my opinion
 1) const references - const arrays and pointers
 2) opAssign/dtors in structures
 are the *only* things left in D not-implemented from
 C++ feature set. If they will be there you and anyone
 can honestly say "D is next letter after C and C++" as
 it allows you to do *everything* that you can in C++
 and it has much more "well done" features - true next step.

Unfortunately, there are several other "must haves" various people want D to have. I do understand the desire for const. But there are many different ways to approach the problem, and I'm not willing to just duplicate the C++ const with all its weaknesses and problems. There's got to be a better way.
Jul 03 2005
next sibling parent reply =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Walter wrote:

 So I am not understanding why const or immutable is needed for D strings.
 I've written a number of string processing programs in D (including a macro
 text processor, and the silly program that transforms newsgroup postings
 into the "archive" pages), and didn't have any difficulty with D strings.
 They went together with much less effort and far fewer bugs than their C++
 counterparts.

No offense, but didn't you design the language and string handling ? :-) I've written several segfaults by changing "readonly" literals, and gotten some strange results by setting hash string keys without duping them first (and then later changing the value of the string, that is...) I also think it's pretty easy to "mess up" when using any array slices. It would be great if there were some "extra mechanism" enforcing CoW.
 I do understand the desire for const. But there are many different ways to
 approach the problem, and I'm not willing to just duplicate the C++ const
 with all its weaknesses and problems. There's got to be a better way.

It would nice to come up with an approach that would: a) default local strings/arrays to read-write b) default external parameters to read-only "in"/"out" doesn't really work, since it only affects the array pointer/length and not the actually characters. Maybe something like "char[out] string", but that looks a little like a variable... Anyway, I wouldn't want to see "const" (or "readonly", "immutable") all over the place either - better to have a "readwrite" or "mutable" keyword for the (few?) cases when you *do* want to modify the contents ? I guess it's the D Gentlemen's Agreement, while keeping on searching. (it's easy enough* to implement java.lang.String and StringBuffer in D, but I'm still hoping there is some compromise between "C" and "Java") --anders * PS. Here's one such hack (mostly for the discussion really) http://www.algonet.se/~afb/d/dcaf/html/class_string.html http://www.algonet.se/~afb/d/dcaf/html/class_string_buffer.html
Jul 03 2005
next sibling parent reply Stefan Zobel <Stefan_member pathlink.com> writes:
In article <da8but$t3j$1 digitaldaemon.com>,
=?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= says...
I guess it's the D Gentlemen's Agreement, while keeping on searching.
(it's easy enough* to implement java.lang.String and StringBuffer in D,
but I'm still hoping there is some compromise between "C" and "Java")

--anders

* PS. Here's one such hack (mostly for the discussion really)
http://www.algonet.se/~afb/d/dcaf/html/class_string.html
http://www.algonet.se/~afb/d/dcaf/html/class_string_buffer.html

For what it's worth, that String isn't immutable in Java/C# sense, is it? Every time you hand out a char[], you give the caller a reference to your internal member. Should be a "return str.dup;" :-( Best regards, Stefan
Jul 03 2005
parent reply =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Stefan Zobel wrote:

 For what it's worth, that String isn't immutable in Java/C# sense, is it?
 Every time you hand out a char[], you give the caller a reference to 
 your internal member. Should be a "return str.dup;" :-(

This goes for most implementations of toString(), I guess ? This actually would be the key issue we are debating here... The char[] that is given out *is* read-only, there's just no way of indicating that - except for the Gentlemen's Agreement. And, no, it should NOT be a dup (as my "StringBuffer" did do that). It's _supposed_ to return a reference to the (immutable) contents. And you could still peek and poke it by casting to char* and changing the memory inside, but that's besides the point here. I don't think that D needs a string class, but "something else" ? (as in Java and C#, the class internals are protected by the VM) I like the current strings, it's just that they are (or: could be) a little dangerous - just like a raw char* in C could be, I guess. But for C/C++ there is "const" - D needs something similar, but better. --anders
Jul 03 2005
next sibling parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Anders F Björklund" <afb algonet.se> wrote in message 
news:da8ivk$12cm$1 digitaldaemon.com...
 Stefan Zobel wrote:

 For what it's worth, that String isn't immutable in Java/C# sense, is it?
 Every time you hand out a char[], you give the caller a reference to your 
 internal member. Should be a "return str.dup;" :-(

This goes for most implementations of toString(), I guess ? This actually would be the key issue we are debating here... The char[] that is given out *is* read-only, there's just no way of indicating that - except for the Gentlemen's Agreement.

Exactly! You can theoretically reproduce String (immutable string value) which will be *completely useles and inneffective*. What is the point to have String which you cannot use e.g. here: FILE * fopen([const] char* path, [const] char* flags); ?
 And, no, it should NOT be a dup (as my "StringBuffer" did do that).
 It's _supposed_ to return a reference to the (immutable) contents.

 And you could still peek and poke it by casting to char* and
 changing the memory inside, but that's besides the point here.


 I don't think that D needs a string class, but "something else" ?
 (as in Java and C#, the class internals are protected by the VM)

 I like the current strings, it's just that they are (or: could be)
 a little dangerous - just like a raw char* in C could be, I guess.

Agreed, String as a class is not needed in D. But String as an entity consist of two things: string value : const char[], char#[], whatever you like, and string manipulation buffer (array): char[]. And this *duo* is the must for success.
 But for C/C++ there is "const" - D needs something similar, but better.

D already has better part - in, inout, out. These combined with const *is* better from notational point of view than in current C/C++.
Jul 03 2005
parent =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Andrew Fedoniouk wrote:

But for C/C++ there is "const" - D needs something similar, but better.

D already has better part - in, inout, out. These combined with const *is* better from notational point of view than in current C/C++.

The only problem being that in/out just affects the pointer/array ref, where it works fine already, but not the actual contents of the array... In some ways, that is similar to how passing an object reference to a function allows it to change internal state of the object passed. But the difference is of course that the object is changed through methods while the array passed could be modified "behind your back". So we still need some "mutable" attribute to give to strings/arrays, and something like "char[out] string" might work - but is rather ugly ? Must confess that I find the proposed char#[] syntax to be obscure too, and would rather have both "mutable char[]" (as well as "static if"...) Assuming here that C++-style "const" is the default for a parameter, and that it would be more useful to have a keyword for the opposite. But I think that it's a _very_ good chance that this ends up like the booleans, with some syntax approaching the real thing but not enforced. How it is *supposed* to work is pretty clear from the Copy-on-Write ? It's just that there is not too much "checking" from the D compiler... For me it's not really a show-stopper, just a(nother) small annoyance. The string handling in D still rocks when compared to what old C had. --anders
Jul 03 2005
prev sibling parent reply Stefan Zobel <Stefan_member pathlink.com> writes:
In article <da8ivk$12cm$1 digitaldaemon.com>,
=?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= says...
Stefan Zobel wrote:

 For what it's worth, that String isn't immutable in Java/C# sense, is it?
 Every time you hand out a char[], you give the caller a reference to 
 your internal member. Should be a "return str.dup;" :-(

This goes for most implementations of toString(), I guess ? This actually would be the key issue we are debating here...

Yep, exactly.
The char[] that is given out *is* read-only, there's just no
way of indicating that - except for the Gentlemen's Agreement.

I understand the "philosophical" point here. I was just pointing out that, technically (current D), it is not.
And, no, it should NOT be a dup (as my "StringBuffer" did do that).
It's _supposed_ to return a reference to the (immutable) contents.

Hhm, "_supposed_". Not sure, if I can follow you here, but that may be because english is not my mother tongue (also didn't take a look at StringBuffer). The fact remains, that (to be really immutable) it must be a dup in D as it is right now.
And you could still peek and poke it by casting to char* and
changing the memory inside, but that's besides the point here.

void main () { String mutableString = new String("immutable!"); writefln(mutableString); char[] ref = mutableString.toString(); ref[9] = '?'; writefln(mutableString); } No "peeking and poking" here, just a realistic use case. But I'm convinced you know that. So, presumably I simply didn't get your point?
I don't think that D needs a string class, but "something else" ?
(as in Java and C#, the class internals are protected by the VM)

I like the current strings, it's just that they are (or: could be)
a little dangerous - just like a raw char* in C could be, I guess.


But for C/C++ there is "const" - D needs something similar, but better.

--anders

Agreed, we wouldn't need a string class (could save on all that duping) if we had a way to declare const/immutable/... references in D. Just wanted to remark that String.d isn't immutable, nothing more. No offense intended :) Kind regards, Stefan
Jul 03 2005
parent reply =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Stefan Zobel wrote:

And you could still peek and poke it by casting to char* and
changing the memory inside, but that's besides the point here.

void main () { String mutableString = new String("immutable!"); writefln(mutableString); char[] ref = mutableString.toString(); ref[9] = '?'; writefln(mutableString); } No "peeking and poking" here, just a realistic use case. But I'm convinced you know that. So, presumably I simply didn't get your point?

I simply meant that even when you *do* have "const char[]" (or similar), you can still (implicitly?) cast it to a pointer in D and change away... Then again, introducing such a new thing would probably be accompanied by "const char*" too, which any "const char[]" would return for .ptr ?
 Agreed, we wouldn't need a string class (could save on all that duping)
 if we had a way to declare const/immutable/... references in D. Just wanted
 to remark that String.d isn't immutable, nothing more. No offense intended :)

As pointed out by others, could take toString out - making it useless. And this is not only "toString", but also toCodePoints and opSlice - and probably most other similar member functions returing arrays... ? They are all read-only and "protected" by the Copy-on-Write convention. --anders
Jul 03 2005
parent Stefan Zobel <Stefan_member pathlink.com> writes:
In article <daali1$5mn$1 digitaldaemon.com>,
=?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= says...
Stefan Zobel wrote:

And you could still peek and poke it by casting to char* and
changing the memory inside, but that's besides the point here.

void main () { String mutableString = new String("immutable!"); writefln(mutableString); char[] ref = mutableString.toString(); ref[9] = '?'; writefln(mutableString); } No "peeking and poking" here, just a realistic use case. But I'm convinced you know that. So, presumably I simply didn't get your point?

I simply meant that even when you *do* have "const char[]" (or similar), you can still (implicitly?) cast it to a pointer in D and change away... Then again, introducing such a new thing would probably be accompanied by "const char*" too, which any "const char[]" would return for .ptr ?
 Agreed, we wouldn't need a string class (could save on all that duping)
 if we had a way to declare const/immutable/... references in D. Just wanted
 to remark that String.d isn't immutable, nothing more. No offense intended :)

As pointed out by others, could take toString out - making it useless. And this is not only "toString", but also toCodePoints and opSlice - and probably most other similar member functions returing arrays... ? They are all read-only and "protected" by the Copy-on-Write convention. --anders

Ok, point taken. It's a COW string intended to be used as such. Thanks for the clarification. Best regards, Stefan
Jul 04 2005
prev sibling parent "Walter" <newshound digitalmars.com> writes:
"Anders F Björklund" <afb algonet.se> wrote in message
news:da8but$t3j$1 digitaldaemon.com...
 Walter wrote:

 So I am not understanding why const or immutable is needed for D


 I've written a number of string processing programs in D (including a


 text processor, and the silly program that transforms newsgroup postings
 into the "archive" pages), and didn't have any difficulty with D


 They went together with much less effort and far fewer bugs than their


 counterparts.

No offense, but didn't you design the language and string handling ? :-)

Yup (with some help from others like Jan Knepper and Arcane Jill), but it did go through a few iterations.
 I've written several segfaults by changing "readonly" literals, and
 gotten some strange results by setting hash string keys without duping
 them first (and then later changing the value of the string, that is...)
 I also think it's pretty easy to "mess up" when using any array slices.

There is a mindset to COW that takes some getting used to.
 It would be great if there were some "extra mechanism" enforcing CoW.

I agree, but I am not convinced that "const" is it.
 I do understand the desire for const. But there are many different ways


 approach the problem, and I'm not willing to just duplicate the C++


 with all its weaknesses and problems. There's got to be a better way.

It would nice to come up with an approach that would: a) default local strings/arrays to read-write b) default external parameters to read-only "in"/"out" doesn't really work, since it only affects the array pointer/length and not the actually characters. Maybe something like "char[out] string", but that looks a little like a variable... Anyway, I wouldn't want to see "const" (or "readonly", "immutable") all over the place either - better to have a "readwrite" or "mutable" keyword for the (few?) cases when you *do* want to modify the contents ?

Yes.
 I guess it's the D Gentlemen's Agreement, while keeping on searching.
 (it's easy enough* to implement java.lang.String and StringBuffer in D,
 but I'm still hoping there is some compromise between "C" and "Java")

 --anders

 * PS. Here's one such hack (mostly for the discussion really)
 http://www.algonet.se/~afb/d/dcaf/html/class_string.html
 http://www.algonet.se/~afb/d/dcaf/html/class_string_buffer.html

Jul 03 2005
prev sibling parent Sean Kelly <sean f4.ca> writes:
In article <da89e7$s7m$1 digitaldaemon.com>, Walter says...
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message
news:da7ulp$kub$1 digitaldaemon.com...
 ooohh... could you first provide me an option to *declare*
 e.g. slice as immutable thus I'll be able to return it from
 function without duping it? *That* would be optimization.

In following COW principles, you do not need to dup the slice when returning it. The producer of the value doesn't need to dup it, the *consumer* does, and only if the *consumer* modifies it. Taking a slice of an array does not modify it in any way, so no dup is required. So I am not understanding why const or immutable is needed for D strings. I've written a number of string processing programs in D (including a macro text processor, and the silly program that transforms newsgroup postings into the "archive" pages), and didn't have any difficulty with D strings. They went together with much less effort and far fewer bugs than their C++ counterparts.

To me, C++ 'const' just a means of indicating, in code, that a value is not intended to be modifiable. So if I have a string property in a class, I can return a const reference my internal copy and be somewhat assurred that the client will have to make a conscious attempt if he wants to modify the data. This is really only useful for strings IMO in D, as they can be expensive to copy and there's no way to restrict their functionality. But I'm not sure it's worth adding a language feature just to help idiot-proof string use.
I do understand the desire for const. But there are many different ways to
approach the problem, and I'm not willing to just duplicate the C++ const
with all its weaknesses and problems. There's got to be a better way.

I agree. Hopefully, something will present itself. Sean
Jul 03 2005
prev sibling next sibling parent reply AJG <AJG_member pathlink.com> writes:
Hi Walter,

 const is not a physical protection. And never was.
 It is logical declaration of intention:

      I am not going to change this parameter or
      value it is refereing, so, compiler, please,
      warn me if I'll do this accidentally.

Yet the value can change anyway. Another reference can change it, and another thread can change it. It isn't "constant" at all, and cannot be relied on to be constant, even if your program is 100% "const-correct". The C++ const is *completely useless* to the compiler optimizer for that reason.

I can't fathom that the compiler can't make use of the fact that you are telling it: "The following function body will not modify [variable] at all, ever."? Surely this is useful information that can be made into some kind of optimization, specially when ignoring the dangers of threading: I simply don't see why threads even have to come into the picture. You could take a soldering iron and hack memory directly and the runtime won't be able to protect against that. But does it matter? I don't think that's the point of const. It is not a guarantee by the _compiler_ that the value will remain constant. It is a guarantee by the _programmer_ that his function body will not touch the variable. Of course, the compiler (or lexer), should make sure to prevent the programmer from violating his contract via syntax.
A const thing that instead, is a guarantee that the underlying values won't
change, is actually useful. An optimizer can do a lot with it.

But wouldn't such a thing (a runtime-enforced const) cause big performance problems? It would mean the runtime would have to deal with race conditions and thread synchronization for every single const variable and object in memory. That seems awfully slow to me; a gratuitous use of locks and mutexes. If so, this makes for an interesting catch-22. If you implement it, you can optimize, but you get the performance penalty. If you don't implement it, there's no performance penalty, but you can't optimize either. I say forget about the runtime-const. Stick with semantic (compile-time) const, and try to make use of that info to optimize. Forget about threading too, which should make it easier. If the programmer wants to make sure some variable won't change via some other thread, then he should: [a] simply not use it in that thread; or [b] make the function that uses it on that thread take a const; or [c] lock and synchronize it himself individually. As far as references go, you should not (syntactically) be able to make a non-const reference to a const. That should guarantee correctness within the function body. Examples: # void func(const type[] c_param) { # assert(c_param.length); # # const type[] c_array = c_param; // OK. # const type c_item = c_param[0]; // OK. # type[] n_array = c_param; // FAILS. # type n_item = c_param[0]; // FAILS. # # // And so forth: # const type[] a = c_array; // OK. # const type b = c_array[0]; // OK. # const type c = c_item; // OK. # type[] d = c_array; // FAILS. # type e = c_array[0]; // FAILS. # type f = c_item; // FAILS. # # // Same thing for slicing. # const type[] g = c_param[0 .. $]; // OK. # const type[] h = c_array[0 .. $]; // OK. # type[] i = c_param[0 .. $]; // FAILS. # type[] j = c_array[0 .. $]; // FAILS. # } Pretty simple, if you ask me. You could make "in" = "const" (syntactically) in that sense, which should have always been the default. Or you could do: - No modifier: e.g. func(int a) : This means make a (mutable, independent) copy of the caller's variable. Use dup for arrays, etc. - IN modifier: e.g. func(in int a) : This means const as defined above. Cheers, --AJG.
Jul 02 2005
next sibling parent "Andrew Fedoniouk" <news terrainformatica.com> writes:
"AJG" <AJG_member pathlink.com> wrote in message 
news:da7vvd$lm6$1 digitaldaemon.com...
 Hi Walter,

 const is not a physical protection. And never was.
 It is logical declaration of intention:

      I am not going to change this parameter or
      value it is refereing, so, compiler, please,
      warn me if I'll do this accidentally.

Yet the value can change anyway. Another reference can change it, and another thread can change it. It isn't "constant" at all, and cannot be relied on to be constant, even if your program is 100% "const-correct". The C++ const is *completely useless* to the compiler optimizer for that reason.

I can't fathom that the compiler can't make use of the fact that you are telling it: "The following function body will not modify [variable] at all, ever."? Surely this is useful information that can be made into some kind of optimization, specially when ignoring the dangers of threading: I simply don't see why threads even have to come into the picture. You could take a soldering iron and hack memory directly and the runtime won't be able to protect against that. But does it matter? I don't think that's the point of const. It is not a guarantee by the _compiler_ that the value will remain constant. It is a guarantee by the _programmer_ that his function body will not touch the variable. Of course, the compiler (or lexer), should make sure to prevent the programmer from violating his contract via syntax.
A const thing that instead, is a guarantee that the underlying values 
won't
change, is actually useful. An optimizer can do a lot with it.

But wouldn't such a thing (a runtime-enforced const) cause big performance problems? It would mean the runtime would have to deal with race conditions and thread synchronization for every single const variable and object in memory. That seems awfully slow to me; a gratuitous use of locks and mutexes. If so, this makes for an interesting catch-22. If you implement it, you can optimize, but you get the performance penalty. If you don't implement it, there's no performance penalty, but you can't optimize either. I say forget about the runtime-const. Stick with semantic (compile-time) const, and try to make use of that info to optimize. Forget about threading too, which should make it easier. If the programmer wants to make sure some variable won't change via some other thread, then he should: [a] simply not use it in that thread; or [b] make the function that uses it on that thread take a const; or [c] lock and synchronize it himself individually. As far as references go, you should not (syntactically) be able to make a non-const reference to a const. That should guarantee correctness within the function body. Examples: # void func(const type[] c_param) { # assert(c_param.length); # # const type[] c_array = c_param; // OK. # const type c_item = c_param[0]; // OK. # type[] n_array = c_param; // FAILS. # type n_item = c_param[0]; // FAILS. # # // And so forth: # const type[] a = c_array; // OK. # const type b = c_array[0]; // OK. # const type c = c_item; // OK. # type[] d = c_array; // FAILS. # type e = c_array[0]; // FAILS. # type f = c_item; // FAILS. # # // Same thing for slicing. # const type[] g = c_param[0 .. $]; // OK. # const type[] h = c_array[0 .. $]; // OK. # type[] i = c_param[0 .. $]; // FAILS. # type[] j = c_array[0 .. $]; // FAILS. # } Pretty simple, if you ask me. You could make "in" = "const" (syntactically) in that sense, which should have always been the default. Or you could do: - No modifier: e.g. func(int a) : This means make a (mutable, independent) copy of the caller's variable. Use dup for arrays, etc. - IN modifier: e.g. func(in int a) : This means const as defined above.

Thanks, AJG, excellent statement. Except final :) in, inout and out in function parameters defines direction. This quite different from const and let's don't mix it. See, declaration: void toLower(in char[] str) means that toLower function will not change length of the str but allowed to change its content. Reasonable? Yes. Next step, this declaration: char[] toLower(in const char[] str) means that: 1) this toLower will not change str. nor length nor its content. 2) It returns mutable array and caller is free to use it in the way it wants - it may own it, store it, whatever. These two functions will peacefuly coexist in phobos as they have different signatures. Developer can do *optimal* choice. Signature: const char[] getDir(in const char[] path) means: getDir will not do anything with path - will just return const slice. Signature: void splitPath(in const char[] path, out const char[] dir, out const char[] filename, out const char[] ext) Means it will not touch path and will return constant slices representing path parts. Signature: void splitPath(in const char[] path, out char[] dir, out char[] filename, out char[] ext) Means it will not touch path and will return arrays - copies of path parts - caller is free to own them. Anyone brave here to tell me (us with AJG :) that all this above have nothing common with optimization?
Jul 03 2005
prev sibling parent reply "Walter" <newshound digitalmars.com> writes:
"AJG" <AJG_member pathlink.com> wrote in message
news:da7vvd$lm6$1 digitaldaemon.com...
Yet the value can change anyway. Another reference can change it, and
another thread can change it. It isn't "constant" at all, and cannot be
relied on to be constant, even if your program is 100% "const-correct".


C++ const is *completely useless* to the compiler optimizer for that


 I can't fathom that the compiler can't make use of the fact that you are

 it: "The following function body will not modify [variable] at all,

Consider the following C++ function: int foo(const int *p, int *q) { int i = *p; *q = 3; return *p; } At the return statement, could we replace *p with i, thereby saving ourselves a dereference operation? After all, p points to "const" data, right? Wrong. Consider calling foo() this way: int a[3]; ... foo(a, a); Since p and q now hold the same value, *q = 3; will change the contents of what p points to. This code is perfectly legal C++, and is "const-correct". It happens often enough in real code, too, as I discovered when trying to implement this optimization.
Jul 03 2005
next sibling parent reply AJG <AJG_member pathlink.com> writes:
In article <da88rb$ruj$1 digitaldaemon.com>, Walter says...
"AJG" <AJG_member pathlink.com> wrote in message
news:da7vvd$lm6$1 digitaldaemon.com...
Yet the value can change anyway. Another reference can change it, and
another thread can change it. It isn't "constant" at all, and cannot be
relied on to be constant, even if your program is 100% "const-correct".


C++ const is *completely useless* to the compiler optimizer for that


 I can't fathom that the compiler can't make use of the fact that you are

 it: "The following function body will not modify [variable] at all,

Consider the following C++ function: int foo(const int *p, int *q) { int i = *p; *q = 3; return *p; }

    int a[3];
    ...
    foo(a, a);

Hm... that's an interesting situation. Ok, say pointers are not considered, because they are inherently unsafe anyway. Let's take only regular in/out/inout variables. Could the same trick be done simply with these?
This code is perfectly legal C++, and is "const-correct". It happens often
enough in real code, too, as I discovered when trying to implement this
optimization.

It's possible that such code, although legal, is simply bad code that can't be protected against. The function documentation should state which variables shouldn't be the same. I think it's simply undefined behaviour. I dunno if all optimization should be off simply because of the occasinal badly coded, documented and used function. It's kind of like modifying the iterating array inside a foreach - perfectly valid too, but that's going to be ugly (perhaps that should be made illegal too, btw). Or for example, sending the same variable to multiple parameters of a string-manipulation (str*) function. Consider this: // char *str = "Some text"; // str = strcat(str, str); --------------------------- Once again, what if pointers are not considered, would this make things easier? If you take out pointers, couldn't the compiler detect if you were sending the same variable to multiple differently-accessable parameters? Cheers, --AJG.
Jul 03 2005
parent reply "Walter" <newshound digitalmars.com> writes:
"AJG" <AJG_member pathlink.com> wrote in message
news:da8vgt$1bos$1 digitaldaemon.com...
 In article <da88rb$ruj$1 digitaldaemon.com>, Walter says...
"AJG" <AJG_member pathlink.com> wrote in message
news:da7vvd$lm6$1 digitaldaemon.com...
Yet the value can change anyway. Another reference can change it, and
another thread can change it. It isn't "constant" at all, and cannot




relied on to be constant, even if your program is 100%




The
C++ const is *completely useless* to the compiler optimizer for that


 I can't fathom that the compiler can't make use of the fact that you



telling
 it: "The following function body will not modify [variable] at all,

Consider the following C++ function: int foo(const int *p, int *q) { int i = *p; *q = 3; return *p; }

    int a[3];
    ...
    foo(a, a);

Hm... that's an interesting situation. Ok, say pointers are not

 because they are inherently unsafe anyway. Let's take only regular

 variables. Could the same trick be done simply with these?

With simple value variables, no. But that isn't interesting, as there isn't much of any point to "const" value variables as function parameters. With reference parameters, yes, it can happen in the same way.
This code is perfectly legal C++, and is "const-correct". It happens


enough in real code, too, as I discovered when trying to implement this
optimization.

It's possible that such code, although legal, is simply bad code that

 protected against. The function documentation should state which variables
 shouldn't be the same. I think it's simply undefined behaviour.

 I dunno if all optimization should be off simply because of the occasinal

 coded, documented and used function.

 It's kind of like modifying the iterating array inside a foreach -

 valid too, but that's going to be ugly (perhaps that should be made

 btw). Or for example, sending the same variable to multiple parameters of

 string-manipulation (str*) function. Consider this:

 // char *str = "Some text";
 // str = strcat(str, str);

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

 Once again, what if pointers are not considered, would this make things

 If you take out pointers, couldn't the compiler detect if you were sending

 same variable to multiple differently-accessable parameters?

The compiler cannot detect it in the general case, as a function may receive a non-const reference to the same data by an arbitrarilly complex path. What you're suggesting is different from C++ "const" - you're suggesting that const actually mean "constant". This is definitely more interesting that C++ const, but then there's the problem of undefined behavior and trying to detect it.
Jul 03 2005
parent reply AJG <AJG_member pathlink.com> writes:
Hi Walter,

 Once again, what if pointers are not considered, would this make things

 If you take out pointers, couldn't the compiler detect if you were sending

 same variable to multiple differently-accessable parameters?

The compiler cannot detect it in the general case, as a function may receive a non-const reference to the same data by an arbitrarilly complex path.

I know I'm pushing it here, but can't the compiler follow that arbitrarily complex path (excluding pointers)?
What you're suggesting is different from C++ "const" - you're suggesting
that const actually mean "constant". This is definitely more interesting
that C++ const, but then there's the problem of undefined behavior and
trying to detect it.

Hm... perhaps. Ok, first let me see if I understand your point: You say: C++ const, which is semantic only, is useless for optimizations. You say: Implementing C++ const in D would be equally useless re: optimizations. I say: const should be _always_ about semantics ("correctness"), and _if possible_ provide optimizations. You say: That is not good enough, we need correctness and optimization. Is that correct? So, if you can solve the arbitrarily complex path problem, you get the both of both worlds, right? I dunno if this is possible, just thinking out loud. If not syntactically, could it be done via whole-program static analysis? Thanks, --AJG.
Jul 03 2005
parent "Walter" <newshound digitalmars.com> writes:
"AJG" <AJG_member pathlink.com> wrote in message
news:da9ig8$1vpg$1 digitaldaemon.com...
 Once again, what if pointers are not considered, would this make things

 If you take out pointers, couldn't the compiler detect if you were



the
 same variable to multiple differently-accessable parameters?

The compiler cannot detect it in the general case, as a function may


a non-const reference to the same data by an arbitrarilly complex path.

I know I'm pushing it here, but can't the compiler follow that arbitrarily complex path (excluding pointers)?

If it could, the program could be executed at compile time rather than run time <g>.
What you're suggesting is different from C++ "const" - you're suggesting
that const actually mean "constant". This is definitely more interesting
that C++ const, but then there's the problem of undefined behavior and
trying to detect it.

Hm... perhaps. Ok, first let me see if I understand your point: You say: C++ const, which is semantic only, is useless for optimizations. You say: Implementing C++ const in D would be equally useless re:

 I say:   const should be _always_ about semantics ("correctness"), and _if
 possible_ provide optimizations.
 You say: That is not good enough, we need correctness and optimization.

 Is that correct?

From correctness comes the optimizations. C++ doesn't implement correctness, as my example showed.
 If not syntactically, could it be done via whole-program static analysis?

No.
Jul 03 2005
prev sibling next sibling parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Walter" <newshound digitalmars.com> wrote in message 
news:da88rb$ruj$1 digitaldaemon.com...
 "AJG" <AJG_member pathlink.com> wrote in message
 news:da7vvd$lm6$1 digitaldaemon.com...
Yet the value can change anyway. Another reference can change it, and
another thread can change it. It isn't "constant" at all, and cannot be
relied on to be constant, even if your program is 100% "const-correct".


C++ const is *completely useless* to the compiler optimizer for that


 I can't fathom that the compiler can't make use of the fact that you are

 it: "The following function body will not modify [variable] at all,

Consider the following C++ function: int foo(const int *p, int *q) { int i = *p; *q = 3; return *p; } At the return statement, could we replace *p with i, thereby saving ourselves a dereference operation? After all, p points to "const" data, right? Wrong. Consider calling foo() this way: int a[3]; ... foo(a, a); Since p and q now hold the same value, *q = 3; will change the contents of what p points to. This code is perfectly legal C++, and is "const-correct". It happens often enough in real code, too, as I discovered when trying to implement this optimization.

Walter, it is enough for me to know that int foo(const int *p, int *q) { int i = *p; *q = 3; .... 200 lines of code return *p; } will not change *p. I am not asking for optimization here. Optimization happened before - when I wrote this fucntion declaration using const parameters. I understand that you focused on optimiziation as compiler and codegenerator writer. This is perfectly good and thank you for that. But const is a matter of language design and not about optimization. Well not exactly as if I will write both: int foo(const int *p, int *q) int foo(int *p, int *q) then I will make an act of optimization on the design level. Again: from the point of optimization 'public', 'private' attributes are almost worthless. But despite of that they are in the language. const is the same - it is a contract. Any argument that you can *intentionally* break constness are true. The same apply to visibility attributes. Andrew.
Jul 03 2005
next sibling parent reply "Dave" <Dave_member pathlink.com> writes:
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message 
news:da93ap$1g54$1 digitaldaemon.com...
 "Walter" <newshound digitalmars.com> wrote in message 
 news:da88rb$ruj$1 digitaldaemon.com...
 "AJG" <AJG_member pathlink.com> wrote in message
 news:da7vvd$lm6$1 digitaldaemon.com...
Yet the value can change anyway. Another reference can change it, and
another thread can change it. It isn't "constant" at all, and cannot be
relied on to be constant, even if your program is 100% "const-correct".


C++ const is *completely useless* to the compiler optimizer for that


 I can't fathom that the compiler can't make use of the fact that you are

 it: "The following function body will not modify [variable] at all,

Consider the following C++ function: int foo(const int *p, int *q) { int i = *p; *q = 3; return *p; } At the return statement, could we replace *p with i, thereby saving ourselves a dereference operation? After all, p points to "const" data, right? Wrong. Consider calling foo() this way: int a[3]; ... foo(a, a); Since p and q now hold the same value, *q = 3; will change the contents of what p points to. This code is perfectly legal C++, and is "const-correct". It happens often enough in real code, too, as I discovered when trying to implement this optimization.

Walter, it is enough for me to know that int foo(const int *p, int *q) { int i = *p; *q = 3; .... 200 lines of code return *p; } will not change *p. I am not asking for optimization here. Optimization happened before - when I wrote this fucntion declaration using const parameters.

The whole problem is, with the C++ rules, the optimizations cannot even be done by the code generator - you may think you've optimized something with const, but in reality the code generator cannot make use of it because of how const is implimented in C++ and the compiler cannot figure out 100% for certain what is being done with referenced data.
 I understand that you focused on optimiziation as compiler and 
 codegenerator
 writer. This is perfectly good and thank you for that.

What I think Walter has in mind with his "explicit in" proposal for D is "constness" while still allowing for the optimizations that C++ can't do, or at least can't do without making the compiler much more complicated.
 But const is a matter of language design and not about optimization.
 Well not exactly as if I will write both:

 int foo(const int *p, int *q)
 int foo(int *p, int *q)

 then I will make an act of optimization on the design level.

 Again: from the point of optimization 'public', 'private' attributes are 
 almost worthless.

'private' and 'package' data members may have some optimizations applied because of the protection attribute scope rules. private and package methods can't be virtual, so there are some optimizations having to do with inlining and the vtable that can be (and are) done by the compiler, because 'private' or 'package' guarantees that those are not virtual methods.
 But despite of that they are in the language. const is the same - it is a 
 contract.
 Any argument that you can *intentionally* break constness are true.
 The same apply to visibility attributes.

 Andrew.

 

Jul 03 2005
parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Dave" <Dave_member pathlink.com> wrote in message 
news:da95on$1jff$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message 
 news:da93ap$1g54$1 digitaldaemon.com...
 "Walter" <newshound digitalmars.com> wrote in message 
 news:da88rb$ruj$1 digitaldaemon.com...
 "AJG" <AJG_member pathlink.com> wrote in message
 news:da7vvd$lm6$1 digitaldaemon.com...
Yet the value can change anyway. Another reference can change it, and
another thread can change it. It isn't "constant" at all, and cannot 
be
relied on to be constant, even if your program is 100% 
"const-correct".


C++ const is *completely useless* to the compiler optimizer for that


 I can't fathom that the compiler can't make use of the fact that you 
 are

 it: "The following function body will not modify [variable] at all,

Consider the following C++ function: int foo(const int *p, int *q) { int i = *p; *q = 3; return *p; } At the return statement, could we replace *p with i, thereby saving ourselves a dereference operation? After all, p points to "const" data, right? Wrong. Consider calling foo() this way: int a[3]; ... foo(a, a); Since p and q now hold the same value, *q = 3; will change the contents of what p points to. This code is perfectly legal C++, and is "const-correct". It happens often enough in real code, too, as I discovered when trying to implement this optimization.

Walter, it is enough for me to know that int foo(const int *p, int *q) { int i = *p; *q = 3; .... 200 lines of code return *p; } will not change *p. I am not asking for optimization here. Optimization happened before - when I wrote this fucntion declaration using const parameters.

The whole problem is, with the C++ rules, the optimizations cannot even be done by the code generator - you may think you've optimized something with const, but in reality the code generator cannot make use of it because of how const is implimented in C++ and the compiler cannot figure out 100% for certain what is being done with referenced data.

Again I am willing to write to functions which provided together will give an optimal choice: void toUpper( in char[] strbuf ) // inplace char[] toUpper( in const char[] str ) // return brand new. I am free to chose optimal function for particular case. And while implementing it compiler will not allow me to change *accidentally* value of str. This is *deterministic* optimization. codegenerator *may* do optimization. And may not. const is not about codegenerator optimiziation. Dot. Forget about it.
 I understand that you focused on optimiziation as compiler and 
 codegenerator
 writer. This is perfectly good and thank you for that.

What I think Walter has in mind with his "explicit in" proposal for D is "constness" while still allowing for the optimizations that C++ can't do, or at least can't do without making the compiler much more complicated.
 But const is a matter of language design and not about optimization.
 Well not exactly as if I will write both:

 int foo(const int *p, int *q)
 int foo(int *p, int *q)

 then I will make an act of optimization on the design level.

 Again: from the point of optimization 'public', 'private' attributes are 
 almost worthless.

'private' and 'package' data members may have some optimizations applied because of the protection attribute scope rules. private and package methods can't be virtual, so there are some optimizations having to do with inlining and the vtable that can be (and are) done by the compiler, because 'private' or 'package' guarantees that those are not virtual methods.

I think that you a wrong here as following: import std.stdio; class One { package int foo() { return 1; } } class Two: One { override package int foo() { return 2; } } int main() { Two t = new Two; return t.foo(); } compiles just fine.
 But despite of that they are in the language. const is the same - it is a 
 contract.
 Any argument that you can *intentionally* break constness are true.
 The same apply to visibility attributes.

 Andrew.


Jul 03 2005
parent reply "Dave" <Dave_member pathlink.com> writes:
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message 
news:da9g47$1tfc$1 digitaldaemon.com...
 "Dave" <Dave_member pathlink.com> wrote in message 
 news:da95on$1jff$1 digitaldaemon.com...
 The whole problem is, with the C++ rules, the optimizations cannot even 
 be done by the code generator - you may think you've optimized something 
 with const, but in reality the code generator cannot make use of it 
 because of how const is implimented in C++ and the compiler cannot figure 
 out 100% for certain what is being done with referenced data.

Again I am willing to write to functions which provided together will give an optimal choice: void toUpper( in char[] strbuf ) // inplace char[] toUpper( in const char[] str ) // return brand new.

I understand - I think we're all looking for some way to implement "constness" in a way that is better, for at least the majority of cases, than how C++ does it. From Walter's earlier post, it appears that overloading based on some type of "const" storage modifier is not going to happen, so I'll take what I can get in this regard, especially if it helps compiler implementors do their job better because then I get better tools. Walter wants D's "constness" to be taken as a semantic guarantee of some value, and I agree with him on that, because then it's of more value to both the compiler and someone debugging code (const the way it is in C++ can actually hide bugs). I also agree with the notion that C++ constness is a mess and that is one of the major reasons why I want D to succeed, so I don't have to deal with that as it is. I take it you basically want C++ constness in D - I just have to disagree with that because that's one of the things I think needs to be done better.
 I am free to chose optimal function for particular case.
 And while implementing it compiler will not allow
 me to change *accidentally* value of str.

 private and package methods can't be virtual, so there are some 
 optimizations having to do with inlining and the vtable that can be (and 
 are) done by the compiler, because 'private' or 'package' guarantees that 
 those are not virtual methods.

I think that you a wrong here as following: import std.stdio; class One { package int foo() { return 1; } } class Two: One { override package int foo() { return 2; } } int main() { Two t = new Two; return t.foo(); } compiles just fine.

Try this: # dmd -version=_package pt.d # ./pt 1 1 vs. this: # dmd pt.d # ./pt 2 1 ;--- import std.stdio; class One { version(_package) package int foo() { return 1; } else public int foo() { return 1; } } class Two: One { version(_package) override package int foo() { return 2; } else override public int foo() { return 2; } } void main() { Two t = new Two; writefln((cast(One)t).foo()); One o = new One; writefln("%d\n",(cast(One)o).foo()); }
Jul 03 2005
parent "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Dave" <Dave_member pathlink.com> wrote in message 
news:da9jup$21h4$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message 
 news:da9g47$1tfc$1 digitaldaemon.com...
 "Dave" <Dave_member pathlink.com> wrote in message 
 news:da95on$1jff$1 digitaldaemon.com...
 The whole problem is, with the C++ rules, the optimizations cannot even 
 be done by the code generator - you may think you've optimized something 
 with const, but in reality the code generator cannot make use of it 
 because of how const is implimented in C++ and the compiler cannot 
 figure out 100% for certain what is being done with referenced data.

Again I am willing to write to functions which provided together will give an optimal choice: void toUpper( in char[] strbuf ) // inplace char[] toUpper( in const char[] str ) // return brand new.

I understand - I think we're all looking for some way to implement "constness" in a way that is better, for at least the majority of cases, than how C++ does it. From Walter's earlier post, it appears that overloading based on some type of "const" storage modifier is not going to happen, so I'll take what I can get in this regard, especially if it helps compiler implementors do their job better because then I get better tools.

'"const" storage modifier is not going to happen,...' Then page http://www.digitalmars.com/d/comparison.html needs to be updated by features which are impossible to implement in D in principle. Just for the sake of truth.
 Walter wants D's "constness" to be taken as a semantic guarantee of some 
 value, and I agree with him on that, because then it's of more value to 
 both the compiler and someone debugging code (const the way it is in C++ 
 can actually hide bugs). I also agree with the notion that C++ constness 
 is a mess and that is one of the major reasons why I want D to succeed, so 
 I don't have to deal with that as it is.

 I take it you basically want C++ constness in D - I just have to disagree 
 with that because that's one of the things I think needs to be done 
 better.

The ultimate const protection can be done only on hardware level (I mean without compromises) which is not the case for D. About stylistic: I will repeat again: the best way (near ideal) is to be able to say something like this: type[def] string: char[] { private opIndexAssign(...) // disabled public string opSlice() // returns immutable slice.... ... etc... } It is more universal but significantly more complex. But I am pretty sure it is a future - to be able to fine tune type redefinitions of primitives. For a while I propose to introduce typedef#[] as an immutable version of typedef[] and typedef#* ...
 I am free to chose optimal function for particular case.
 And while implementing it compiler will not allow
 me to change *accidentally* value of str.

 private and package methods can't be virtual, so there are some 
 optimizations having to do with inlining and the vtable that can be (and 
 are) done by the compiler, because 'private' or 'package' guarantees 
 that those are not virtual methods.

I think that you a wrong here as following: import std.stdio; class One { package int foo() { return 1; } } class Two: One { override package int foo() { return 2; } } int main() { Two t = new Two; return t.foo(); } compiles just fine.

Try this: # dmd -version=_package pt.d # ./pt 1 1 vs. this: # dmd pt.d # ./pt 2 1 ;--- import std.stdio; class One { version(_package) package int foo() { return 1; } else public int foo() { return 1; } } class Two: One { version(_package) override package int foo() { return 2; } else override public int foo() { return 2; } } void main() { Two t = new Two; writefln((cast(One)t).foo()); One o = new One; writefln("%d\n",(cast(One)o).foo()); }

Nice! Just perfect! And those people are telling me that const hides possible errors? :-)))
Jul 03 2005
prev sibling parent reply "Walter" <newshound digitalmars.com> writes:
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message
news:da93ap$1g54$1 digitaldaemon.com...
 Walter, it is enough for me to know that

 int foo(const int *p, int *q)
    {
        int i = *p;
        *q = 3;

        .... 200 lines of code

        return *p;
    }

 will not change *p. I am not asking for optimization here. Optimization
 happened before - when I wrote this fucntion declaration using const
 parameters.

 I understand that you focused on optimiziation as compiler and

 writer. This is perfectly good and thank you for that.

The optimization issue is a symptom of the problem with const, not the problem itself. The inability to make *any* use of const for the compiler to learn something about the program is, to me anyway, indicative that the semantic value of const is not there. Optimizers work by being able to prove certain properties of code to be true. At a higher level, being able to prove certain things about a program is important for all kinds of code analysis tools, like verifiers, etc. Being able to prove something about a program is also useful for the programmer, as knowing something that must be true about a piece of code is the first step to debugging it. C++ const doesn't enable proving anything about the const reference. The optimizer can't prove the values won't change, and *neither can the programmer* rely on it. If I see a const reference in C++ code, I don't know if it really is constant or not. As a programmer looking at someone else's code, it offers no value.
 But const is a matter of language design and not about optimization.
 Well not exactly as if I will write both:

 int foo(const int *p, int *q)
 int foo(int *p, int *q)

 then I will make an act of optimization on the design level.

 Again: from the point of optimization 'public', 'private' attributes are
 almost worthless.
 But despite of that they are in the language. const is the same - it is a
 contract.
 Any argument that you can *intentionally* break constness are true.
 The same apply to visibility attributes.

My point (with the example given) is you are NOT breaking const. The code is legal, supported and is const-correct. It's not like const_cast, which is known to be an escape from const, can be grepped for, and can be warned about. There is no commonly accepted C++ convention that says such code is bad form, undefined, etc. And yes, these things do appear in real, working, production code, as I found out when attempting to use const in the optimizer. The only way "const" can be constant in C++ is if you follow an informal convention for your own code that is not enforced by the compiler or the language or by any third party whose code you might wish to use. You cannot assume that const is constant..
Jul 03 2005
parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Walter" <newshound digitalmars.com> wrote in message 
news:da99a9$1n0q$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:da93ap$1g54$1 digitaldaemon.com...
 Walter, it is enough for me to know that

 int foo(const int *p, int *q)
    {
        int i = *p;
        *q = 3;

        .... 200 lines of code

        return *p;
    }

 will not change *p. I am not asking for optimization here. Optimization
 happened before - when I wrote this fucntion declaration using const
 parameters.

 I understand that you focused on optimiziation as compiler and

 writer. This is perfectly good and thank you for that.

The optimization issue is a symptom of the problem with const, not the problem itself. The inability to make *any* use of const for the compiler to learn something about the program is, to me anyway, indicative that the semantic value of const is not there. Optimizers work by being able to prove certain properties of code to be true. At a higher level, being able to prove certain things about a program is important for all kinds of code analysis tools, like verifiers, etc. Being able to prove something about a program is also useful for the programmer, as knowing something that must be true about a piece of code is the first step to debugging it. C++ const doesn't enable proving anything about the const reference. The optimizer can't prove the values won't change, and *neither can the programmer* rely on it. If I see a const reference in C++ code, I don't know if it really is constant or not. As a programmer looking at someone else's code, it offers no value.

True. Except of the last statement: "As a programmer looking at someone else's code, it offers no value." When I am looking on: char[] toStringz(const char[] s) I can tell that: 1) function designed to do not change 's' 2) body of the function passed through compiler - it not contains stupid mistakes inside. Currently I am looking on char* toStringz(char[] s) and trying to guess - what a hell it is doing with my 's'? And finally I can see there memcpy from my friend - C runtime which I know declared as memcpy(void* dst, const void* src, size_t sz)... Could you please do the same? Without it DbC is not full in D.
 But const is a matter of language design and not about optimization.
 Well not exactly as if I will write both:

 int foo(const int *p, int *q)
 int foo(int *p, int *q)

 then I will make an act of optimization on the design level.

 Again: from the point of optimization 'public', 'private' attributes are
 almost worthless.
 But despite of that they are in the language. const is the same - it is a
 contract.
 Any argument that you can *intentionally* break constness are true.
 The same apply to visibility attributes.

My point (with the example given) is you are NOT breaking const. The code is legal, supported and is const-correct. It's not like const_cast, which is known to be an escape from const, can be grepped for, and can be warned about. There is no commonly accepted C++ convention that says such code is bad form, undefined, etc. And yes, these things do appear in real, working, production code, as I found out when attempting to use const in the optimizer. The only way "const" can be constant in C++ is if you follow an informal convention for your own code that is not enforced by the compiler or the language or by any third party whose code you might wish to use. You cannot assume that const is constant..

Exactly! And this is huge. If *you* will write: int foo(const char[] s) then I will trust you - Walter made as much as possible to ensure that foo is not changing s. So I don't need to waste my time digging inside *each* string function in Phobos. Ben propose to use 'to' for that... Is it better or what? Will you also implement "if function name starts from 'to' then ..."? Trying to optimize everything is good but close to "Road to hell is paved by good wishes". Andrew.
Jul 03 2005
parent reply "Walter" <newshound digitalmars.com> writes:
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message
news:da9sbs$29to$1 digitaldaemon.com...
 True.
 Except of the last statement:
 "As a programmer looking at someone else's code, it offers no value."

 When I am looking on:

 char[] toStringz(const char[] s)

 I can tell that:

 1) function designed to do not change 's'
 2) body of the function passed through compiler -
     it not contains stupid mistakes inside.

I will argue that you cannot tell that - especially if you are looking for bugs. The language offers no guarantees about const, so when you're going bug hunting, const is not helpful.
 Currently I am looking on

 char* toStringz(char[] s)

 and trying to guess - what a hell it is doing with my 's'?

I understand it can be helpful there, but I don't think it is as helpful as you do. I think there's a better way here somewhere, if we can find it.
Jul 04 2005
next sibling parent "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Walter" <newshound digitalmars.com> wrote in message 
news:dach1f$1u8t$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:da9sbs$29to$1 digitaldaemon.com...
 True.
 Except of the last statement:
 "As a programmer looking at someone else's code, it offers no value."

 When I am looking on:

 char[] toStringz(const char[] s)

 I can tell that:

 1) function designed to do not change 's'
 2) body of the function passed through compiler -
     it not contains stupid mistakes inside.

I will argue that you cannot tell that - especially if you are looking for bugs. The language offers no guarantees about const, so when you're going bug hunting, const is not helpful.

const helps me to do not do bugs. To change what is not designed to be changed. From the very beginning - at planning level. Hunting is a different story. But again such simple (well, from external look) preventive method can narrow the bug field a lot. DbC methods in D are good, but if code designer will not cover all conditions carefully then they at least meaningless if not worse...
 Currently I am looking on

 char* toStringz(char[] s)

 and trying to guess - what a hell it is doing with my 's'?

I understand it can be helpful there, but I don't think it is as helpful as you do. I think there's a better way here somewhere, if we can find it.

Yep, so far I can see three methods only. Hope somebody will add more. First is straightforward reproduction of const in C++ with all bells and whistles. Second is already defined in "Round III. Brainstrom...." (Explicit contsness, variant I) Third one I've already mentioned somewhere here and going to formalize today also. I like explicit contsness variants as more I would say D-ish (grammatically pure) and easily implementable - read reliable. But again it is my personal opinion only - means can be not perfect. Andrew.
Jul 04 2005
prev sibling parent "Unknown W. Brackets" <unknown simplemachines.org> writes:
Well, now, I have a question.  What does this say:

char* toStringz(in char[] s)

As compared to:

char* toStringz(char[] s)

Or:

char* toStringz(inout char[] s)

Since the in is explicitly specified (even if it is implicit) you can 
easily tell that the argument is meant not to modify the data pointed 
to.  If it says inout, then you can assume it returns and modifies the 
string.

It may not mean that it CAN'T change s, but there's only so much you can 
get out of stupid programmers.  In some cases, it's just a simple matter 
of knowing what you're doing.

-[Unknown]


 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:da9sbs$29to$1 digitaldaemon.com...
 
True.
Except of the last statement:
"As a programmer looking at someone else's code, it offers no value."

When I am looking on:

char[] toStringz(const char[] s)

I can tell that:

1) function designed to do not change 's'
2) body of the function passed through compiler -
    it not contains stupid mistakes inside.

I will argue that you cannot tell that - especially if you are looking for bugs. The language offers no guarantees about const, so when you're going bug hunting, const is not helpful.
Currently I am looking on

char* toStringz(char[] s)

and trying to guess - what a hell it is doing with my 's'?

I understand it can be helpful there, but I don't think it is as helpful as you do. I think there's a better way here somewhere, if we can find it.

Jul 04 2005
prev sibling parent reply Sean Kelly <sean f4.ca> writes:
In article <da88rb$ruj$1 digitaldaemon.com>, Walter says...
Consider the following C++ function:

    int foo(const int *p, int *q)
    {
        int i = *p;
        *q = 3;
        return *p;
    }

At the return statement, could we replace *p with i, thereby saving
ourselves a dereference operation? After all, p points to "const" data,
right? Wrong. Consider calling foo() this way:

    int a[3];
    ...
    foo(a, a);

Since p and q now hold the same value, *q = 3; will change the contents of
what p points to.

This code is perfectly legal C++, and is "const-correct". It happens often
enough in real code, too, as I discovered when trying to implement this
optimization.

Why do I suddenly feel like we're moving towards defining 'restrict' in D? :) Sean
Jul 03 2005
parent Dave <Dave_member pathlink.com> writes:
In article <da9716$1knv$1 digitaldaemon.com>, Sean Kelly says...
In article <da88rb$ruj$1 digitaldaemon.com>, Walter says...
Consider the following C++ function:

    int foo(const int *p, int *q)
    {
        int i = *p;
        *q = 3;
        return *p;
    }

At the return statement, could we replace *p with i, thereby saving
ourselves a dereference operation? After all, p points to "const" data,
right? Wrong. Consider calling foo() this way:

    int a[3];
    ...
    foo(a, a);

Since p and q now hold the same value, *q = 3; will change the contents of
what p points to.

This code is perfectly legal C++, and is "const-correct". It happens often
enough in real code, too, as I discovered when trying to implement this
optimization.

Why do I suddenly feel like we're moving towards defining 'restrict' in D? :) Sean

Take a peek in the archives on that subject - I don't think you need to worry about that <g> - Dave
Jul 03 2005
prev sibling parent reply Nick <Nick_member pathlink.com> writes:
In article <da7pp5$i06$1 digitaldaemon.com>, Walter says...
Yet the value can change anyway. Another reference can change it, and
another thread can change it. It isn't "constant" at all, and cannot be
relied on to be constant, even if your program is 100% "const-correct".

That is true, but also in fact completly irrelevant. I think you might have misunderstood the intention of the const keyword in C++. It's not meant to be, and has never been meant to be, a guarantee to the internals of the function that "this value will not change". It's not supposed to protect the INSIDE of the function from the outside world, but quite the opposite. It's a guarantee (or contract, if you will) with the code OUTSIDE the function (ie. the caller) that "THIS function will never change this value." What happens in other threads and other references has no relevance to this contract. Also, your example with foo(a,a) is ok, since when you (the caller) send 'a' as the second (non-const) parameter, the function is 'allowed' to change it. Thus the function has not broken the contract. I am not arguing for or against const in D here. My experience with it in C++ has been pretty much the same as yours, and so I am not really convinced of it's usefulness. But your argument really attacks a use of 'const' that was never intended, and thus is not a very good argument. Nick
Jul 03 2005
parent reply "Walter" <newshound digitalmars.com> writes:
"Nick" <Nick_member pathlink.com> wrote in message
news:da9dfv$1r9p$1 digitaldaemon.com...
 In article <da7pp5$i06$1 digitaldaemon.com>, Walter says...
Yet the value can change anyway. Another reference can change it, and
another thread can change it. It isn't "constant" at all, and cannot be
relied on to be constant, even if your program is 100% "const-correct".

That is true, but also in fact completly irrelevant. I think you might

 misunderstood the intention of the const keyword in C++. It's not meant to

 and has never been meant to be, a guarantee to the internals of the

 that "this value will not change". It's not supposed to protect the INSIDE

 the function from the outside world, but quite the opposite. It's a

 (or contract, if you will) with the code OUTSIDE the function (ie. the

 that "THIS function will never change this value." What happens in other

 and other references has no relevance to this contract. Also, your example

 foo(a,a) is ok, since when you (the caller) send 'a' as the second

 parameter, the function is 'allowed' to change it. Thus the function has

 broken the contract.

 I am not arguing for or against const in D here. My experience with it in

 has been pretty much the same as yours, and so I am not really convinced

 usefulness. But your argument really attacks a use of 'const' that was

 intended, and thus is not a very good argument.

You do make a good point.
Jul 03 2005
parent "Regan Heath" <regan netwin.co.nz> writes:
On Sun, 3 Jul 2005 15:05:20 -0700, Walter <newshound digitalmars.com>  
wrote:
 "Nick" <Nick_member pathlink.com> wrote in message
 news:da9dfv$1r9p$1 digitaldaemon.com...
 In article <da7pp5$i06$1 digitaldaemon.com>, Walter says...
Yet the value can change anyway. Another reference can change it, and
another thread can change it. It isn't "constant" at all, and cannot be
relied on to be constant, even if your program is 100% "const-correct".

That is true, but also in fact completly irrelevant. I think you might

 misunderstood the intention of the const keyword in C++. It's not meant  
 to

 and has never been meant to be, a guarantee to the internals of the

 that "this value will not change". It's not supposed to protect the  
 INSIDE

 the function from the outside world, but quite the opposite. It's a

 (or contract, if you will) with the code OUTSIDE the function (ie. the

 that "THIS function will never change this value." What happens in other

 and other references has no relevance to this contract. Also, your  
 example

 foo(a,a) is ok, since when you (the caller) send 'a' as the second

 parameter, the function is 'allowed' to change it. Thus the function has

 broken the contract.

 I am not arguing for or against const in D here. My experience with it  
 in

 has been pretty much the same as yours, and so I am not really convinced

 usefulness. But your argument really attacks a use of 'const' that was

 intended, and thus is not a very good argument.

You do make a good point.

This is the same point I've tried to make in the past. To me 'in' is part of the function contract stating I will only 'read' this parameter. I had a DBC style idea for detecting modification to 'in' parameters, it went: 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; } The compiler could concievably insert these checks itself. Of course, this only detects changes to the variable itself be it a reference, pointer, int etc. It does not address the other desire, to protect the data referenced by the variable. Regan
Jul 03 2005
prev sibling parent reply "Dave" <Dave_member pathlink.com> writes:
"Walter" <newshound digitalmars.com> wrote in message 
news:da6k71$11rs$1 digitaldaemon.com...
 "Ben Hinkle" <bhinkle mathworks.com> wrote in message
 news:da4afr$24jc$1 digitaldaemon.com...
 How would this cover the following case that Walter's proposal covers:
 class A { int x; }
 void foo(in A obj){
   int y = obj.x;
   // do whatever you want...
   assert( obj.x == y );
 }
 void main() {
   A obj = new A;
   foo(obj); // says it doesn't change obj
 }
 Is it practical to force A to implement some immutability just because 
 foo
 doesn't change its inputs? I'm not saying Walter's proposal is prefect.

 very strong for foo to say no other thread or reference will change obj
 since it has no control over what other threads are doing. I would be

 pretty much blind leap of faith when declaring an object reference as 
 'in'
 and saying that no other thread is stepping on that object during the 
 call
 lifetime.

You're right. I have misgivings about it for that reason. On the other hand, look at C++ "const". Nothing about "const" says that some other thread or reference cannot change the value out from under you at any moment. Furthermore, it can be cast away and modified anyway. The semantic value of C++ "const" is essentially zip. This is why I am often flummoxed why it is given such weight in C++.

It is equally probable that another thread could step on obj within the foo() call lifetime as it is now, regardless of any optimizations that the "in" proposal allows, so I don't think that concern should be a show stopper. Either way the results are the same - sporadically incorrect results, and either way it is going to be a bear to debug and proper synchronization by the /user/ of obj and foo() will be the way to fix the problem - same as any other multi-threading issue. I see no problem with just removing the part of the proposal that promises that no other /thread/ will change obj. because I don't think that is practical in any sense at the language implementaton level for a language with the goals of D (D doesn't offer or promise auto-synchronization in any other case, does it?). - Dave
Jul 03 2005
parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
"Dave" <Dave_member pathlink.com> wrote in message 
news:da8nqk$161t$1 digitaldaemon.com...
 "Walter" <newshound digitalmars.com> wrote in message 
 news:da6k71$11rs$1 digitaldaemon.com...
 "Ben Hinkle" <bhinkle mathworks.com> wrote in message
 news:da4afr$24jc$1 digitaldaemon.com...
 How would this cover the following case that Walter's proposal covers:
 class A { int x; }
 void foo(in A obj){
   int y = obj.x;
   // do whatever you want...
   assert( obj.x == y );
 }
 void main() {
   A obj = new A;
   foo(obj); // says it doesn't change obj
 }
 Is it practical to force A to implement some immutability just because 
 foo
 doesn't change its inputs? I'm not saying Walter's proposal is prefect.

 very strong for foo to say no other thread or reference will change obj
 since it has no control over what other threads are doing. I would be

 pretty much blind leap of faith when declaring an object reference as 
 'in'
 and saying that no other thread is stepping on that object during the 
 call
 lifetime.

You're right. I have misgivings about it for that reason. On the other hand, look at C++ "const". Nothing about "const" says that some other thread or reference cannot change the value out from under you at any moment. Furthermore, it can be cast away and modified anyway. The semantic value of C++ "const" is essentially zip. This is why I am often flummoxed why it is given such weight in C++.

It is equally probable that another thread could step on obj within the foo() call lifetime as it is now, regardless of any optimizations that the "in" proposal allows, so I don't think that concern should be a show stopper. Either way the results are the same - sporadically incorrect results, and either way it is going to be a bear to debug and proper synchronization by the /user/ of obj and foo() will be the way to fix the problem - same as any other multi-threading issue. I see no problem with just removing the part of the proposal that promises that no other /thread/ will change obj. because I don't think that is practical in any sense at the language implementaton level for a language with the goals of D (D doesn't offer or promise auto-synchronization in any other case, does it?). - Dave

You're right - the threading model shouldn't enter into it. I'm liking Walter's suggestion more now. Earlier I thought it was too strong a condition but now I can see, for example, lots of places in phobos where 'in' can be used.
Jul 03 2005
parent reply "Dave" <Dave_member pathlink.com> writes:
"Ben Hinkle" <ben.hinkle gmail.com> wrote in message 
news:da8qa5$17op$1 digitaldaemon.com...
 "Dave" <Dave_member pathlink.com> wrote in message 
 news:da8nqk$161t$1 digitaldaemon.com...
 "Walter" <newshound digitalmars.com> wrote in message 
 news:da6k71$11rs$1 digitaldaemon.com...
 "Ben Hinkle" <bhinkle mathworks.com> wrote in message
 news:da4afr$24jc$1 digitaldaemon.com...
 How would this cover the following case that Walter's proposal covers:
 class A { int x; }
 void foo(in A obj){
   int y = obj.x;
   // do whatever you want...
   assert( obj.x == y );
 }
 void main() {
   A obj = new A;
   foo(obj); // says it doesn't change obj
 }
 Is it practical to force A to implement some immutability just because 
 foo
 doesn't change its inputs? I'm not saying Walter's proposal is prefect.

 very strong for foo to say no other thread or reference will change obj
 since it has no control over what other threads are doing. I would be

 pretty much blind leap of faith when declaring an object reference as 
 'in'
 and saying that no other thread is stepping on that object during the 
 call
 lifetime.

You're right. I have misgivings about it for that reason. On the other hand, look at C++ "const". Nothing about "const" says that some other thread or reference cannot change the value out from under you at any moment. Furthermore, it can be cast away and modified anyway. The semantic value of C++ "const" is essentially zip. This is why I am often flummoxed why it is given such weight in C++.

It is equally probable that another thread could step on obj within the foo() call lifetime as it is now, regardless of any optimizations that the "in" proposal allows, so I don't think that concern should be a show stopper. Either way the results are the same - sporadically incorrect results, and either way it is going to be a bear to debug and proper synchronization by the /user/ of obj and foo() will be the way to fix the problem - same as any other multi-threading issue. I see no problem with just removing the part of the proposal that promises that no other /thread/ will change obj. because I don't think that is practical in any sense at the language implementaton level for a language with the goals of D (D doesn't offer or promise auto-synchronization in any other case, does it?). - Dave

You're right - the threading model shouldn't enter into it. I'm liking Walter's suggestion more now. Earlier I thought it was too strong a condition but now I can see, for example, lots of places in phobos where 'in' can be used.

I think Walter's idea is a great idea and a good compromise! Truth be told, I actually think the following would be the best: [none]/in/out/inout - [none] and 'in' would follow the new proposal with regard to 'immutable', and /all/ would allow the new opimizations that I think Walter has in mind. The exceptions would be pointer params. and functions declared extern or exported, which would simply operate as they do now, where the expectation is that they are treated differently anyway. volatile/volatile in/volatile out/volatile inout - 'volatile', 'volatile in', 'volatile out' and 'volatile inout' params. would basically operate exactly as they do now. Just like other statements in any other scope, a "volatile" param. would mean "inhibit optimizations on the variable that may effect memory reads/writes". Not even a new keyword.. The whole justification for these new defaults is because the cases where "volatile" would have to be used for the code to operate correctly are a small minority, so shouldn't the default go with what benefits the great majority of cases? Also, the same justification goes for making the default [none] and 'in' operate the same way w.r.t. the new proposal - majority of cases rules. Another big plus would be not having to litter code with 'in' (like C++ code is littered with 'const').
Jul 03 2005
parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Dave" <Dave_member pathlink.com> wrote in message 
news:da931u$1fto$1 digitaldaemon.com...
 "Ben Hinkle" <ben.hinkle gmail.com> wrote in message 
 news:da8qa5$17op$1 digitaldaemon.com...
 "Dave" <Dave_member pathlink.com> wrote in message 
 news:da8nqk$161t$1 digitaldaemon.com...
 "Walter" <newshound digitalmars.com> wrote in message 
 news:da6k71$11rs$1 digitaldaemon.com...
 "Ben Hinkle" <bhinkle mathworks.com> wrote in message
 news:da4afr$24jc$1 digitaldaemon.com...
 How would this cover the following case that Walter's proposal covers:
 class A { int x; }
 void foo(in A obj){
   int y = obj.x;
   // do whatever you want...
   assert( obj.x == y );
 }
 void main() {
   A obj = new A;
   foo(obj); // says it doesn't change obj
 }
 Is it practical to force A to implement some immutability just because 
 foo
 doesn't change its inputs? I'm not saying Walter's proposal is 
 prefect.

 very strong for foo to say no other thread or reference will change 
 obj
 since it has no control over what other threads are doing. I would be

 pretty much blind leap of faith when declaring an object reference as 
 'in'
 and saying that no other thread is stepping on that object during the 
 call
 lifetime.

You're right. I have misgivings about it for that reason. On the other hand, look at C++ "const". Nothing about "const" says that some other thread or reference cannot change the value out from under you at any moment. Furthermore, it can be cast away and modified anyway. The semantic value of C++ "const" is essentially zip. This is why I am often flummoxed why it is given such weight in C++.

It is equally probable that another thread could step on obj within the foo() call lifetime as it is now, regardless of any optimizations that the "in" proposal allows, so I don't think that concern should be a show stopper. Either way the results are the same - sporadically incorrect results, and either way it is going to be a bear to debug and proper synchronization by the /user/ of obj and foo() will be the way to fix the problem - same as any other multi-threading issue. I see no problem with just removing the part of the proposal that promises that no other /thread/ will change obj. because I don't think that is practical in any sense at the language implementaton level for a language with the goals of D (D doesn't offer or promise auto-synchronization in any other case, does it?). - Dave

You're right - the threading model shouldn't enter into it. I'm liking Walter's suggestion more now. Earlier I thought it was too strong a condition but now I can see, for example, lots of places in phobos where 'in' can be used.

I think Walter's idea is a great idea and a good compromise! Truth be told, I actually think the following would be the best: [none]/in/out/inout - [none] and 'in' would follow the new proposal with regard to 'immutable', and /all/ would allow the new opimizations that I think Walter has in mind. The exceptions would be pointer params. and functions declared extern or exported, which would simply operate as they do now, where the expectation is that they are treated differently anyway.

1) How in will solve this: class Record { Field[] fields() { return m_fields.dup; // this is not needed, isn't it? // but it must be here in current D. } } 2) 'In' does not allow to distinguish cases: void toUpper(in char[] str_in_place); char[] toUpper(in const char[] str); and select optimal implementation.
 volatile/volatile in/volatile out/volatile inout - 'volatile', 'volatile 
 in', 'volatile out' and 'volatile inout' params. would basically operate 
 exactly as they do now. Just like other statements in any other scope, a 
 "volatile" param. would mean "inhibit optimizations on the variable that 
 may effect memory reads/writes". Not even a new keyword..

 The whole justification for these new defaults is because the cases where 
 "volatile" would have to be used for the code to operate correctly are a 
 small minority, so shouldn't the default go with what benefits the great 
 majority of cases?

 Also, the same justification goes for making the default [none] and 'in' 
 operate the same way w.r.t. the new proposal - majority of cases rules. 
 Another big plus would be not having to litter code with 'in' (like C++ 
 code is littered with 'const').

"littered with 'const'".... well, it depends.... If European will see Stone Garden in Japan he will find it littered by stones. For me personally code which is not using const looks non-prefessional and written by young hacker in 'fire-n-forget' mode. Non maintainable, non reliable, non optimized. Someone can tell that: private int something1 public int something2 is littered with private and public. Does it *really* mean that it is littered? Andrew.
Jul 03 2005
parent reply "Walter" <newshound digitalmars.com> writes:
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message
news:da95gq$1j4t$1 digitaldaemon.com...
 1) How in will solve this:

 class Record
 {
     Field[] fields()
     {
         return m_fields.dup; // this is not needed, isn't it?
                                      // but it must be here in current D.
     }
 }

It won't, but then again, I don't see that the .dup is necessary there, as fields() is a producer of a value, not a consumer.
 2) 'In' does not allow to distinguish cases:

 void toUpper(in char[] str_in_place);
 char[] toUpper(in const char[] str);

 and select optimal implementation.

That's correct, there would be no overloading based on const-ness. I know this is commonplace in C++, but frankly I think it's poor design. A function overloaded on const implicitly has significantly different behavior, and so should have a different name.
 volatile/volatile in/volatile out/volatile inout - 'volatile', 'volatile
 in', 'volatile out' and 'volatile inout' params. would basically operate
 exactly as they do now. Just like other statements in any other scope, a
 "volatile" param. would mean "inhibit optimizations on the variable that
 may effect memory reads/writes". Not even a new keyword..

 The whole justification for these new defaults is because the cases


 "volatile" would have to be used for the code to operate correctly are a
 small minority, so shouldn't the default go with what benefits the great
 majority of cases?

 Also, the same justification goes for making the default [none] and 'in'
 operate the same way w.r.t. the new proposal - majority of cases rules.
 Another big plus would be not having to litter code with 'in' (like C++
 code is littered with 'const').

"littered with 'const'".... well, it depends.... If European will see Stone Garden in Japan he will find it littered by stones. For me personally code which is not using const looks non-prefessional and written by young hacker in 'fire-n-forget' mode. Non maintainable, non reliable, non optimized. Someone can tell that: private int something1 public int something2 is littered with private and public. Does it *really* mean that it is littered?

The idea is that the most common case should be the default. Would you agree that for the vast majority of function parameters, they are read only? That mutable ones are relatively rare? If so, then it makes sense to have the uncommon ones need the extra syntax. As for myself, since most parameters in C++ code are const, the const everywhere tends to visually clutter up the code, obscuring the other stuff.
Jul 03 2005
next sibling parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
 2) 'In' does not allow to distinguish cases:

 void toUpper(in char[] str_in_place);
 char[] toUpper(in const char[] str);

 and select optimal implementation.

That's correct, there would be no overloading based on const-ness. I know this is commonplace in C++, but frankly I think it's poor design. A function overloaded on const implicitly has significantly different behavior, and so should have a different name.

Perhaps dstyle.html should say functions with a leading 'to' should not modify their inputs. There are several toFoo functions in phobos and it would be nice to keep that style consistent.
Jul 03 2005
parent reply "Walter" <newshound digitalmars.com> writes:
"Ben Hinkle" <ben.hinkle gmail.com> wrote in message
news:da9b6j$1ouo$1 digitaldaemon.com...
 Perhaps dstyle.html should say functions with a leading 'to' should not
 modify their inputs. There are several toFoo functions in phobos and it
 would be nice to keep that style consistent.

That's a good idea. There are also the 'is' prefix functions.
Jul 03 2005
parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Walter" <newshound digitalmars.com> wrote in message 
news:da9dc2$1r5s$2 digitaldaemon.com...
 "Ben Hinkle" <ben.hinkle gmail.com> wrote in message
 news:da9b6j$1ouo$1 digitaldaemon.com...
 Perhaps dstyle.html should say functions with a leading 'to' should not
 modify their inputs. There are several toFoo functions in phobos and it
 would be nice to keep that style consistent.

That's a good idea. There are also the 'is' prefix functions.

I beleive that next will be a proposal to use 'c' as a first char of parameter name and all this will end up with Polish Notation and the like... Poor man type system to be short. Gentlemen, array and immutable slice are two *distinct* types with their own set of operations. The same for pointers - immutable pointer cannot be dereferenced to l-value. And please don't cover holes in type system by inventing naming conventions. This is not honest. Andrew.
Jul 03 2005
parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message 
news:da9k9n$2201$1 digitaldaemon.com...
 "Walter" <newshound digitalmars.com> wrote in message 
 news:da9dc2$1r5s$2 digitaldaemon.com...
 "Ben Hinkle" <ben.hinkle gmail.com> wrote in message
 news:da9b6j$1ouo$1 digitaldaemon.com...
 Perhaps dstyle.html should say functions with a leading 'to' should not
 modify their inputs. There are several toFoo functions in phobos and it
 would be nice to keep that style consistent.

That's a good idea. There are also the 'is' prefix functions.

I beleive that next will be a proposal to use 'c' as a first char of parameter name and all this will end up with Polish Notation and the like... Poor man type system to be short. Gentlemen, array and immutable slice are two *distinct* types with their own set of operations. The same for pointers - immutable pointer cannot be dereferenced to l-value. And please don't cover holes in type system by inventing naming conventions. This is not honest. Andrew.

Nothing is preventing someone from writing void upper(char[] str); char[] toUpper(char[] str); I see no reason to abuse the already-established conventions with the "to" prefix. Multiple versions of toUpper might seem natural to you and your team but it isn't "typical" D code. Even if all your proposals were accepted I would still argue a function named toUpper should not modify its input. That isn't saying your general point is wrong - just that the example you gave using the name "toUpper" isn't one that should be encouraged.
Jul 03 2005
parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Ben Hinkle" <ben.hinkle gmail.com> wrote in message 
news:da9lak$23de$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message 
 news:da9k9n$2201$1 digitaldaemon.com...
 "Walter" <newshound digitalmars.com> wrote in message 
 news:da9dc2$1r5s$2 digitaldaemon.com...
 "Ben Hinkle" <ben.hinkle gmail.com> wrote in message
 news:da9b6j$1ouo$1 digitaldaemon.com...
 Perhaps dstyle.html should say functions with a leading 'to' should not
 modify their inputs. There are several toFoo functions in phobos and it
 would be nice to keep that style consistent.

That's a good idea. There are also the 'is' prefix functions.

I beleive that next will be a proposal to use 'c' as a first char of parameter name and all this will end up with Polish Notation and the like... Poor man type system to be short. Gentlemen, array and immutable slice are two *distinct* types with their own set of operations. The same for pointers - immutable pointer cannot be dereferenced to l-value. And please don't cover holes in type system by inventing naming conventions. This is not honest. Andrew.

Nothing is preventing someone from writing void upper(char[] str); char[] toUpper(char[] str); I see no reason to abuse the already-established conventions with the "to" prefix. Multiple versions of toUpper might seem natural to you and your team but it isn't "typical" D code. Even if all your proposals were accepted I would still argue a function named toUpper should not modify its input. That isn't saying your general point is wrong - just that the example you gave using the name "toUpper" isn't one that should be encouraged.

Ben, am I propsing to abuse naming conventions? No. 'to' works in some places and for someone - fine. But how this related to const? OT: this 'to' in Russian is one letter and sometimes looks funny combined with camelCase.
Jul 03 2005
parent Victor Nakoryakov <nail-mail mail.ru> writes:
Andrew Fedoniouk wrote:
 
 OT: this 'to' in Russian is one letter and sometimes looks funny combined
 with camelCase.
 

Emmmm... All speaking russian use english for variables/methods/classes as well as in comments. So this is no matter how such things are translated to native language, you will never find constructions ala stroka kStroke(); :) -- Victor (aka nail) Nakoryakov nail-mail<at>mail<dot>ru Krasnoznamensk, Moscow, Russia
Jul 04 2005
prev sibling next sibling parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Walter" <newshound digitalmars.com> wrote in message 
news:da99t5$1net$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:da95gq$1j4t$1 digitaldaemon.com...
 1) How in will solve this:

 class Record
 {
     Field[] fields()
     {
         return m_fields.dup; // this is not needed, isn't it?
                                      // but it must be here in current D.
     }
 }

It won't, but then again, I don't see that the .dup is necessary there, as fields() is a producer of a value, not a consumer.
 2) 'In' does not allow to distinguish cases:

 void toUpper(in char[] str_in_place);
 char[] toUpper(in const char[] str);

 and select optimal implementation.

That's correct, there would be no overloading based on const-ness. I know this is commonplace in C++, but frankly I think it's poor design. A function overloaded on const implicitly has significantly different behavior, and so should have a different name.
 volatile/volatile in/volatile out/volatile inout - 'volatile', 
 'volatile
 in', 'volatile out' and 'volatile inout' params. would basically 
 operate
 exactly as they do now. Just like other statements in any other scope, 
 a
 "volatile" param. would mean "inhibit optimizations on the variable 
 that
 may effect memory reads/writes". Not even a new keyword..

 The whole justification for these new defaults is because the cases


 "volatile" would have to be used for the code to operate correctly are 
 a
 small minority, so shouldn't the default go with what benefits the 
 great
 majority of cases?

 Also, the same justification goes for making the default [none] and 
 'in'
 operate the same way w.r.t. the new proposal - majority of cases rules.
 Another big plus would be not having to litter code with 'in' (like C++
 code is littered with 'const').

"littered with 'const'".... well, it depends.... If European will see Stone Garden in Japan he will find it littered by stones. For me personally code which is not using const looks non-prefessional and written by young hacker in 'fire-n-forget' mode. Non maintainable, non reliable, non optimized. Someone can tell that: private int something1 public int something2 is littered with private and public. Does it *really* mean that it is littered?

The idea is that the most common case should be the default. Would you agree that for the vast majority of function parameters, they are read only? That mutable ones are relatively rare? If so, then it makes sense to have the uncommon ones need the extra syntax.

Walter, imagine that you know nothing about internals of this function: char* toStringz(char[] string) what you can tell about it? And if you'll see char[] toStringz(const char[] string) isn't it better? You don't need documentation or its source code in most cases.
 As for myself, since most parameters in C++ code are const, the const
 everywhere tends to visually clutter up the code, obscuring the other 
 stuff.

most cases are strings I believe. So do alias const char[] string; alias char[] string_buffer; and use this strings. Word 'string' has same number of characters as 'char[]'. And forget about clutter.
Jul 03 2005
parent "Walter" <newshound digitalmars.com> writes:
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message
news:da9jf7$210d$1 digitaldaemon.com...
 most cases are strings I believe. So do

I'm afraid not. Take a look at the STL source code :-( Go into \dm\stlport\stlport\stl and do a grep for "const".
Jul 03 2005
prev sibling parent "Andrew Fedoniouk" <news terrainformatica.com> writes:
"Walter" <newshound digitalmars.com> wrote in message 
news:da99t5$1net$1 digitaldaemon.com...
 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:da95gq$1j4t$1 digitaldaemon.com...
 1) How in will solve this:

 class Record
 {
     Field[] fields()
     {
         return m_fields.dup; // this is not needed, isn't it?
                                      // but it must be here in current D.
     }
 }

It won't, but then again, I don't see that the .dup is necessary there, as fields() is a producer of a value, not a consumer.
 2) 'In' does not allow to distinguish cases:

 void toUpper(in char[] str_in_place);
 char[] toUpper(in const char[] str);

 and select optimal implementation.

That's correct, there would be no overloading based on const-ness. I know this is commonplace in C++, but frankly I think it's poor design. A function overloaded on const implicitly has significantly different behavior, and so should have a different name.

1 ) There are situations when you just cannot use different names. E.g. template specializations. 2) "overloaded on const implicitly has significantly different behavior" This apply also to all cases of function overloading. E.g. foo(int i) and foo(char[] s) might have a significantly different behavior, isn't it? 3) "should have a different name" - someone will consider D as language forcing "name pollution" then. Following this statement all toString() shall be rewritten as toStringFromXXX( XXX x );
 volatile/volatile in/volatile out/volatile inout - 'volatile', 
 'volatile
 in', 'volatile out' and 'volatile inout' params. would basically 
 operate
 exactly as they do now. Just like other statements in any other scope, 
 a
 "volatile" param. would mean "inhibit optimizations on the variable 
 that
 may effect memory reads/writes". Not even a new keyword..

 The whole justification for these new defaults is because the cases


 "volatile" would have to be used for the code to operate correctly are 
 a
 small minority, so shouldn't the default go with what benefits the 
 great
 majority of cases?

 Also, the same justification goes for making the default [none] and 
 'in'
 operate the same way w.r.t. the new proposal - majority of cases rules.
 Another big plus would be not having to litter code with 'in' (like C++
 code is littered with 'const').

"littered with 'const'".... well, it depends.... If European will see Stone Garden in Japan he will find it littered by stones. For me personally code which is not using const looks non-prefessional and written by young hacker in 'fire-n-forget' mode. Non maintainable, non reliable, non optimized. Someone can tell that: private int something1 public int something2 is littered with private and public. Does it *really* mean that it is littered?

The idea is that the most common case should be the default. Would you agree that for the vast majority of function parameters, they are read only? That mutable ones are relatively rare? If so, then it makes sense to have the uncommon ones need the extra syntax. As for myself, since most parameters in C++ code are const, the const everywhere tends to visually clutter up the code, obscuring the other stuff.

Yep, as I meantioned above: alias const char[] string; will help.
Jul 03 2005