www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - preparing for const, final, and invariant

reply Walter Bright <newshound1 digitalmars.com> writes:
This is coming for the D 2.0 beta, and it will need some source code 
changes. Specifically, for function parameters that are arrays or 
pointers, start using 'in' for them.

'in' will mean 'scope const final', which means:

final - the parameter will not be reassigned within the function
const - the function will not attempt to change the contents of what is 
referred to
scope - the function will not keep a reference to the parameter's data 
that will persist beyond the scope of the function

For example:

int[] g;

void foo(in int[] a)
{
     a = [1,2];	// error, a is final
     a[1] = 2;   // error, a is const
     g = a;	// error, a is scope
}

Do not use 'in' if you wish to do any of these operations on a 
parameter. Using 'in' has no useful effect on D 1.0 code, so it'll be 
backwards compatible.

Adding in all those 'in's is tedious, as I'm finding out :-(, but I 
think the results will be worth the effort.
May 17 2007
next sibling parent reply Frank Benoit <keinfarbton googlemail.com> writes:
int[] g;
void foo(in int[] a){
    g = a.dup;    // allowed?
}
May 17 2007
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Frank Benoit wrote:
 int[] g;
 void foo(in int[] a){
     g = a.dup;    // allowed?
 }

Yes.
May 17 2007
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Walter Bright wrote

 Frank Benoit wrote:
 int[] g;
 void foo(in int[] a){
     g = a.dup;    // allowed?
 }

Yes.

The `.dup'ing an array where a cell contains a reference to the array is allowed too? alias void* T; T[] a; void main(){ T[] g; g.length= 1; g[0]=&g; void f( in T[] p){ a= p.dup; } } That would contradict the given rule. -manfred
May 17 2007
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Manfred Nowak wrote:
 Walter Bright wrote
 
 Frank Benoit wrote:
 int[] g;
 void foo(in int[] a){
     g = a.dup;    // allowed?
 }


The `.dup'ing an array where a cell contains a reference to the array is allowed too? alias void* T; T[] a; void main(){ T[] g; g.length= 1; g[0]=&g; void f( in T[] p){ a= p.dup; } } That would contradict the given rule.

I don't understand. What rule is being violated, and how?
May 17 2007
parent reply =?ISO-8859-1?Q?Manuel_K=F6nig?= <ManuelK89 gmx.net> writes:
Walter Bright wrote:
 Manfred Nowak wrote:
 Walter Bright wrote

 Frank Benoit wrote:
 int[] g;
 void foo(in int[] a){
     g = a.dup;    // allowed?
 }


The `.dup'ing an array where a cell contains a reference to the array is allowed too? alias void* T; T[] a; void main(){ T[] g; g.length= 1; g[0]=&g; void f( in T[] p){ a= p.dup; } } That would contradict the given rule.

I don't understand. What rule is being violated, and how?

I think he is concerning to the scope rule. When 'f' gets called with 'g' as param, then 'a' has implicitly a reference to 'g', namely in a[0]. This would be a violation of the scope rule. -- Regards Manuel
May 18 2007
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Manuel König wrote:
 I think he is concerning to the scope rule. When 'f' gets called with 
 'g' as param, then 'a' has implicitly a reference to 'g', namely in 
 a[0]. This would be a violation of the scope rule.

Passing things through void* is a way of escaping the type checking, and if you break the rules by doing so, your program might break.
May 18 2007
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Walter Bright wrote

 Passing things through void* is a way of escaping the type
 checking, and if you break the rules by doing so, your program
 might break. 

The compiler seems to follow the specs which say | A pointer T* can be implicitly converted to one of the following: | | void* There is no hint in the specs that this even _implicite_ possible conversion is breaking the security of the type system. But let me assume for now, that this implicite conversion is an exception and that "breaks type system" will be included in the specs. Now how about using a circular list, i.e avoiding use of `void *' struct T{ T* next; } T a; void main(){ T g; g.next= &g; void f( in T p){ a= *(p.next); // *_ } f( g); // breaking of scope rule? } -manfred
May 18 2007
parent Walter Bright <newshound1 digitalmars.com> writes:
Manfred Nowak wrote:
 Walter Bright wrote
 
 Passing things through void* is a way of escaping the type
 checking, and if you break the rules by doing so, your program
 might break. 

