www.digitalmars.com         C & C++   DMDScript  

D - [bug] line number in error message

reply J C Calvarese <jcc7 cox.net> writes:
Walter,

Genn Lewis has pointed out to me that this erroneous code produces an 
error message, but it leaves out the line number. Obviously, it would be 
helpful to new and existing users alike if the offending line number is 
included.


void main()
{	
   char[] s;
   s.length++;    // 's.length' is not an lvalue
}


Thanks.

-- 
Justin
http://jcc_7.tripod.com/d/
Mar 13 2004
parent reply Andrew Edwards <remove_ridimz remove_yahoo.com> writes:
On Sat, 13 Mar 2004 14:57:08 -0600, J C Calvarese <jcc7 cox.net> wrote:

    s.length++;    // 's.length' is not an lvalue
I forget the reason why this is not authorized, but I rationalize it myself. If I can do this: s.length = s.length + 1; s.length = s.length - 1; s.length = 0; Then why on earth wouldn't I be allowed to do this: s.length++; s.length--; s.length += 1; s.length -= 1; [etc...] They are all means to the same end. The .length property is simply a uint variable. As such, it should be able to be modified like any other variable of type uint. Andrew -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Mar 14 2004
next sibling parent reply J C Calvarese <jcc7 cox.net> writes:
Andrew Edwards wrote:
 On Sat, 13 Mar 2004 14:57:08 -0600, J C Calvarese <jcc7 cox.net> wrote:
 
    s.length++;    // 's.length' is not an lvalue
I forget the reason why this is not authorized, but I rationalize it myself.
I know it's not allowed. My purpose for the bug report is to get the line number included in the error message. It'd be helpful for newbies and anyone else who hasn't heard of this little oddity. Of course, if that code could be allowed that would be even better in my opinion. I forget the reason, too, but I know there's a reason.
 
 If I can do this:
 
 s.length = s.length + 1;
 s.length = s.length - 1;
 s.length = 0;
 
 Then why on earth wouldn't I be allowed to do this:
 
 s.length++;
 s.length--;
 s.length += 1;
 s.length -= 1;
 [etc...]
I agree.
 
 They are all means to the same end. The .length property is simply a 
 uint variable. As such, it should be able to be modified like any other 
 variable of type uint.
I think the reason has do with trying to use it in a slice: s[0..s.length++] Unknowable weirdness would happen behind the scenes, I suppose.
 
 Andrew
-- Justin http://jcc_7.tripod.com/d/
Mar 14 2004
parent Andrew Edwards <remove_ridimz remove_yahoo.com> writes:
On Sun, 14 Mar 2004 14:31:11 -0600, J C Calvarese <jcc7 cox.net> wrote:

 Andrew Edwards wrote:
 On Sat, 13 Mar 2004 14:57:08 -0600, J C Calvarese <jcc7 cox.net> wrote:

    s.length++;    // 's.length' is not an lvalue
I forget the reason why this is not authorized, but I rationalize it myself.
I know it's not allowed. My purpose for the bug report is to get the line number included in the error message. It'd be helpful for newbies and anyone else who hasn't heard of this little oddity. Of course, if that code could be allowed that would be even better in my opinion. I forget the reason, too, but I know there's a reason.
 If I can do this:

 s.length = s.length + 1;
 s.length = s.length - 1;
 s.length = 0;

 Then why on earth wouldn't I be allowed to do this:

 s.length++;
 s.length--;
 s.length += 1;
 s.length -= 1;
 [etc...]
I agree.
 They are all means to the same end. The .length property is simply a 
 uint variable. As such, it should be able to be modified like any other 
 variable of type uint.
I think the reason has do with trying to use it in a slice: s[0..s.length++] Unknowable weirdness would happen behind the scenes, I suppose.
This is a special case that can be handled much like the general case is currently handled; simply disallow the use of -- and ++ over slices. I don't know of any other usage that could cause a problem.
 Andrew
-- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Mar 14 2004
prev sibling next sibling parent reply larry cowan <larry_member pathlink.com> writes:
It would seem that this is similar to an overloaded assignment operator which
knows that the corresponding array must be adjusted, whereas the ++ (and others)
operator doesn't know anything about the underlying array - thus its a
non-lvalue which is especially recognized by "=".

In article <opr4vasfyhs6zaqn news.digitalmars.com>, Andrew Edwards says...
On Sat, 13 Mar 2004 14:57:08 -0600, J C Calvarese <jcc7 cox.net> wrote:

    s.length++;    // 's.length' is not an lvalue
I forget the reason why this is not authorized, but I rationalize it myself. If I can do this: s.length = s.length + 1; s.length = s.length - 1; s.length = 0; Then why on earth wouldn't I be allowed to do this: s.length++; s.length--; s.length += 1; s.length -= 1; [etc...] They are all means to the same end. The .length property is simply a uint variable. As such, it should be able to be modified like any other variable of type uint. Andrew -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Mar 14 2004
parent reply Andrew Edwards <remove_ridimz remove_yahoo.com> writes:
On Sun, 14 Mar 2004 20:36:25 +0000 (UTC), larry cowan 
<larry_member pathlink.com> wrote:

 It would seem that this is similar to an overloaded assignment operator 
 which
 knows that the corresponding array must be adjusted, whereas the ++ (and 
 others)
 operator doesn't know anything about the underlying array - thus its a
 non-lvalue which is especially recognized by "=".
.length is a member variable (property) of type uint. the ++ operator already knows how to manipulate it. uint mylength; mylength++; // mylength = 1 mylength--; // mylength = 0 Maybe I'm missing the point, but I'm cannot understand what else the operator needs to know in order to manipulate a variable of integral type (i.e. int, uint, short, etc...).
 In article <opr4vasfyhs6zaqn news.digitalmars.com>, Andrew Edwards 
 says...
 On Sat, 13 Mar 2004 14:57:08 -0600, J C Calvarese <jcc7 cox.net> wrote:

    s.length++;    // 's.length' is not an lvalue
I forget the reason why this is not authorized, but I rationalize it myself. If I can do this: s.length = s.length + 1; s.length = s.length - 1; s.length = 0; Then why on earth wouldn't I be allowed to do this: s.length++; s.length--; s.length += 1; s.length -= 1; [etc...] They are all means to the same end. The .length property is simply a uint variable. As such, it should be able to be modified like any other variable of type uint. Andrew -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
-- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Mar 14 2004
parent reply larry cowan <larry_member pathlink.com> writes:
In article <opr4vdw6lds6zaqn news.digitalmars.com>, Andrew Edwards says...
On Sun, 14 Mar 2004 20:36:25 +0000 (UTC), larry cowan 
<larry_member pathlink.com> wrote:

 It would seem that this is similar to an overloaded assignment operator 
 which
 knows that the corresponding array must be adjusted, whereas the ++ (and 
 others)
 operator doesn't know anything about the underlying array - thus its a
 non-lvalue which is especially recognized by "=".
.length is a member variable (property) of type uint. the ++ operator already knows how to manipulate it.
Why should you be able to directly modify a property of an array? It requires a reset (clip or reallocate) of the array itself, so the operation must be recognized as such. It is just a supplied convenience that assigning a length to a dynamic array is the method of specifying its (max)size. There is no reason why you should be able to use "++" or "--" which are different operations than assignment entirely. Calling it not-an-lvalue means that in the normal case it cannot be used on the left (the "to" operand) of a statement. In this case a value can be assigned to it - which allocates the array - but it cannot be otherwise modified.
uint mylength;
mylength++; // mylength = 1
mylength--; // mylength = 0

Maybe I'm missing the point, but I'm cannot understand what else the 
operator needs to know in order to manipulate a variable of integral type 
(i.e. int, uint, short, etc...).

 In article <opr4vasfyhs6zaqn news.digitalmars.com>, Andrew Edwards 
 says...
 On Sat, 13 Mar 2004 14:57:08 -0600, J C Calvarese <jcc7 cox.net> wrote:

    s.length++;    // 's.length' is not an lvalue
