June 25, 2008
Steven Schveighoffer Wrote:

> "Jason House" wrote
> > A lot of times, when I think about tail const/mixed const/mutable/..., I
> > start thinking about arrays.
> > AKA:
> >  T[] vs. array!(T)
> >  const(T)[] vs. array!(const(T)) vs. const!(element)(array!(T))

I probably should have stated that arrays have special status in D.  As built in containers, they have support for for tail const while other objects don't have that luxury.  I implicitly measure the quality of a const proposal by how it can implement an alternate to arrays without the syntactic sugar arrays provide.


> or const!(element)(T)[]
> 
> or
> 
> alias const!(element) eleconst;
> 
> eleconst(T)[]

What's the difference between const!(element)(T)[] and const(T)[]?  I believe this is more a misunderstanding of what I was driving at.  Consider this template:

class array(T){
  typedef element T elem;
  elem contents[];
}

Maybe I got the syntax wrong, but the basic idea is that T and element are really the same kind of thing.  array!(const T) and const!(element)(array!(T)) are different types.  Should they be?  I don't think so.  There's still something buried in a tail const scheme that still needs to get fleshed out, somehow...
June 25, 2008
"Jason House" wrote
> Steven Schveighoffer Wrote:
>
>> "Jason House" wrote
>> > A lot of times, when I think about tail const/mixed const/mutable/...,
>> > I
>> > start thinking about arrays.
>> > AKA:
>> >  T[] vs. array!(T)
>> >  const(T)[] vs. array!(const(T)) vs. const!(element)(array!(T))
>
> I probably should have stated that arrays have special status in D.  As built in containers, they have support for for tail const while other objects don't have that luxury.  I implicitly measure the quality of a const proposal by how it can implement an alternate to arrays without the syntactic sugar arrays provide.

Ah, I now understand what you meant.  Yes, it can be done, just like you say.

const alias element;

class array(T){
   typedef element(T) elem;
   elem[] contents; // same as elem contents[] I think
}

the tag is not in itself const.  It is a noop when not selected for const/invariant.

So array!(T) becomes:

{
   typedef T elem;
   elem[] contents;
}

And const!(element)(array!(T)) becomes:

{
   typedef const(T) elem;
   elem[] contents;  // which is now const(T)[]
}

>> or const!(element)(T)[]
>>
>> or
>>
>> alias const!(element) eleconst;
>>
>> eleconst(T)[]
>
> What's the difference between const!(element)(T)[] and const(T)[]?  I believe this is more a misunderstanding of what I was driving at.

Yes, I misunderstood you.  const!(element)(T)[] and const(T)[] are different depending on what T is.  If T is a struct:

struct T
{
   element int x;
   int y;
}

Then const(T) yields:

{
   const int x;
   const int y;
}

and const!(element)(T) yields:

{
   const int x;
   int y;
}

>  Consider this template:
>
> class array(T){
>  typedef element T elem;
>  elem contents[];
> }
>
> Maybe I got the syntax wrong, but the basic idea is that T and element are really the same kind of thing.  array!(const T) and const!(element)(array!(T)) are different types.  Should they be?  I don't think so.  There's still something buried in a tail const scheme that still needs to get fleshed out, somehow...

Tail const is much more possible with the const scheme I outlined.  Your example is not really relevant because the entire set of members is marked by a tag.  This is no different than today's const.

Basically, as a simple rough explanation, what I propose allows you to direct const to apply only to certain pieces of a struct or class, instead of always affecting the whole thing.  Tail const is possible because you can tag only the 'pointed to' data and const-ify only that part.

Another aspect is this:

array!(T) and array!(const T) are not implicitly castable, because they are two separate types.  e.g.:

array!(T) t = new array!(T)(5); // array of 5 Ts

const(array!(T)) t2 = t; // ok, t2 is the same type, but with a const modifier.

array!(const T) t3 = t; // error, incompatible types

const!(element)(array!(T)) t4 = t; // ok, because t4 is the same type, but with a const modifier.

-Steve


June 25, 2008
Steven Schveighoffer Wrote:

> "Jason House" wrote
> >  Consider this template:
> >
> > class array(T){
> >  typedef element T elem;
> >  elem contents[];
> > }
> >
> > Maybe I got the syntax wrong, but the basic idea is that T and element are really the same kind of thing.  array!(const T) and const!(element)(array!(T)) are different types.  Should they be?  I don't think so.  There's still something buried in a tail const scheme that still needs to get fleshed out, somehow...
> 
> Tail const is much more possible with the const scheme I outlined.  Your example is not really relevant because the entire set of members is marked by a tag.  This is no different than today's const.

Actually, it is different.  The array is resizable, so not everything inside is constant.  I'm sure using an array inside a class is far less clear for const examples, but I was trying to show the parallels with a simple array.


> Basically, as a simple rough explanation, what I propose allows you to direct const to apply only to certain pieces of a struct or class, instead of always affecting the whole thing.  Tail const is possible because you can tag only the 'pointed to' data and const-ify only that part.
> 
> Another aspect is this:
> 
> array!(T) and array!(const T) are not implicitly castable, because they are two separate types.  e.g.:
> 
> array!(T) t = new array!(T)(5); // array of 5 Ts
> 
> const(array!(T)) t2 = t; // ok, t2 is the same type, but with a const modifier.
> 
> array!(const T) t3 = t; // error, incompatible types
> 
> const!(element)(array!(T)) t4 = t; // ok, because t4 is the same type, but with a const modifier.

That's all true as proposed.  The deeper question is should it be that way?  When should having a const argument as a template parameter result in a whole new type and when should implicit casts to const template parameters be allowed?
June 25, 2008
"Jason House" wrote
> Steven Schveighoffer Wrote:
>
>> "Jason House" wrote
>> >  Consider this template:
>> >
>> > class array(T){
>> >  typedef element T elem;
>> >  elem contents[];
>> > }
>> >
>> > Maybe I got the syntax wrong, but the basic idea is that T and element
>> > are
>> > really the same kind of thing.  array!(const T) and
>> > const!(element)(array!(T)) are different types.  Should they be?  I
>> > don't
>> > think so.  There's still something buried in a tail const scheme that
>> > still needs to get fleshed out, somehow...
>>
>> Tail const is much more possible with the const scheme I outlined.  Your
>> example is not really relevant because the entire set of members is
>> marked
>> by a tag.  This is no different than today's const.
>
> Actually, it is different.  The array is resizable, so not everything inside is constant.  I'm sure using an array inside a class is far less clear for const examples, but I was trying to show the parallels with a simple array.

Yes, I stand corrected.  For your example const(array!(T)) is different than array!(const T).  My mistake.

>> Basically, as a simple rough explanation, what I propose allows you to
>> direct const to apply only to certain pieces of a struct or class,
>> instead
>> of always affecting the whole thing.  Tail const is possible because you
>> can
>> tag only the 'pointed to' data and const-ify only that part.
>>
>> Another aspect is this:
>>
>> array!(T) and array!(const T) are not implicitly castable, because they
>> are
>> two separate types.  e.g.:
>>
>> array!(T) t = new array!(T)(5); // array of 5 Ts
>>
>> const(array!(T)) t2 = t; // ok, t2 is the same type, but with a const
>> modifier.
>>
>> array!(const T) t3 = t; // error, incompatible types
>>
>> const!(element)(array!(T)) t4 = t; // ok, because t4 is the same type,
>> but
>> with a const modifier.
>
> That's all true as proposed.  The deeper question is should it be that way?  When should having a const argument as a template parameter result in a whole new type and when should implicit casts to const template parameters be allowed?

The problem is that with template compile-time evaluation, one can construct a completely different template for const T than for T.  With the generic const proposal, you cannot do this, as there is no generated type based on whether something is const or not.  The compiler would have to disallow this kind of thing, or else have a special way to identify the constancy as not varying the template generated.  But I much prefer not dealing with templates at all.

If there is a simpler way to do it, then I'm all for that.

-Steve


June 26, 2008
Walter Bright wrote:

Perl has invariant strings, but they are implicitly invariant
> and so nobody notices it, they just work.
> 
Sorry Walter, but thta is simply not the case: Vis:

[0] Perl> $x = 'x' x 500e6;
[0] Perl> print length $x;;
500000000
[0] Perl> substr $x, 250e6, 1, 'y';;
[0] Perl> print length $x;;
500000000
[0] Perl> print substr $x, 250e6-5, 10;;
xxxxxyxxxx

b.
-- 

June 26, 2008
Me Here wrote:
> Walter Bright wrote:
> 
> Perl has invariant strings, but they are implicitly invariant
>> and so nobody notices it, they just work.
>>
> Sorry Walter, but thta is simply not the case: Vis:
> 
> [0] Perl> $x = 'x' x 500e6;
> [0] Perl> print length $x;;
> 500000000
> [0] Perl> substr $x, 250e6, 1, 'y';;
> [0] Perl> print length $x;;
> 500000000
> [0] Perl> print substr $x, 250e6-5, 10;;
> xxxxxyxxxx
> 
> b.

What are you disagreeing with?

The fact that they're invariant?
Or the fact that nobody notices?

I have no idea if they're invariant in perl or not.  But I don't think your test above is conclusive proof that they're mutable.

--bb
June 26, 2008
"Bill Baxter" wrote
> Me Here wrote:
>> Walter Bright wrote:
>>
>> Perl has invariant strings, but they are implicitly invariant
>>> and so nobody notices it, they just work.
>>>
>> Sorry Walter, but thta is simply not the case: Vis:
>>
>> [0] Perl> $x = 'x' x 500e6;
>> [0] Perl> print length $x;;
>> 500000000
>> [0] Perl> substr $x, 250e6, 1, 'y';;
>> [0] Perl> print length $x;;
>> 500000000
>> [0] Perl> print substr $x, 250e6-5, 10;;
>> xxxxxyxxxx
>>
>> b.
>
> What are you disagreeing with?
>
> The fact that they're invariant?
> Or the fact that nobody notices?
>
> I have no idea if they're invariant in perl or not.  But I don't think your test above is conclusive proof that they're mutable.

No it's not.  The only conclusive proof comes from observing what happens when you copy strings from one to the other:

#!/usr/bin/perl

print "before x\n";
sleep 20;
$x = 'x' x 100000000;
print "initialized x\n";
sleep 5;
$y = $x;
print "copied to y\n";
sleep 5;
substr $x, 3, 1, 'y';
print "did substring\n";
print substr $y, 0, 5;
print "\n";
sleep 5;

OK, so what does this do?  I set x to a string of 100 million x's, then assign x to y, then replace the 4th character in x with a 'y', then print the first 5 characters of y to see if they changed too (see if x and y reference the same data)

So what does this output?
before x
initialized x
copied to y
did substring
xxxxx

But this is not yet conclusive proof, we need to watch what happens with memory usage when each step occurs (hence the sleeps).  So using 'top', I observed this:

before x => mem usage 3k
initialized x => 191MB (!)
copied to y => 291MB
did substring => 291MB
xxxxx

So, what it looks like is on assignment, the string is copied, and the editing edits the string in-place.   But I can't really explain why it takes 191MB to store x, where it only takes 100MB to store y.

So I'd say perl does not have invariant strings.  'course, I'm not a perl hacker, so I don't know if I did this correctly :)

-Steve


June 26, 2008
Steven Schveighoffer Wrote:

> 
> "Bill Baxter" wrote
> > Me Here wrote:
> >> Walter Bright wrote:
> >>
> >> Perl has invariant strings, but they are implicitly invariant
> >>> and so nobody notices it, they just work.
> >>>
> >> Sorry Walter, but thta is simply not the case: Vis:
> >>
> >> [0] Perl> $x = 'x' x 500e6;
> >> [0] Perl> print length $x;;
> >> 500000000
> >> [0] Perl> substr $x, 250e6, 1, 'y';;
> >> [0] Perl> print length $x;;
> >> 500000000
> >> [0] Perl> print substr $x, 250e6-5, 10;;
> >> xxxxxyxxxx
> >>
> >> b.
> >
> > What are you disagreeing with?
> >
> > The fact that they're invariant?
> > Or the fact that nobody notices?
> >
> > I have no idea if they're invariant in perl or not.  But I don't think your test above is conclusive proof that they're mutable.
> 
> No it's not.  The only conclusive proof comes from observing what happens when you copy strings from one to the other:
> 
> #!/usr/bin/perl
> 
> print "before x\n";
> sleep 20;
> $x = 'x' x 100000000;
> print "initialized x\n";
> sleep 5;
> $y = $x;
> print "copied to y\n";
> sleep 5;
> substr $x, 3, 1, 'y';
> print "did substring\n";
> print substr $y, 0, 5;
> print "\n";
> sleep 5;
> 
> OK, so what does this do?  I set x to a string of 100 million x's, then assign x to y, then replace the 4th character in x with a 'y', then print the first 5 characters of y to see if they changed too (see if x and y reference the same data)
> 
> So what does this output?
> before x
> initialized x
> copied to y
> did substring
> xxxxx
> 
> But this is not yet conclusive proof, we need to watch what happens with memory usage when each step occurs (hence the sleeps).  So using 'top', I observed this:
> 
> before x => mem usage 3k
> initialized x => 191MB (!)
> copied to y => 291MB
> did substring => 291MB
> xxxxx
> 
> So, what it looks like is on assignment, the string is copied, and the editing edits the string in-place.   But I can't really explain why it takes 191MB to store x, where it only takes 100MB to store y.
> 
> So I'd say perl does not have invariant strings.  'course, I'm not a perl hacker, so I don't know if I did this correctly :)
> 
> -Steve

Hello! I think the first part of your message is correct. the second is maybe mis guided. Walter is correct. Perl strings do not have mutable chars. They can be think as similar to D strings. Your example with $x and $y shows that.

Perl can optimize copies sometimes. But it does not matter. Semantics is all that matters. And Perl strings can not mutate individual chars ever. Thanks, Dee Girl
June 26, 2008
Bill Baxter wrote:

> Me Here wrote:
> > Walter Bright wrote:
> > 
> > Perl has invariant strings, but they are implicitly invariant
> > > and so nobody notices it, they just work.
> > > 
> > Sorry Walter, but thta is simply not the case: Vis:
> > 
> >[0] Perl> $x = 'x' x 500e6;
> >[0] Perl> print length $x;;
> > 500000000
> >[0] Perl> substr $x, 250e6, 1, 'y';;
> >[0] Perl> print length $x;;
> > 500000000
> >[0] Perl> print substr $x, 250e6-5, 10;;
> > xxxxxyxxxx
> > 
> > b.
> 
> What are you disagreeing with?

Simple. Walter's statement that Perl's strings are invarient.

> 
> The fact that they're invariant?
> Or the fact that nobody notices?
> 
> I have no idea if they're invariant in perl or not.  But I don't think your test above is conclusive proof that they're mutable.
> 

True. It is not conclusive proof. That's very hard to provide in a forum such as this.

I *know* the above proves it, because I can monitor the memory usage and
addresses.
I used a very large string and the mutated a character in the middle of it. If
the original string was mutated, the memory consumption of the process would
have to (breifly) double. It does not.

For those familiar with Perl, a simple

    $scalar =~ s[(.)(.)][\2\2]g;

would be sufficient to demonstrate it. This will swap every pair of characters in the string, in place.

Or
    $scalar =~ tr[A-Za-z][a-zA-Z];

which will switch the case of all characters in the string *in-place*.

So, let me make this statement: Perl's SVs are *absolutely not* immutable!

> --bb

What does this mean for the wider discussion? Nothing. But that particular part of Walter's post is incorrect.

b.
-- 

June 26, 2008
Me Here <p9e883002@sneakemail.com> wrote:
> I *know* the above proves it, because I can monitor the memory usage and
> addresses.
> I used a very large string and the mutated a character in the middle of it. If
> the original string was mutated, the memory consumption of the process would
> have to (breifly) double. It does not.

Could not the garbage collector theoretically be intelligent enough to see
that there's only one reference to the string, and thus not do CoW?

-- Simen