The compiler seems to follow the specs which say | A pointer T* can be implicitly converted to one of the following: | | void* There is no hint in the specs that this even _implicite_ possible conversion is breaking the security of the type system. But let me assume for now, that this implicite conversion is an exception and that "breaks type system" will be included in the specs. Now how about using a circular list, i.e avoiding use of `void *' struct T{ T* next; } T a; void main(){ T g; g.next= &g; void f( in T p){ a= *(p.next); // *_ } f( g); // breaking of scope rule? }

Yes, you're breaking it.
May 18 2007
prev sibling next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Walter Bright wrote:
 This is coming for the D 2.0 beta, and it will need some source code 
 changes. Specifically, for function parameters that are arrays or 
 pointers, start using 'in' for them.
 
 'in' will mean 'scope const final', which means:
 
 final - the parameter will not be reassigned within the function
 const - the function will not attempt to change the contents of what is 
 referred to
 scope - the function will not keep a reference to the parameter's data 
 that will persist beyond the scope of the function
 
 For example:
 
 int[] g;
 
 void foo(in int[] a)
 {
     a = [1,2];    // error, a is final
     a[1] = 2;   // error, a is const
     g = a;    // error, a is scope
 }
 
 Do not use 'in' if you wish to do any of these operations on a 
 parameter. Using 'in' has no useful effect on D 1.0 code, so it'll be 
 backwards compatible.
 
 Adding in all those 'in's is tedious, as I'm finding out :-(, but I 
 think the results will be worth the effort.

So if you don't use 'in' then the behavior will the the same as not using anything (or using 'in') in D1.0? --bb
May 17 2007
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Bill Baxter wrote:
 So if you don't use 'in' then the behavior will the the same as not 
 using anything (or using 'in') in D1.0?

Right - except that you won't be able to past string literals to them (as string literals will be const).
May 17 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Walter Bright wrote:
 Bill Baxter wrote:
 So if you don't use 'in' then the behavior will the the same as not 
 using anything (or using 'in') in D1.0?

Right - except that you won't be able to past string literals to them (as string literals will be const).

Ok. Well that is actually a little nicer than C++ where every reference param you don't intend to modify needs to be marked 'const'. Nicer in the sense that 'in' is shorter to type, at least, and in that it won't make Don Clugston cringe every time he has to type it. What about method signatures that want 'this' to be an 'in' param. Trailing 'in' like C++? void aMethod() in { writefln(x, toString); } Seems a little strange but I'm sure I'd get used to it. I guess const would mean the same thing, though, since 'this' is already final and scope doesn't really apply. --bb
May 17 2007
parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Bill Baxter wrote:
 Walter Bright wrote:
 Bill Baxter wrote:
 So if you don't use 'in' then the behavior will the the same as not 
 using anything (or using 'in') in D1.0?

Right - except that you won't be able to past string literals to them (as string literals will be const).

Ok. Well that is actually a little nicer than C++ where every reference param you don't intend to modify needs to be marked 'const'. Nicer in the sense that 'in' is shorter to type, at least, and in that it won't make Don Clugston cringe every time he has to type it. What about method signatures that want 'this' to be an 'in' param. Trailing 'in' like C++? void aMethod() in { writefln(x, toString); }

Assuming they haven't changed, this would break pre-conditions.
 Seems a little strange but I'm sure I'd get used to it.
 I guess const would mean the same thing, though, since 'this' is already 
 final and scope doesn't really apply.
 
 --bb

Since this may have its uses, and so long as the meaning is very clear, I could live with 'const' in that position. -- Chris Nicholson-Sauls
May 17 2007
prev sibling next sibling parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Walter Bright wrote:
 This is coming for the D 2.0 beta, and it will need some source code 
 changes. Specifically, for function parameters that are arrays or 
 pointers, start using 'in' for them.
 
 'in' will mean 'scope const final', which means:
 
 final - the parameter will not be reassigned within the function
 const - the function will not attempt to change the contents of what is 
 referred to
 scope - the function will not keep a reference to the parameter's data 
 that will persist beyond the scope of the function
 
 For example:
 
 int[] g;
 
 void foo(in int[] a)
 {
     a = [1,2];    // error, a is final
     a[1] = 2;   // error, a is const
     g = a;    // error, a is scope
 }
 
 Do not use 'in' if you wish to do any of these operations on a 
 parameter. Using 'in' has no useful effect on D 1.0 code, so it'll be 
 backwards compatible.
 
 Adding in all those 'in's is tedious, as I'm finding out :-(, but I 
 think the results will be worth the effort.

Sounds good to me. How soon can we expect 2.0beta? -- Chris Nicholson-Sauls
May 17 2007
prev sibling next sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Walter Bright wrote

 scope - the function will not keep a reference to the parameter's
 data that will persist beyond the scope of the function

     g = a;	// error, a is scope

In this example the function assigns to a variable living outside of the scope of the function. Therefore the function does not keep that reference itself---and that rule should not fire. In addition: if the rule's wording is changed to match that example, then it becomes unclear, whether `writefln( &a)' is allowed because `writefln' might store that reference somewhere---especially via OS in a file, which might be read in later by the calling process. In case of disallowance that rule would disallow printing too. -manfred
May 17 2007
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Manfred Nowak wrote:
 Walter Bright wrote
 
 scope - the function will not keep a reference to the parameter's
 data that will persist beyond the scope of the function

     g = a;	// error, a is scope

In this example the function assigns to a variable living outside of the scope of the function. Therefore the function does not keep that reference itself---and that rule should not fire.

Since it's storing a reference that will "persist beyond the scope of the function", it's illegal.
 In addition: if the rule's wording is changed to match that example, 
 then it becomes unclear, whether `writefln( &a)' is allowed because 
 `writefln' might store that reference somewhere---especially via OS in 
 a file, which might be read in later by the calling process.
 
 In case of disallowance that rule would disallow printing too.

Making copies is allowed.
May 17 2007
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Walter Bright wrote
 Making copies is allowed.

A copy of a reference is not the reference itself? Then `g = a;' does not make a copy of the adress contained in `a'? WHat does it do then? -manfred
May 18 2007
parent reply torhu <fake address.dude> writes:
Manfred Nowak wrote:
 Walter Bright wrote
 Making copies is allowed.