I forget the reason why this is not authorized, but I rationalize it myself. If I can do this: s.length = s.length + 1; s.length = s.length - 1; s.length = 0; Then why on earth wouldn't I be allowed to do this: s.length++; s.length--; s.length += 1; s.length -= 1; [etc...] They are all means to the same end. The .length property is simply a uint variable. As such, it should be able to be modified like any other variable of type uint. Andrew -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
-- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Mar 14 2004
parent reply Andrew Edwards <remove_ridimz remove_yahoo.com> writes:
On Sun, 14 Mar 2004 22:11:55 +0000 (UTC), larry cowan 
<larry_member pathlink.com> wrote:

 In article <opr4vdw6lds6zaqn news.digitalmars.com>, Andrew Edwards 
 says...
 On Sun, 14 Mar 2004 20:36:25 +0000 (UTC), larry cowan
 <larry_member pathlink.com> wrote:

 It would seem that this is similar to an overloaded assignment operator
 which
 knows that the corresponding array must be adjusted, whereas the 
 ++ (and
 others)
 operator doesn't know anything about the underlying array - thus its a
 non-lvalue which is especially recognized by "=".
.length is a member variable (property) of type uint. the ++ operator already knows how to manipulate it.
Why should you be able to directly modify a property of an array? It
The terms "directly modify" appears to mean two completely different things for you and I. In my mind, to direct modify a variable is to explicitly change its value. This means that: s.length = 10; s.length++; are both means of "directly" affecting change to the value of length. My position is that if this form (first example) of "direct modification" is authorized, then why not allow all other forms of direct modification? Why allow some forms and prevent others? If we are not change some something "directly", then make it so. I'm quite positive that the .length property can be defined to grow and shrink dinamically (as is already the case). As a matter of fact, I personally favor a dynamic array (i.e. char[], int[], unit[], etc...) whose length property can only be implicitly modified by assigning a value larger/smaller than its current value or explicitly decreased with with --; Examples: char[] str; // str.length = 0 str = "information" // str.length = 11, str = "information" str = str[2..str.length]; // str.length = 9, str = "formation" str.length++; // illegal str.length = 10; // illegal str.length--; // str.length = 8, str = "formatio" str = ""; // OK, str.length = 0 This can prove quite helpful with implementing a stack or queue. class stack { char[][] stackmember; void push(char[] str){stackmember ~= str;} void pop(){stackmember--;} // LIFO ... } class queue { char[][] queuemember; void enqueue(char[] str){queuemember = str ~ queuemember;} void dequeue(){queuemember--}; // FIFO ... } Apart from these, I find little reasons to directly modify the length of a dynamic array. I find absolutely no reason for explicitly lengthen a dynamic array. Maybe someone else can provide an argument in favor of (I personally am against) it.
 requires
 a reset (clip or reallocate) of the array itself, so the operation must 
 be
 recognized as such.  It is just a supplied convenience that assigning a 
 length
 to a dynamic array is the method of specifying its (max)size.  There is 
 no
 reason why you should be able to use "++" or "--" which are different 
 operations
 than assignment entirely.  Calling it not-an-lvalue means that in the 
 normal
 case it cannot be used on the left (the "to" operand) of a statement.
 In this case a value can be assigned to it - which allocates the array - 
 but it
 cannot be otherwise modified.
 uint mylength;
 mylength++; // mylength = 1
 mylength--; // mylength = 0

 Maybe I'm missing the point, but I'm cannot understand what else the
 operator needs to know in order to manipulate a variable of integral 
 type
 (i.e. int, uint, short, etc...).

 In article <opr4vasfyhs6zaqn news.digitalmars.com>, Andrew Edwards
 says...
 On Sat, 13 Mar 2004 14:57:08 -0600, J C Calvarese <jcc7 cox.net> 
 wrote:

    s.length++;    // 's.length' is not an lvalue
