Another prayer for invariant strngs

Robert Fraser fraserofthenight at gmail.com
Fri Jul 13 12:25:35 PDT 2007


Oh, didn't see your message. That's awesome, thanks! No, I didn't want the refrences to be final, just the data. Basically, I want to ensure that functions I call won't mess around with my data.

Thanks!
All the best,
Fraser

Regan Heath Wrote:

> (disclaimer, I have done only the testing shown at the end of this post)
> 
> Robert Fraser wrote:
> > Invariant strings have been discussed before (briefly) in discussions
> > of constness, however I wish to bring up the subject again more
> > directly.
> > 
> > The "string" alias as it is now (in D 2.0) is an odd beast. The
> > problem is that it is invariant(char)[] instead of invariant(char[]),
> > so that while the characters themselves are invariant, the array is
> > mutable. 
> 
> This makes sense if you think about it from the compilers point of view.
> 
> It has placed the characters themselves in ROM but the array reference 
> is in RAM so it's pointer and length can change.  So, this is valid:
> 
> invariant(char)[] a = "foo";
> invariant(char)[] b = "bar";
> b = a;
> 
> But these are invalid:
> 
> char[] p;
> 
> a[0] = 'a'; //for any given rvalue
> b[] = a[];  //and slicing variants
> p = a;      //p cannot point to invariant(char)
> 
> If you want to prevent the reference from changing make it 'final', eg.
> 
> final invariant(char)[] a;
> 
>  > This has two main problems:
> > 
> > 1. It's confusing. There have been quite a few topics both in this
> > newsgroup and in digitalmars.D.learn about how exactly to use the 2.0
> > string alias and where it's immutable/where it's not.
> 
> I wont argue as to whether it's confusing, but to me it seems the basic 
> concept is:  "A 'string' reference isn't immutable (or rather 'final'), 
> but it's data is (immutable)".
> 
> > 2. Performance. While writing my own code, I can pretend "string" is
> > invariant (or use my own invariant(char[]) alias), but when passing
> > to, or receiving code from library functions, this is not possible.
> 
> When you pass string to a function that function gets a /copy/ of the 
> reference.  So, there is technically no need for the copied reference to 
> be invariant (or rather 'final').  Changes to the reference in the 
> function *do not* propagate back to the caller.
> 
> Unless, however, the parameter is 'ref'.  In which case changes to the 
> reference propagate back to the caller.  In this case if your reference 
> is final DMD will error, see test case below.
> 
> In short, if you use 'final' on your strings then even if you call a 
> library function which takes a 'ref' the compiler will protect you.
> 
> > This means that in each of these situations I must take two,
> > performance-draining precautionary measures: i. Duplicate the string
> > every time it's passed in or out of my code. ii.Synchronize
> > multithreaded access to strings/acquire locks/etc.
> 
> You do not need to sync access to invariant data, but you may need to 
> sync access to an array reference (if your code, or library code might 
> change it).  To prevent changes make your strings final.
> 
> > Invariant strings have precedent: they're used in Java, .NET, Perl,
> > Python, Ruby and quite a few other languages. And for when multiple
> > string operations are going down, there's always char[] and .idup to
> > fall back on, which are far better than Java's StringBuffer, etc.
> 
> Does Java prevent you re-assigning an invariant string reference?  If 
> so, are they implicitly 'final' then?
> 
> > So, please, Walter... consider Andrei's proposal and make "string" an
> > alias to invariant(char[]). It'll make a lot of happiness happen.
> 
> I think a greater understanding of the current system is required before 
> we start opting for changes.
> 
>   - Regan Heath
> 
> Test cases:
> 
> void main()
> {
> 	invariant(char)[] p1 = "one";
> 	invariant(char[]) p2 = "two";
> 	final invariant(char[]) p3 = "three";
> 	char[] p4 = "four".dup;
> 	const(char)[] p5 = "five";
> 	const(char[]) p6 = "six";
> 
> 	//p1[0] = 'a'; //Error: p1[0] is not mutable
> 	//p2[0] = 'a'; //Error: p2[0] is not mutable
> 	//p3[0] = 'a'; //Error: p3[0] is not mutable
> 	p4[0] = 'a'; //ok
> 	//p5[0] = 'a'; //Error: p5[0] is not mutable
> 	//p6[0] = 'a'; //Error: p6[0] is not mutable
> 	
> 	//p1[] = p2[]; //Error: slice p1[] is not mutable
> 	//p2[] = p1[]; //Error: slice p2[] is not mutable
> 	//p3[] = p1[]; //Error: slice p3[] is not mutable
> 	p4[] = p1[]; //ok
> 	//p5[] = p1[]; //Error: slice p5[] is not mutable
> 	//p6[] = p1[]; //Error: slice p6[] is not mutable
> 	
> 	p1 = p2; //ok
> 	p2 = p1; //ok	
> 	//p3 = p1; //variable invariant.p3 cannot modify final/const/invariant 
> variable 'p3'
> 	//p4 = p1;  //Error: cannot implicitly convert expression (p1) of type 
> invariant(char)[] to char[]
> 	p5 = p1; //ok
> 	p6 = p1; //ok
> 
> 	foo(p3); //variable invariant.main.p3 cannot modify 
> final/const/invariant variable 'p3'
> }
> 
> /*
> void foo(final invariant(char)[] param)
> {
> 	//param = "test";  //variable invariant.foo.param cannot modify 
> final/const/invariant variable 'param'
> }
> */
> 
> void foo(ref invariant(char)[] param)
> {
> 	param = "test";  //variable invariant.foo.param cannot modify 
> final/const/invariant variable 'param'
> }




More information about the Digitalmars-d mailing list