A copy of a reference is not the reference itself? Then `g = a;' does not make a copy of the adress contained in `a'?

It does make a copy, but if g is 'scope', you're only allowed to have local copies of a. This would be fine: int[] b = a;
 
 WHat does it do then?
 
 -manfred

May 18 2007
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
torhu wrote

 It does make a copy, but if g is 'scope', you're only allowed to
 have local copies of a.
 
 This would be fine:
 
 int[] b = a;

I understand this exactly as you say it: only local copies are allowed! But `writef( &b);' as well as `writef( &a);' may create global copies, i.e. at least not local copies. If this holds, then the scope-rule forbids printing out. But Walter responds with "Making copies is allowed." Which seems to mean, that global copies are allowed by printing out---or his remark has nothing to do with the problem stated. How to resolve this contradiction? -manfred
May 18 2007
parent reply torhu <fake address.dude> writes:
Manfred Nowak wrote:
 torhu wrote
 
 It does make a copy, but if g is 'scope', you're only allowed to
 have local copies of a.
 
 This would be fine:
 
 int[] b = a;

I understand this exactly as you say it: only local copies are allowed! But `writef( &b);' as well as `writef( &a);' may create global copies, i.e. at least not local copies. If this holds, then the scope-rule forbids printing out. But Walter responds with "Making copies is allowed." Which seems to mean, that global copies are allowed by printing out---or his remark has nothing to do with the problem stated. How to resolve this contradiction?

It's not a contradiction. Only references that are actually inside your application are relevant for this rule.
May 18 2007
parent Manfred Nowak <svv1999 hotmail.com> writes:
torhu wrote

 It's not a contradiction.  Only references that are actually
 inside your application are relevant for this rule.

Very true. If one restricts the application to local copies, then the rule cannot be violated---but then the rule is ineffective also. This seems to shout for a formalization of the scope rule. -manfred
May 20 2007
prev sibling next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Note: I've read the reply where you clarified that this is to allow
static things like string literals to be passed in.

Walter Bright wrote:
 This is coming for the D 2.0 beta, and it will need some source code
 changes. Specifically, for function parameters that are arrays or
 pointers, start using 'in' for them.
 
 'in' will mean 'scope const final', which means:
 
 final - the parameter will not be reassigned within the function
 const - the function will not attempt to change the contents of what is
 referred to
 scope - the function will not keep a reference to the parameter's data
 that will persist beyond the scope of the function
 
 For example:
 
 int[] g;
 
 void foo(in int[] a)
 {
     a = [1,2];    // error, a is final
     a[1] = 2;   // error, a is const
     g = a;    // error, a is scope
 }
 Do not use 'in' if you wish to do any of these operations on a
 parameter. Using 'in' has no useful effect on D 1.0 code, so it'll be
 backwards compatible.

Is final really necessary? I can understand const and scope; but is it really a problem if the function rebinds the argument? I mean, that shouldn't affect the calling code in the slightest, should it? void foo(const scope int[] a) { a = [1,2]; } static bar = [3,4]; foo(bar); assert( bar == [3,4] ); // This should still hold, right? There are a few functions I've written which re-bind the argument as they run; the simplest examples being functions that process strings (effectively, it just loops until there's just an empty slice left). Apart from that, I don't think there's any problems with doing this. Oh well; I'll just have to declare an extra argument. :P
 Adding in all those 'in's is tedious, as I'm finding out :-(, but I
 think the results will be worth the effort.

Actually, I was thinking of doing this anyway so that my argument lists are nice and symmetric (qualifiers on all of them, instead of just ref and out). Now I have an excellent reason to do so other than my pedantic-ness. :) One question: is there a keyword for "normal" arguments--for instance, I know that most variables are "auto" if you don't specify the storage class explicitly. I can't imagine where it would be useful; just curious. At any rate, looks spiffy. -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
May 18 2007
parent Walter Bright <newshound1 digitalmars.com> writes:
Daniel Keep wrote:
 Is final really necessary?

No. It's there because nearly all the time, one won't be rebinding a parameter, so making it easier to be final seems like a good idea.
 I can understand const and scope; but is it
 really a problem if the function rebinds the argument?  I mean, that
 shouldn't affect the calling code in the slightest, should it?

No, it does not affect the caller. Only the callee.
 void foo(const scope int[] a)
 {
     a = [1,2];
 }
 
 static bar = [3,4];
 foo(bar);
 assert( bar == [3,4] ); // This should still hold, right?

Yes.
 There are a few functions I've written which re-bind the argument as
 they run; the simplest examples being functions that process strings
 (effectively, it just loops until there's just an empty slice left).
 
 Apart from that, I don't think there's any problems with doing this.  Oh
 well; I'll just have to declare an extra argument.  :P
 
 Adding in all those 'in's is tedious, as I'm finding out :-(, but I
 think the results will be worth the effort.

Actually, I was thinking of doing this anyway so that my argument lists are nice and symmetric (qualifiers on all of them, instead of just ref and out). Now I have an excellent reason to do so other than my pedantic-ness. :) One question: is there a keyword for "normal" arguments--