I forget the reason why this is not authorized, but I rationalize it myself. If I can do this: s.length = s.length + 1; s.length = s.length - 1; s.length = 0; Then why on earth wouldn't I be allowed to do this: s.length++; s.length--; s.length += 1; s.length -= 1; [etc...] They are all means to the same end. The .length property is simply a uint variable. As such, it should be able to be modified like any other variable of type uint. Andrew -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
-- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
-- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Mar 14 2004
next sibling parent Andrew Edwards <remove_ridimz remove_yahoo.com> writes:
On Sun, 14 Mar 2004 22:15:43 -0500, Andrew Edwards 
<remove_ridimz remove_yahoo.com> wrote:

 The terms "directly modify" appears to mean two completely different 
 things for you and I. In my mind, to direct modify a variable is to 
 explicitly change its value. This means that:

    s.length = 10;
    s.length++;

 are both means of "directly" affecting change to the value of length. My 
 position is that if this form (first example) of "direct modification" 
 is authorized, then why not allow all other forms of direct 
 modification? Why allow some forms and prevent others? If we are not 
 change some something "directly", then make it so. I'm quite positive 
 that the .length property can be defined to grow and shrink dinamically 
 (as is already the case).

 As a matter of fact, I personally favor a dynamic array (i.e. char[], 
 int[], unit[], etc...) whose length property can only be implicitly 
 modified by assigning a value larger/smaller than its current value or 
 explicitly decreased with with --;

 Examples:

 char[] str;               // str.length = 0
 str = "information"       // str.length = 11, str = "information"
 str = str[2..str.length]; // str.length = 9,  str = "formation"
 str.length++;             // illegal
 str.length = 10;          // illegal
 str.length--;             // str.length = 8,  str = "formatio"
 str = "";                 // OK, str.length = 0

 This can prove quite helpful with implementing a stack or queue.
 class stack {
   char[][] stackmember;
   void push(char[] str){stackmember ~= str;}
   void pop(){stackmember--;} // LIFO
   ...
 }

 class queue {
    char[][] queuemember;
    void enqueue(char[] str){queuemember = str ~ queuemember;}
    void dequeue(){queuemember--}; // FIFO
    ...
 }
One last thing... (pardon my spellings and gramatical errors) Because my desire for "--" only exist for these specific cases and can be easily satisfied with array slicing, I don't find it that important and can easily do without. Which is to say that I would readily support the decision to prevent all direct modifications to the .length property. Andrew
Mar 14 2004
prev sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Andrew Edwards wrote:

[...]
 str = "";                 // OK, str.length = 0
Not agreed. Because making a dynamic array longer is an expensive operation any shortening should be mentioned explicitely. Except there is no actually returning of memory to a freeb list or the underlying os. [...]
 I find absolutely no reason for explicitly lengthen a dynamic array.
 Maybe someone else can provide an argument in favor of (I personally am
 against) it.
[...] The reason is very simple: increasing the length of a dynamic array is expensive and I think you know the reasons for this expensiveness. Because of this expensiveness the requirement of explicitely mentioning a wanted lenghtening is justified. Remember also, that preallocating a big chunk of memory is more efficient than allocating several smaller pieces. So long!
Mar 15 2004
parent reply Scott Wood <nospam buserror.net> writes:
On Mon, 15 Mar 2004 13:33:19 +0100, Manfred Nowak <svv1999 hotmail.com> wrote:
 The reason is very simple: increasing the length of a dynamic array is
 expensive and I think you know the reasons for this expensiveness.
 
 Because of this expensiveness the requirement of explicitely
 mentioning a wanted lenghtening is justified.
 
 Remember also, that preallocating a big chunk of memory is more
 efficient than allocating several smaller pieces.