No. We could use 'auto' for that, but what's the point <g>.
 for instance, I
 know that most variables are "auto" if you don't specify the storage
 class explicitly.  I can't imagine where it would be useful; just curious.
 
 At any rate, looks spiffy.
 
 	-- Daniel
 

May 18 2007
prev sibling next sibling parent reply Aarti_pl <aarti interia.pl> writes:
Walter Bright pisze:
 This is coming for the D 2.0 beta, and it will need some source code 
 changes. Specifically, for function parameters that are arrays or 
 pointers, start using 'in' for them.
 
 'in' will mean 'scope const final', which means:
 
 final - the parameter will not be reassigned within the function
 const - the function will not attempt to change the contents of what is 
 referred to
 scope - the function will not keep a reference to the parameter's data 
 that will persist beyond the scope of the function
 
 For example:
 
 int[] g;
 
 void foo(in int[] a)
 {
     a = [1,2];    // error, a is final
     a[1] = 2;   // error, a is const
     g = a;    // error, a is scope
 }
 
 Do not use 'in' if you wish to do any of these operations on a 
 parameter. Using 'in' has no useful effect on D 1.0 code, so it'll be 
 backwards compatible.
 
 Adding in all those 'in's is tedious, as I'm finding out :-(, but I 
 think the results will be worth the effort.

I want to ask about something opposite to above example... Will it be possible to pass ownership of object? I mean that when you pass object by reference to function/class/member variable you can still modify this object from outside of function/class. It breaks encapsulation in program. Example: import std.stdio; public class TestX { char[] value; char[] toString() { return value; } } public class TestMain { TestX x; } void main(char[][] args) { TestX parameter = new TestX(); parameter.value = "First assignment"; TestMain tmain = new TestMain(); tmain.x = parameter; parameter.value = "Second assignment"; writefln(tmain.x); } Notice that tmain.x value has changed although I would like just to set once, and have second assignment to parameter illegal... When using setters and getters problem is even more visible.... How to achieve proper behavior with new final/const/invariant/scope?? Regards Marcin Kuszczak (aarti_pl)
May 18 2007
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Aarti_pl wrote:
 I want to ask about something opposite to above example...
 
 Will it be possible to pass ownership of object? I mean that when you
 pass object by reference to function/class/member variable you can still
 modify this object from outside of function/class. It breaks
 encapsulation in program.
 
 Example:
 
 import std.stdio;
 public class TestX {
    char[] value;
    char[] toString() {
        return value;
    }
 }
 public class TestMain {
    TestX x;
 }
 
 void main(char[][] args) {
       TestX parameter = new TestX();
       parameter.value = "First assignment";
 
       TestMain tmain = new TestMain();
       tmain.x = parameter;
 
       parameter.value = "Second assignment";
       writefln(tmain.x);
 }
 
 Notice that tmain.x value has changed although I would like just to set
 once, and have second assignment to parameter illegal... When using
 setters and getters problem is even more visible....
 
 How to achieve proper behavior with new final/const/invariant/scope??
 
 Regards
 Marcin Kuszczak
 (aarti_pl)

I don't think the new const, final & invariant are going to help you any. Basically, you seem to be complaining that reference semantics are... well, reference semantics. That's like complaining that water is wet :P There's a few things I can think of to get the behaviour you want. 1. Use a write-once setter for 'value'. You can either create a nullable template, or use a flag to ensure external code can only set it once. 1.a. A "nicer" approach would be to set it in the constructor, and then either mark it "final" (with the new final), or only write a public getter function. 2. Use a struct instead; no references, no indirect changes. 3. Take a private copy of the object by writing a .dup method. -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
May 18 2007
parent reply Aarti_pl <aarti interia.pl> writes:
Daniel Keep pisze:
 
 Aarti_pl wrote:
 I want to ask about something opposite to above example...

 Will it be possible to pass ownership of object? I mean that when you
 pass object by reference to function/class/member variable you can still
 modify this object from outside of function/class. It breaks
 encapsulation in program.

 Example:

 import std.stdio;
 public class TestX {
    char[] value;
    char[] toString() {
        return value;
    }
 }
 public class TestMain {
    TestX x;
 }

 void main(char[][] args) {
       TestX parameter = new TestX();
       parameter.value = "First assignment";

       TestMain tmain = new TestMain();
       tmain.x = parameter;

       parameter.value = "Second assignment";
       writefln(tmain.x);
 }

 Notice that tmain.x value has changed although I would like just to set
 once, and have second assignment to parameter illegal... When using
 setters and getters problem is even more visible....

 How to achieve proper behavior with new final/const/invariant/scope??

 Regards
 Marcin Kuszczak
 (aarti_pl)

I don't think the new const, final & invariant are going to help you any. Basically, you seem to be complaining that reference semantics are... well, reference semantics. That's like complaining that water is wet :P

The problem here is that current behavior breaks encapsulation - you can change already passed value from outside of object, when contract is that you can set it only with setter. Imagine consequences in multithreaded application, when in the middle of function your data suddenly change... But also with single threaded application it can be real problem when you change referenced object by mistake. So it is more like complaining that water is dry when it should be wet in fact :-) I know that other languages also have same problem, but I think that D can do better.
 There's a few things I can think of to get the behaviour you want.
 
 1. Use a write-once setter for 'value'.  You can either create a
 nullable template, or use a flag to ensure external code can only set it
 once.
 

Could you please give example? I don't know how to achieve this behavior with this method...
 1.a. A "nicer" approach would be to set it in the constructor, and then
 either mark it "final" (with the new final), 
 or only write a public getter function.

I think that rather invariant? Final will not disallow changing of referenced object. And I am afraid that it won't help anyway, it would be still possible to change value from outside... Using only getter and passing reference in constructor also doesn't help. You can still also modify variable from outside...
 
 2. Use a struct instead; no references, no indirect changes.
 

Ok. I didn't think about it. But it is basically same as below, so please see comment below. Probably you have also problem when struct has references inside...
 3. Take a private copy of the object by writing a .dup method.
 

Yes that is possible solution, but program would be much faster (no unnecessary copies) with other solution...
 	-- Daniel
 

BR Marcin Kuszczak (aarti_pl)
May 18 2007
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Aarti_pl wrote:
 Daniel Keep pisze:
 Aarti_pl wrote:
 I want to ask about something opposite to above example...

 Will it be possible to pass ownership of object? I mean that when you
 pass object by reference to function/class/member variable you can still
 modify this object from outside of function/class. It breaks
 encapsulation in program.

 Example:

 import std.stdio;
 public class TestX {
    char[] value;
    char[] toString() {
        return value;
    }
 }
 public class TestMain {
    TestX x;
 }

 void main(char[][] args) {
       TestX parameter = new TestX();
       parameter.value = "First assignment";

       TestMain tmain = new TestMain();
       tmain.x = parameter;

       parameter.value = "Second assignment";
       writefln(tmain.x);
 }

 Notice that tmain.x value has changed although I would like just to set
 once, and have second assignment to parameter illegal... When using
 setters and getters problem is even more visible....

 How to achieve proper behavior with new final/const/invariant/scope??

 Regards
 Marcin Kuszczak
 (aarti_pl)

I don't think the new const, final & invariant are going to help you any. Basically, you seem to be complaining that reference semantics are... well, reference semantics. That's like complaining that water is wet :P

The problem here is that current behavior breaks encapsulation - you can change already passed value from outside of object, when contract is that you can set it only with setter. Imagine consequences in multithreaded application, when in the middle of function your data suddenly change... But also with single threaded application it can be real problem when you change referenced object by mistake. So it is more like complaining that water is dry when it should be wet in fact :-) I know that other languages also have same problem, but I think that D can do better.

Ok: so the problem is that because D's class system doesn't have a concept of ownership, encapsulation can be violated. That said, I've never seen an OO language that *did* have a concept of ownership, so I don't know what we could do to "fix" it :P
 There's a few things I can think of to get the behaviour you want.

 1. Use a write-once setter for 'value'.  You can either create a
 nullable template, or use a flag to ensure external code can only set it
 once.

Could you please give example? I don't know how to achieve this behavior with this method...

class TestX { private { char[] _value; bool _value_set = false; } char[] value(char[] v) { if( _value_set ) assert(false, "cannot set value more than once!"); _value = v; _value_set = true; return v; } char[] value() { return _value; } }
 1.a. A "nicer" approach would be to set it in the constructor, and then
 either mark it "final" (with the new final), or only write a public
 getter function.

I think that rather invariant? Final will not disallow changing of referenced object. And I am afraid that it won't help anyway, it would be still possible to change value from outside... Using only getter and passing reference in constructor also doesn't help. You can still also modify variable from outside...

Since D2.0 hasn't been released yet, I don't know for certain, but I would hope it would be possible to create a final invariant member. In this case, you can assign to it *only* during the constructor, and you can only assign something to it which will never change. But then, I'm not sure if that would really work or not.
 2. Use a struct instead; no references, no indirect changes.

Ok. I didn't think about it. But it is basically same as below, so please see comment below. Probably you have also problem when struct has references inside...

Mmm.
 3. Take a private copy of the object by writing a .dup method.

Yes that is possible solution, but program would be much faster (no unnecessary copies) with other solution...
     -- Daniel

BR Marcin Kuszczak (aarti_pl)

Here's another idea I had. This *might* work come D2.0 (but again, I don't know for certain). The idea here is that if we are passed a possibly mutable value, we take a private copy of it since this is the only way we can ensure no one else can mutate it. BUT, if we are passed an invariant string, we just take a reference since the compiler is effectively guaranteeing that its contents will never, ever change. Incidentally, I'm also assuming the whole "casting to const" thing works. class TestX { private { char[] _value; } // Copy v: no external mutations! char[] value(char[] v) { _value = v.dup; return v; } // Invariant, so a reference to it is fine char[] value(invariant char[] v) { _value = v; return v; } // Return const: no one calling this can modify it, even though they // have a reference! const char[] value() { return cast(const char[])_value; } } So maybe you will be able to get what you want. Will be interesting to find out :) -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
May 18 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Daniel Keep wrote:
     // Invariant, so a reference to it is fine
     char[] value(invariant char[] v)
     {
         _value = v;
         return v;
     }