What about making "capacity" a separate property from "length", where the former refers to the allocated storage and the latter refers to the number of currently valid elements? This way, you don't need to worry about filling in default initializers when allocating more capacity, and bounds checking would work on the actual number of used elements. The downside would be the need to store two values for each array, but that buys you saner array behavior. -Scott
Mar 16 2004
next sibling parent reply J C Calvarese <jcc7 cox.net> writes:
Scott Wood wrote:
 On Mon, 15 Mar 2004 13:33:19 +0100, Manfred Nowak <svv1999 hotmail.com> wrote:
 
The reason is very simple: increasing the length of a dynamic array is
expensive and I think you know the reasons for this expensiveness.

Because of this expensiveness the requirement of explicitely
mentioning a wanted lenghtening is justified.

Remember also, that preallocating a big chunk of memory is more
efficient than allocating several smaller pieces.
What about making "capacity" a separate property from "length", where the former refers to the allocated storage and the latter refers to the number of currently valid elements? This way, you don't need to worry about filling in default initializers when allocating more capacity, and bounds checking would work on the actual number of used elements. The downside would be the need to store two values for each array, but that buys you saner array behavior. -Scott
If you want a "capacity" for performance reasons, it's been suggested before (last time it was called ".reserve"). I was in favor of it until Walter mentioned this trick: "After setting .length to the max reasonable size, then set .length back to zero. You now have a reserve that is something like the max reasonable size rounded up to the next bucket size." (http://www.digitalmars.com/drn-bin/wwwnews?D/17688) More tricks are here: http://www.wikiservice.at/d/wiki.cgi?FaqRoadmap -- Justin http://jcc_7.tripod.com/d/
Mar 16 2004
next sibling parent reply Ben Hinkle <bhinkle4 juno.com> writes:
If you want a "capacity" for performance reasons, it's been suggested 
before (last time it was called ".reserve"). I was in favor of it until 
Walter mentioned this trick:

"After setting .length to the max reasonable size, then set .length back 
to zero. You now have a reserve that is something like the max 
reasonable size rounded up to the next bucket size."