But a mutable reference to it shouldn't be fine. So IMHO this should fail because you're trying to return an invariant char[] as a mutable char[]...
     // Return const: no one calling this can modify it, even though they
     // have a reference!
     const char[] value()
     {
         return cast(const char[])_value;
     }

I think that explicit cast should be unneeded. Mutable to const should be possible through an implicit cast..
May 18 2007
parent Daniel Keep <daniel.keep.lists gmail.com> writes:
Frits van Bommel wrote:
 Daniel Keep wrote:
     // Invariant, so a reference to it is fine
     char[] value(invariant char[] v)
     {
         _value = v;
         return v;
     }

But a mutable reference to it shouldn't be fine. So IMHO this should fail because you're trying to return an invariant char[] as a mutable char[]...

*grumbles* Fine, Mr. Pick On My Mistakes...
 invariant char[] value(invariant char[] v)
 {
     _value = v;
     return v;
 }

There, all better now? :) -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
May 18 2007
prev sibling next sibling parent reply Don Clugston <dac nospam.com.au> writes:
Walter Bright wrote:
 This is coming for the D 2.0 beta, and it will need some source code 
 changes. Specifically, for function parameters that are arrays or 
 pointers, start using 'in' for them.
 
 'in' will mean 'scope const final', which means:
 
 final - the parameter will not be reassigned within the function
 const - the function will not attempt to change the contents of what is 
 referred to
 scope - the function will not keep a reference to the parameter's data 
 that will persist beyond the scope of the function

Looks great, although somewhat overwhelming for a newcomer. Will functions be overloadable on all of these? Anyway, it sounds as though we'll see 2.0 beta 1 before DMD 1.15 ?
May 18 2007
parent Walter Bright <newshound1 digitalmars.com> writes:
Don Clugston wrote:
 Walter Bright wrote:
 final - the parameter will not be reassigned within the function
 const - the function will not attempt to change the contents of what 
 is referred to
 scope - the function will not keep a reference to the parameter's data 
 that will persist beyond the scope of the function

Looks great, although somewhat overwhelming for a newcomer. Will functions be overloadable on all of these?

Just for const.
 Anyway, it sounds as though we'll see 2.0 beta 1 before DMD 1.15 ?

Probably <g>.
May 18 2007
prev sibling next sibling parent reply torhu <fake address.dude> writes:
Walter Bright wrote:
 This is coming for the D 2.0 beta, and it will need some source code 
 changes. Specifically, for function parameters that are arrays or 
 pointers, start using 'in' for them.
 
 'in' will mean 'scope const final', which means:
 
 final - the parameter will not be reassigned within the function
 const - the function will not attempt to change the contents of what is 
 referred to
 scope - the function will not keep a reference to the parameter's data 
 that will persist beyond the scope of the function
 
 For example:
 
 int[] g;
 
 void foo(in int[] a)
 {
      a = [1,2];	// error, a is final
      a[1] = 2;   // error, a is const
      g = a;	// error, a is scope
 }
 
 Do not use 'in' if you wish to do any of these operations on a 
 parameter. Using 'in' has no useful effect on D 1.0 code, so it'll be 
 backwards compatible.
 
 Adding in all those 'in's is tedious, as I'm finding out :-(, but I 
 think the results will be worth the effort.

If you've got a C library with a header file containing this: // C header file void f(const char* p); Is there any reason why you should think twice before turning it into this D code, and link it with the C library, not knowing anything about the implementation of f? // D import module extern (C) void f(in char* p); Without reading the docs for f, would it be better to just go with 'const'? In that case it won't be backwards compatible with D 1.0 anymore. If I get the meaning of 'scope' correctly, that's the one that can cause problems here.
May 20 2007
parent Walter Bright <newshound1 digitalmars.com> writes:
torhu wrote:
 If you've got a C library with a header file containing this:
 
 // C header file
 void f(const char* p);
 
 Is there any reason why you should think twice before turning it into 
 this D code, and link it with the C library, not knowing anything about 
 the implementation of f?
 
 // D import module
 extern (C) void f(in char* p);
 
 
 Without reading the docs for f, would it be better to just go with 
 'const'?  In that case it won't be backwards compatible with D 1.0 
 anymore.  If I get the meaning of 'scope' correctly, that's the one that 
 can cause problems here.

I'd go with: f(const char* p); because that expresses the C semantics. Using 'in' will cause problems if f() stores p somewhere.
May 20 2007
prev sibling next sibling parent janderson <askme me.com> writes:
Perhaps we need a D2.0.learn newsgroup?  Would we also need to make 2.0 
of the others?

-Joel
May 20 2007
prev sibling next sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
I've only now been able to read this thread, so, just some simple questions:

Walter Bright wrote:
 This is coming for the D 2.0 beta, and it will need some source code 
 changes. Specifically, for function parameters that are arrays or 
 pointers, start using 'in' for them.
 
 'in' will mean 'scope const final', which means:
 
 final - the parameter will not be reassigned within the function
 const - the function will not attempt to change the contents of what is 
 referred to
 scope - the function will not keep a reference to the parameter's data 
 that will persist beyond the scope of the function
 

Does this mean you have finished a working design for const/final/invariant/etc. ? If so, then what is the type of fooptr here? : final foo; auto fooptr = &foo;
 For example:
 
 int[] g;
 
 void foo(in int[] a)
 {
     a = [1,2];    // error, a is final
     a[1] = 2;   // error, a is const
     g = a;    // error, a is scope
 }
 
 Do not use 'in' if you wish to do any of these operations on a 
 parameter. Using 'in' has no useful effect on D 1.0 code, so it'll be 
 backwards compatible.
 
 Adding in all those 'in's is tedious, as I'm finding out :-(, but I 
 think the results will be worth the effort.

Whoa there, that idea of 'scope' being the default togheter with 'const' and 'final', where did that came from? I understand why (and agree) that 'final' and 'const' should be the default type modifiers for function parameters, but why 'scope' as well? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
May 26 2007
parent Walter Bright <newshound1 digitalmars.com> writes:
Bruno Medeiros wrote:
 Whoa there, that idea of 'scope' being the default togheter with 'const' 
 and 'final', where did that came from? I understand why (and agree) that 
 'final' and 'const' should be the default type modifiers for function 
 parameters, but why 'scope' as well?

Because most function parameters are scope already.
Jun 04 2007
prev sibling parent reply Charlie <charlie.fats gmail.com> writes:
I'm appalled, both that this is pretty much assured to be in D , and 
that the community seems to be behind it.  I thought that the reason 
Walter didn't want const was because of its added complexity , so 
instead he introduces _3_ new keywords ?  Does no one else feel like 
this is using a machine gun to kill a fly ?

I understand the need for immutable data when writing libraries, but 
'scope const final MyClass myInstance' ?!?  Theres got to be a better way.

I know this sounds over-dramatic, but if this is the direction D is 
headed, then count me out.  I loved D because if its elegant and 
powerful simplicity, I think D has strayed way to far from its original 
goal.

If anyone feels like _this_ implementation for const ( not the 
usefulness of const mind you ) is not for D, then please speak up or we 
all might end up losing our favorite language.

Charlie

Walter Bright wrote:
 This is coming for the D 2.0 beta, and it will need some source code 
 changes. Specifically, for function parameters that are arrays or 
 pointers, start using 'in' for them.
 
 'in' will mean 'scope const final', which means:
 
 final - the parameter will not be reassigned within the function
 const - the function will not attempt to change the contents of what is 
 referred to
 scope - the function will not keep a reference to the parameter's data 
 that will persist beyond the scope of the function
 
 For example:
 
 int[] g;
 
 void foo(in int[] a)
 {
     a = [1,2];    // error, a is final
     a[1] = 2;   // error, a is const
     g = a;    // error, a is scope
 }
 
 Do not use 'in' if you wish to do any of these operations on a 
 parameter. Using 'in' has no useful effect on D 1.0 code, so it'll be 
 backwards compatible.
 
 Adding in all those 'in's is tedious, as I'm finding out :-(, but I 
 think the results will be worth the effort.

Jun 04 2007
next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Charlie" <charlie.fats gmail.com> wrote in message 
news:46649DD9.1010801 gmail.com...
 I'm appalled, both that this is pretty much assured to be in D , and that 
 the community seems to be behind it.  I thought that the reason Walter 
 didn't want const was because of its added complexity , so instead he 
 introduces _3_ new keywords ?  Does no one else feel like this is using a 
 machine gun to kill a fly ?

 I understand the need for immutable data when writing libraries, but 
 'scope const final MyClass myInstance' ?!?  Theres got to be a better way.

 I know this sounds over-dramatic, but if this is the direction D is 
 headed, then count me out.  I loved D because if its elegant and powerful 
 simplicity, I think D has strayed way to far from its original goal.

 If anyone feels like _this_ implementation for const ( not the usefulness 
 of const mind you ) is not for D, then please speak up or we all might end 
 up losing our favorite language.

I was beginning to think I was the only one. It doesn't seem any easier than the C++ style const-ness at all. If anything it's more complex. Instead of "here a const, there a const, everywhere a const * const" it seems like it'll be "here a const, there a final, everywhere an invariant scope int[new]" :P
Jun 04 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Jarrett Billingsley wrote:
 "Charlie" <charlie.fats gmail.com> wrote in message 
 news:46649DD9.1010801 gmail.com...
 I'm appalled, both that this is pretty much assured to be in D , and that 
 the community seems to be behind it.  I thought that the reason Walter 
 didn't want const was because of its added complexity , so instead he 
 introduces _3_ new keywords ?  Does no one else feel like this is using a 
 machine gun to kill a fly ?

 I understand the need for immutable data when writing libraries, but 
 'scope const final MyClass myInstance' ?!?  Theres got to be a better way.

 I know this sounds over-dramatic, but if this is the direction D is 
 headed, then count me out.  I loved D because if its elegant and powerful 
 simplicity, I think D has strayed way to far from its original goal.

 If anyone feels like _this_ implementation for const ( not the usefulness 
 of const mind you ) is not for D, then please speak up or we all might end 
 up losing our favorite language.

I was beginning to think I was the only one. It doesn't seem any easier than the C++ style const-ness at all. If anything it's more complex. Instead of "here a const, there a const, everywhere a const * const" it seems like it'll be "here a const, there a final, everywhere an invariant scope int[new]" :P