(http://www.digitalmars.com/drn-bin/wwwnews?D/17688)
I wonder how/if this trick actually works since setting the length back to zero nulls out the data pointer which leaves the old "reserve" to be garbage collected. The next time the length is set it looks on the free list and the reserve will only be on the free list (first of all it might be on the wrong free list if the reserve size is significantly different than the requested length) after a garbage collect. I can see how it works if the length is set back to, say, 1. In that case the data pointer is not released. The key routine I'm looking at is _d_arraysetlength in src/phobos/internal/gc/gc.d This shouldn't be too hard to test using gcstats. I've attached a small test file to show what I mean. -Ben
Mar 16 2004
parent J C Calvarese <jcc7 cox.net> writes:
Ben Hinkle wrote:
If you want a "capacity" for performance reasons, it's been suggested 
before (last time it was called ".reserve"). I was in favor of it until 
Walter mentioned this trick:

"After setting .length to the max reasonable size, then set .length back 
to zero. You now have a reserve that is something like the max 
reasonable size rounded up to the next bucket size."

(http://www.digitalmars.com/drn-bin/wwwnews?D/17688)
I wonder how/if this trick actually works
I have no idea. I've never checked it. We were discussing the need for a "reserve" and suddenly Walter chimes in with what he says will already work. I thought the issue was moot. But if this method doesn't work, then that might change everything...
 since setting the length
 back to zero nulls out the data pointer which leaves the old
 "reserve" to be garbage collected. The next time the length is
 set it looks on the free list and the reserve will only be on
 the free list (first of all it might be on the wrong free list
 if the reserve size is significantly different than the requested
 length) after a garbage collect.
 I can see how it works if the length is set back to, say, 1.
 In that case the data pointer is not released.
 
 The key routine I'm looking at is _d_arraysetlength
 in src/phobos/internal/gc/gc.d
 
 This shouldn't be too hard to test using gcstats. I've
 attached a small test file to show what I mean.
 
 -Ben
 
-- Justin http://jcc_7.tripod.com/d/
Mar 16 2004
prev sibling parent Ben Hinkle <bhinkle4 juno.com> writes:
begin 644 lengthtest.d



M<')I;G1F*")P;V]L("5U('5S960 )74 9G)E92`E=2!F<F5E;&ES="`E=2!P
M86=E("5U7&XB+`T*"2` <W1A=',N<&]O;'-I>F4L<W1A=',N=7-E9'-I>F4L
M<W1A=',N9G)E96)L;V-K<RP-" D ('-T871S+F9R965L:7-T<VEZ92QS=&%T
M<RYP86=E8FQO8VMS*3L-" T*("` :6YT6UT >#L-"B` (' N;&5N9W1H(#T 

M;"`E=2!U<V5D("5U(&9R964 )74 9G)E96QI<W0 )74 <&%G92`E=5QN(BP-
M" D ('-T871S+G!O;VQS:7IE+'-T871S+G5S961S:7IE+'-T871S+F9R965B



M=F5R<VEO;B`H4T547UI%4D\I('L-" D >"YL96YG=&  /2`P.PT*("` ("` 


M=%-T871S*'-T871S*3L-"B` ("` ('!R:6YT9B B<&]O;"`E=2!U<V5D("5U
M(&9R964 )74 9G)E96QI<W0 )74 <&%G92`E=5QN(BP-" D ("` ('-T871S



`
end
Mar 16 2004
prev sibling parent reply "Matthew" <matthew stlsoft.org> writes:
"Scott Wood" <nospam buserror.net> wrote in message
news:slrnc5efdi.3af.nospam aoeu.buserror.net...
 On Mon, 15 Mar 2004 13:33:19 +0100, Manfred Nowak <svv1999 hotmail.com>
wrote:
 The reason is very simple: increasing the length of a dynamic array is
 expensive and I think you know the reasons for this expensiveness.

 Because of this expensiveness the requirement of explicitely
 mentioning a wanted lenghtening is justified.

 Remember also, that preallocating a big chunk of memory is more
 efficient than allocating several smaller pieces.
What about making "capacity" a separate property from "length", where the former refers to the allocated storage and the latter refers to the number of currently valid elements? This way, you don't need to worry about filling in default initializers when allocating more capacity, and bounds checking would work on the actual number of used elements.
It complicates slicing enormously, and will also likely impact on performance. I think it's got to stay as it is because slicing, as implemented in D, is such a huge win.
 The downside would be the need to store two values for each array,
 but that buys you saner array behavior.

 -Scott
Mar 17 2004
parent reply Scott Wood <nospam buserror.net> writes:
On Wed, 17 Mar 2004 12:34:38 -0000, Matthew <matthew stlsoft.org> wrote:
 "Scott Wood" <nospam buserror.net> wrote in message
 news:slrnc5efdi.3af.nospam aoeu.buserror.net...
 What about making "capacity" a separate property from "length", 
[snip]
 It complicates slicing enormously, 
Why? Make growing array slices illegal without copying first. At worst, you'll get undefined behavior if you do it. You could also set the slice's capacity to zero, and throw an exception if the user tries to grow an array with zero capacity and non-zero length. You wouldn't be able to grow back to the original slice size, but would you be legally able to do so (and recover the original elements) currently? I'd think it'd be bad programming practice to assume that the array you've been given is a slice that you can shrink and regrow without losing data, even if it is legal. What would currently happen if you try to grow a slice past its original size? On a somewhat tangential note, non-slicing reference assignments seem a little vague too. Code that strictly adheres to copy-on-write wouldn't be a problem, but what about code that does this: char[] a, b; a.length = 10; <fill in values in a> b = a; b.length = 20; // b was unable to grow in place, and thus was copied <fill in values in b> Does a see the changes in b? As I understand it, the current answer is no, but would have been yes if b were able to grow in place. Some sort of true reference array type might be nice, where length (and capacity, if any) are pointed to rather than copied around. I suppose one could make a custom struct for it (and arrays with capacity, for that matter), but still... You could then make resizing non-slice assigned arrays illegal as well. What about function parameters? Does inout apply to the contents of an array, or the pointer/length combo itself?
 and will also likely impact on performance.
It'll take slightly longer for things like assigning an array (one more word to copy), but growing arrays would be faster when doing a simple concatenation loop (and IMHO it's better to keep implementation details such as resizing policy out of the way when possible, so that the important stuff is more visible). It'd probably be faster than setting length up and then back down again as well, as I imagine the latter option requires calls into the allocator each time you increase length to determine if you really do need to grow the allocation. The alternative to both of the above is set length high and leave it there, keeping track of the actual end-of-array yourself (as the D spec's example code does), but that's rather ugly, and you lose full bounds checking. It also isn't going to be any faster (assuming the compiler implements a sane growth strategy; if the allocator rounds up to power-of-two, then the compiler could do the same when deciding how much to bump capacity when it's exceeded), except for the one-word-copy hit in assigning arrays. -Scott
Mar 17 2004
parent reply Ben Hinkle <bhinkle4 juno.com> writes:
On Thu, 18 Mar 2004 01:09:34 +0000 (UTC), Scott Wood
<nospam buserror.net> wrote:

On Wed, 17 Mar 2004 12:34:38 -0000, Matthew <matthew stlsoft.org> wrote:
 "Scott Wood" <nospam buserror.net> wrote in message
 news:slrnc5efdi.3af.nospam aoeu.buserror.net...
 What about making "capacity" a separate property from "length", 
[snip]
 It complicates slicing enormously, 
Why? Make growing array slices illegal without copying first. At worst, you'll get undefined behavior if you do it. You could also set the slice's capacity to zero, and throw an exception if the user tries to grow an array with zero capacity and non-zero length.
I'd expect the capacity to be write-only and be a minimum bound. So setting the capacity to n means "this array should make space for at least n elements". That would be equivalent to setting the length to n and back as long as phobos changes to make that actually work.
You
wouldn't be able to grow back to the original slice size, but would
you be legally able to do so (and recover the original elements)
currently?  I'd think it'd be bad programming practice to assume
that the array you've been given is a slice that you can shrink
and regrow without losing data, even if it is legal.

What would currently happen if you try to grow a slice past its
original size?
The section on the length property says growing a slice that starts in the middle of a gc block copies always. Growing a slice that starts at the head of a gc block (ie - index 0) reallocates if the new size is longer than the space allocated.
On a somewhat tangential note, non-slicing reference assignments seem
a little vague too.  Code that strictly adheres to copy-on-write
wouldn't be a problem, but what about code that does this:

char[] a, b;

a.length = 10;
<fill in values in a>
b = a;
b.length = 20; // b was unable to grow in place, and thus was copied
<fill in values in b>

Does a see the changes in b?  As I understand it, the current answer
is no, but would have been yes if b were able to grow in place.
That's right - the examples in the section about setting the length property talk about this. It would be nice to document copy-on-write in more places than just the string module.
Some sort of true reference array type might be nice, where length
(and capacity, if any) are pointed to rather than copied around.  I
suppose one could make a custom struct for it (and arrays with
capacity, for that matter), but still...  You could then make
resizing non-slice assigned arrays illegal as well.

What about function parameters?  Does inout apply to the contents
of an array, or the pointer/length combo itself?
inout applies to the pointer/length combo. If you change the length of the parameter it changes the length of the original variable passed in to the function.
 and will also likely impact on performance.
It'll take slightly longer for things like assigning an array (one more word to copy), but growing arrays would be faster when doing a simple concatenation loop (and IMHO it's better to keep implementation details such as resizing policy out of the way when possible, so that the important stuff is more visible). It'd probably be faster than setting length up and then back down again as well, as I imagine the latter option requires calls into the allocator each time you increase length to determine if you really do need to grow the allocation.
Looking at src/phobos/internal/gc/gcx.d the function size_t capacity(void*p) uses a cache so if you are increasing the length in a loop it caches the last lookup so it is fast. If you increase the length of multiple arrays in a loop then it will have to call findSize to do more work. I don't know if it is faster to compute the capacity like this or store the capacity in the array structure together with the length. It would also depend on the GC implementation.
The alternative to both of the above is set length high and leave it
there, keeping track of the actual end-of-array yourself (as the D
spec's example code does), but that's rather ugly, and you lose full
bounds checking.  It also isn't going to be any faster (assuming the
compiler implements a sane growth strategy; if the allocator rounds
up to power-of-two, then the compiler could do the same when deciding
how much to bump capacity when it's exceeded), except for the
one-word-copy hit in assigning arrays.

-Scott
Mar 17 2004
parent Scott Wood <nospam buserror.net> writes:
On Wed, 17 Mar 2004 22:42:31 -0500, Ben Hinkle <bhinkle4 juno.com> wrote:
 On Thu, 18 Mar 2004 01:09:34 +0000 (UTC), Scott Wood
<nospam buserror.net> wrote:
What would currently happen if you try to grow a slice past its
original size?
The section on the length property says growing a slice that starts in the middle of a gc block copies always. Growing a slice that starts at the head of a gc block (ie - index 0) reallocates if the new size is longer than the space allocated.
Sounds like it could make for some fun behavior when code that used to get a slice starts getting passed a whole array (or a slice at the beginning)...
Does a see the changes in b?  As I understand it, the current answer
is no, but would have been yes if b were able to grow in place.
That's right - the examples in the section about setting the length property talk about this.
Doh... I'm not entirely sure how I missed that. :-P
What about function parameters?  Does inout apply to the contents
of an array, or the pointer/length combo itself?
inout applies to the pointer/length combo. If you change the length of the parameter it changes the length of the original variable passed in to the function.
It seems a little asymmetric to be able to create such a reference through parameter passing but not by assignement...
 Looking at src/phobos/internal/gc/gcx.d the function 
  size_t capacity(void*p)
 uses a cache so if you are increasing the length in a loop it
 caches the last lookup so it is fast.
Hmm... In that case, there's not much need to carry it around in the array. Plus, a sufficiently optimizing compiler could cache the capacity on its own within the loop. BTW, there doesn't appear to be any synchronization in GC.capacity, so a thread could update the cache between when another thread reads p_cache and size_cache. If thread local storage is supported, this seems like an appropriate place to use it. -Scott
Mar 18 2004
prev sibling parent Manfred Nowak <svv1999 hotmail.com> writes:
Andrew Edwards wrote:

[...]
 The .length property is simply a uint variable.
[...] Not agreed. It is a property and therefore should be interpreted as an overloaded function to be consistent to the properties of structs and classes which _are_ functions. Did you notice that D also has module properties? private int num; public void f(int num){ .num=num;} // do not shout at me, that this is public int f(){ return num;} // example is somehow senseless void main(){ f++; // error: 'f' is not a scalar, it is a void(int num) f=f+1; // compiles okay } The error message is quite okay, because `f++' is equivalent to `f=f+1' and therefore the `(int)' overload is needed first, or because the `(int)' overload appears lexically first. D can however be made such that properties are treated as variables. Because of the syntactical equvivalence of properties to variables, this is recommended. But then D is at the point that also classes and structs, that have overloaded opCalls should be treated as variables, thereby imposing an ambiguity in the language: class C{ private int num; void opCall( int num1){ num= num1;} int opCall( return num;} private int foo, bar; .... } C foo, bar; .... foo= bar; What is meant by the assignment `foo= bar;'? Is only the value of `foo.num' changed to the value of `bar.num', beacuase the overloaded opCalls are called, or are all inetrnal values of `foo' set to the values `bar', because the calls variables are assigned? So long!
Mar 15 2004