I think we should wait and see how it comes out. Of course expressing your doubts and misgivings is a good thing too, but, yeh, let's try not to be over-dramatic. Naturally the discussion here tends to revolve around the cases that aren't obvious or straightforward, because the obvious, easy cases need no discussion. So it's natural that it ends up sounding like "everywhere an invariant scope int[new]", but I suspect in typical code such things will be uncommon. I'm not sure about this int[*] thing though. That will probably require a lot of changes whether int[*] ends up meaning resizeable or not. But come on, you have to admit that slices are a little dicey, and giving the compiler a way to detect bogus usage of a slice will be good. They're supposed to be a safer alternative to naked pointers, but instead they introduce their own equivalently dangerous set of gotchas due to the ambiguity of ownership. Other than that, I think pretty much all of the changes Walter has mentioned will be ignorable. --bb
Jun 04 2007
parent Dave <Dave_member pathlink.com> writes:
Bill Baxter wrote:
 Jarrett Billingsley wrote:
 "Charlie" <charlie.fats gmail.com> wrote in message 
 news:46649DD9.1010801 gmail.com...
 I'm appalled, both that this is pretty much assured to be in D , and 
 that the community seems to be behind it.  I thought that the reason 
 Walter didn't want const was because of its added complexity , so 
 instead he introduces _3_ new keywords ?  Does no one else feel like 
 this is using a machine gun to kill a fly ?

 I understand the need for immutable data when writing libraries, but 
 'scope const final MyClass myInstance' ?!?  Theres got to be a better 
 way.

 I know this sounds over-dramatic, but if this is the direction D is 
 headed, then count me out.  I loved D because if its elegant and 
 powerful simplicity, I think D has strayed way to far from its 
 original goal.

 If anyone feels like _this_ implementation for const ( not the 
 usefulness of const mind you ) is not for D, then please speak up or 
 we all might end up losing our favorite language.

I was beginning to think I was the only one. It doesn't seem any easier than the C++ style const-ness at all. If anything it's more complex. Instead of "here a const, there a const, everywhere a const * const" it seems like it'll be "here a const, there a final, everywhere an invariant scope int[new]" :P

I think we should wait and see how it comes out. Of course expressing your doubts and misgivings is a good thing too, but, yeh, let's try not to be over-dramatic. Naturally the discussion here tends to revolve around the cases that aren't obvious or straightforward, because the obvious, easy cases need no discussion. So it's natural that it ends up sounding like "everywhere an invariant scope int[new]", but I suspect in typical code such things will be uncommon.

Recalling the resistance that Walter originally had to adding const (the 'loose' semantics of C++ const and the concern about "littering" D code w/ const), I too think it will be wise to see what Walter has come up with. I'm pretty confident it will be both better and less onerous than C++ const for a majority of situations given the quality of design (of D) in other areas.
 I'm not sure about this int[*] thing though. That will probably require 
 a lot of changes whether int[*] ends up meaning resizeable or not.  But 
 come on, you have to admit that slices are a little dicey, and giving 
 the compiler a way to detect bogus usage of a slice will be good. 
 They're supposed to be a safer alternative to naked pointers, but 
 instead they introduce their own equivalently dangerous set of gotchas 
 due to the ambiguity of ownership.
 
 Other than that, I think pretty much all of the changes Walter has 
 mentioned will be ignorable.
 
 --bb

Jun 04 2007
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Charlie wrote:
 I'm appalled, both that this is pretty much assured to be in D , and 
 that the community seems to be behind it.  I thought that the reason 
 Walter didn't want const was because of its added complexity , so 
 instead he introduces _3_ new keywords ?  Does no one else feel like 
 this is using a machine gun to kill a fly ?
 
 I understand the need for immutable data when writing libraries, but 
 'scope const final MyClass myInstance' ?!?  Theres got to be a better way.
 
 I know this sounds over-dramatic, but if this is the direction D is 
 headed, then count me out.  I loved D because if its elegant and 
 powerful simplicity, I think D has strayed way to far from its original 
 goal.
 
 If anyone feels like _this_ implementation for const ( not the 
 usefulness of const mind you ) is not for D, then please speak up or we 
 all might end up losing our favorite language.

Actually, I quite empathize with your viewpoint. I worry that the final, const, invariant thing is too complicated. But there are some mitigating factors: 1) Just as in C++, you can pretty much ignore final, const, and invariant if they don't appeal to you. I don't bother using const in my C++ code. 2) The transitive nature of const means that there are a lot fewer const's you have to write. 3) Using D's type inference capability, a lot fewer types (and their attendant const's) need to be written. 4) It provides information that is actually useful to the compiler. 5) Scope has the promise of enabling reference counting to be far more efficient than is possible in C++. 6) Working together, these features move us towards supporting the functional programming paradigm better. FP is very important for the future, as it is very adaptable to parallel programming. 7) They make interfaces much more self-documenting. 8) They can make automated code analysis tools more effective. Automated code analysis is big business and is getting to be far more important as security consultants are brought in to analyze code for correctness, security, etc. Wall Street in particular is very interested in this stuff. 9) So far, in my work to make Phobos const-correct, it hasn't been the annoyance I thought it would be.
Jun 04 2007