digitalmars.D - why $ is need to access array [negative index]?
- mw (14/14) Sep 18 2020 In Python it's such a convenience to be able to access array
- Steven Schveighoffer (7/28) Sep 18 2020 I would say no. The indexing code lowers to a machine instruction.
- mw (5/11) Sep 18 2020 Currently we have range check on every single indexing operation
- mipri (4/15) Sep 18 2020 Range checks that never fire because your code isn't buggy
- Steven Schveighoffer (5/15) Sep 18 2020 -boundscheck=off
- IGotD- (4/7) Sep 18 2020 We want as few range checks as possible because indexing arrays
- IGotD- (6/20) Sep 18 2020 Array indexes in D are using unsigned integers so negative
- mw (3/8) Sep 18 2020 This is the *consequence* of current design.
- bachmeier (23/37) Sep 18 2020 I'm inclined to say typing a single character is not a hardship
- mw (11/13) Sep 18 2020 It not about saving "typing a single character".
- bachmeier (3/17) Sep 18 2020 I'm confused. The justification for a major language change would
- mw (3/13) Sep 18 2020 You are indeed confused: the justification is either compiler
- Ethan (15/17) Sep 18 2020 Good.
- Steven Schveighoffer (4/23) Sep 18 2020 Well, if you don't care about verbosity.
- mw (3/5) Sep 18 2020 I want compiler writes this verbosity, instead of the user :-)
- mw (6/12) Sep 18 2020 And ... this [(sign + $) % $] is not right, it's defensive
- Steven Schveighoffer (10/22) Sep 18 2020 It depends on how you want to define indexing.
- mipri (3/9) Sep 18 2020 It's not free, and not always desirable. This code would silently
- Steven Schveighoffer (5/12) Sep 18 2020 A custom type will do this for you. Just write one.
- H. S. Teoh (15/21) Sep 18 2020 Yawn.
- Patrick Schluter (2/16) Sep 18 2020 signs[1+sign]
- bachmeier (7/53) Sep 18 2020 I forgot to add when discussing C, that D already has negative
- mw (2/8) Sep 18 2020 This is using array index syntax on a raw pointer.
- mipri (23/48) Sep 18 2020 The hardship isn't typing a single character, but requiring an
In Python it's such a convenience to be able to access array element from the end: arr[-1] in D, we can do that too, but need an extra $: arr[$-1] I'm porting some code from Python to D: int[3] signs; // sign: -1, 0, 1 int sign = -1; // for example writeln(signs[sign]); // Range violation // Error: array index 18446744073709551615 is out of bounds signs[0 .. 3] (yes, I know I can use AA, int[int], but it just make things complicated) Can we have a DIP remove / make optional `$` in this usage? Thoughts?
Sep 18 2020
On 9/18/20 3:53 PM, mw wrote:In Python it's such a convenience to be able to access array element from the end: arr[-1] in D, we can do that too, but need an extra $: arr[$-1] I'm porting some code from Python to D: int[3] signs; // sign: -1, 0, 1 int sign = -1; // for example writeln(signs[sign]); // Range violation // Error: array index 18446744073709551615 is out of bounds signs[0 .. 3] (yes, I know I can use AA, int[int], but it just make things complicated) Can we have a DIP remove / make optional `$` in this usage? Thoughts?I would say no. The indexing code lowers to a machine instruction. Making it so a negative value means something else means every single indexing operation is going to have to check whether it's negative, and if so do something completely different. You can create your own array type if you want this behavior. -Steve
Sep 18 2020
On Friday, 18 September 2020 at 20:06:01 UTC, Steven Schveighoffer wrote:I would say no. The indexing code lowers to a machine instruction. Making it so a negative value means something else means every single indexing operation is going to have to check whether it's negative, and if so do something completely different.Currently we have range check on every single indexing operation already; so the trade-off here is: adding one more check v.s. the convenience it buys.You can create your own array type if you want this behavior.
Sep 18 2020
On Friday, 18 September 2020 at 20:46:00 UTC, mw wrote:On Friday, 18 September 2020 at 20:06:01 UTC, Steven Schveighoffer wrote:Range checks that never fire because your code isn't buggy are very friendly to the branch predictor. Negative-indexing checks are not so friendly.I would say no. The indexing code lowers to a machine instruction. Making it so a negative value means something else means every single indexing operation is going to have to check whether it's negative, and if so do something completely different.Currently we have range check on every single indexing operation already; so the trade-off here is: adding one more check v.s. the convenience it buys.
Sep 18 2020
On 9/18/20 4:46 PM, mw wrote:On Friday, 18 September 2020 at 20:06:01 UTC, Steven Schveighoffer wrote:-boundscheck=off This currently disables the bounds checks. If your proposed feature went in, then it would still have to check the index for sign. -SteveI would say no. The indexing code lowers to a machine instruction. Making it so a negative value means something else means every single indexing operation is going to have to check whether it's negative, and if so do something completely different.Currently we have range check on every single indexing operation already; so the trade-off here is: adding one more check v.s. the convenience it buys.
Sep 18 2020
On Friday, 18 September 2020 at 20:46:00 UTC, mw wrote:Currently we have range check on every single indexing operation already; so the trade-off here is: adding one more check v.s. the convenience it buys.We want as few range checks as possible because indexing arrays are not too seldom done it loops. Adding an extra check could affect performance in this case.
Sep 18 2020
On Friday, 18 September 2020 at 21:31:53 UTC, IGotD- wrote:On Friday, 18 September 2020 at 20:46:00 UTC, mw wrote:You dont need an extra check, you just do an unsigned comparison, negative values will interpreted as larger. IE... int idx = length-i; assert(cast(unsigned) idx < length) catches anything outside the valid range. Yes you have the issue that the index could wrap around and end up valid, but you already have that anyway. I mean if (idx-1) is going to cause a problem so will (idx+0xFFFFFFFF)Currently we have range check on every single indexing operation already; so the trade-off here is: adding one more check v.s. the convenience it buys.We want as few range checks as possible because indexing arrays are not too seldom done it loops. Adding an extra check could affect performance in this case.
Sep 20 2020
On Sunday, 20 September 2020 at 14:01:58 UTC, claptrap wrote:You dont need an extra check, you just do an unsigned comparison, negative values will interpreted as larger. IE... int idx = length-i; assert(cast(unsigned) idx < length) catches anything outside the valid range. Yes you have the issue that the index could wrap around and end up valid, but you already have that anyway. I mean if (idx-1) is going to cause a problem so will (idx+0xFFFFFFFF)No, if -1 is going to be interpreted as the element just before the end of the array you will need to have an extra check additional from the extra range check. Still completely irrelevant for D as indexes are of type size_t which is unsigned.
Sep 20 2020
On Sunday, 20 September 2020 at 14:06:10 UTC, IGotD- wrote:On Sunday, 20 September 2020 at 14:01:58 UTC, claptrap wrote:Nevermind I missunderstood the OPYou dont need an extra check, you just do an unsigned comparison, negative values will interpreted as larger. IE... int idx = length-i; assert(cast(unsigned) idx < length) catches anything outside the valid range. Yes you have the issue that the index could wrap around and end up valid, but you already have that anyway. I mean if (idx-1) is going to cause a problem so will (idx+0xFFFFFFFF)No, if -1 is going to be interpreted as the element just before the end of the array you will need to have an extra check additional from the extra range check. Still completely irrelevant for D as indexes are of type size_t which is unsigned.
Sep 20 2020
On Friday, 18 September 2020 at 19:53:41 UTC, mw wrote:In Python it's such a convenience to be able to access array element from the end: arr[-1] in D, we can do that too, but need an extra $: arr[$-1] I'm porting some code from Python to D: int[3] signs; // sign: -1, 0, 1 int sign = -1; // for example writeln(signs[sign]); // Range violation // Error: array index 18446744073709551615 is out of bounds signs[0 .. 3] (yes, I know I can use AA, int[int], but it just make things complicated) Can we have a DIP remove / make optional `$` in this usage? Thoughts?Array indexes in D are using unsigned integers so negative numbers don't exist. What you are suggesting isn't possible in D. $ is the length of the array so $-1 is correct in this regard and produces a correct positive number given that it is inside the array bounds.
Sep 18 2020
On Friday, 18 September 2020 at 20:08:36 UTC, IGotD- wrote:Array indexes in D are using unsigned integers so negative numbers don't exist. What you are suggesting isn't possible inThis is the *consequence* of current design. We are talking about change the design here.D. $ is the length of the array so $-1 is correct in this regard and produces a correct positive number given that it is inside the array bounds.
Sep 18 2020
On Friday, 18 September 2020 at 19:53:41 UTC, mw wrote:In Python it's such a convenience to be able to access array element from the end: arr[-1] in D, we can do that too, but need an extra $: arr[$-1] I'm porting some code from Python to D: int[3] signs; // sign: -1, 0, 1 int sign = -1; // for example writeln(signs[sign]); // Range violation // Error: array index 18446744073709551615 is out of bounds signs[0 .. 3] (yes, I know I can use AA, int[int], but it just make things complicated) Can we have a DIP remove / make optional `$` in this usage? Thoughts?I'm inclined to say typing a single character is not a hardship in exchange for extreme clarity of the code. Keep in mind that Python is not the only language with a negative array index. For instance, C supports it: https://stackoverflow.com/questions/3473675/are-negative-array-indexes-allowed-in-c That's probably the place to look if you want to start, given the relationship of C and D. Then there's R, for which x[-1] means to drop the first element. That makes a lot of sense if x is treated as a vector of data. Python's usage, on the other hand, is not at all intuitive. Why -4 would mean the fourth to last element is unclear. I believe it was copied from Perl. Ruby does the same thing. Then there's PHP, which allows you to use a negative array index as an arbitrary reference to an element: x[-2] could be any of the elements. The strange one is Javascript, which has negative indexes that are actually properties or something like that. Bottom line is that the Python approach is one of many, it only makes sense if someone tells you what it means, and it saves you a single character in return for less clear code. As noted, it's really easy to create a struct that operates like Python if you want. That's the beauty of D.
Sep 18 2020
On Friday, 18 September 2020 at 20:48:47 UTC, bachmeier wrote:I'm inclined to say typing a single character is not a hardship in exchange for extreme clarity of the code. Keep in mind thatIt not about saving "typing a single character". In the example I showed, signs[sign] = ...; // the sign can be -1, 0, 1 in D, to write the same code, you have to test the sign and branch: if (sign >= 0) { signs[ sign] = ...; } else { signs[$+sign] = ...; // remember + here }
Sep 18 2020
On Friday, 18 September 2020 at 20:56:30 UTC, mw wrote:On Friday, 18 September 2020 at 20:48:47 UTC, bachmeier wrote:I'm confused. The justification for a major language change would be convenience of porting Python code to D?I'm inclined to say typing a single character is not a hardship in exchange for extreme clarity of the code. Keep in mind thatIt not about saving "typing a single character". In the example I showed, signs[sign] = ...; // the sign can be -1, 0, 1 in D, to write the same code, you have to test the sign and branch: if (sign >= 0) { signs[ sign] = ...; } else { signs[$+sign] = ...; // remember + here }
Sep 18 2020
On Friday, 18 September 2020 at 21:02:11 UTC, bachmeier wrote:You are indeed confused: the justification is either compiler writes that branching code, or user have to write it.in D, to write the same code, you have to test the sign and branch: if (sign >= 0) { signs[ sign] = ...; } else { signs[$+sign] = ...; // remember + here }I'm confused. The justification for a major language change would be convenience of porting Python code to D?
Sep 18 2020
On Friday, 18 September 2020 at 21:06:22 UTC, mw wrote:You are indeed confused: the justification is either compiler writes that branching code, or user have to write it.Good. Let the user write it every time. I don't want the compiler inserting branches in to my code simply because of the essentially-never chance I might not want to put a $ in front of a -<integer> statement for array access. Further to write it every time: Write an array template. It's simple. Here's the important parts, the rest isn't too difficult to write from here struct Array( T ) { ref auto opIndex( int Index ) { if( Index < 0 ) Index = slice.length + Index; return slice[ Index ]; } T[] slice; }
Sep 18 2020
On 9/18/20 4:56 PM, mw wrote:On Friday, 18 September 2020 at 20:48:47 UTC, bachmeier wrote:Well, if you don't care about verbosity. signs[(sign + $) % $] = ...; -SteveI'm inclined to say typing a single character is not a hardship in exchange for extreme clarity of the code. Keep in mind thatIt not about saving "typing a single character". In the example I showed, signs[sign] = ...; // the sign can be -1, 0, 1 in D, to write the same code, you have to test the sign and branch: if (sign >= 0) { signs[ sign] = ...; } else { signs[$+sign] = ...; // remember + here }
Sep 18 2020
On Friday, 18 September 2020 at 21:11:58 UTC, Steven Schveighoffer wrote:Well, if you don't care about verbosity. signs[(sign + $) % $] = ...;I want compiler writes this verbosity, instead of the user :-)
Sep 18 2020
On Friday, 18 September 2020 at 21:14:19 UTC, mw wrote:On Friday, 18 September 2020 at 21:11:58 UTC, Steven Schveighoffer wrote:And ... this [(sign + $) % $] is not right, it's defensive programming: and will hide real bugs, e.g. when array index > array.length. See how easy user code contains bugs. The compiler should really do the hard work to make programmer's life easier.Well, if you don't care about verbosity. signs[(sign + $) % $] = ...;I want compiler writes this verbosity, instead of the user :-)
Sep 18 2020
On 9/18/20 5:17 PM, mw wrote:On Friday, 18 September 2020 at 21:14:19 UTC, mw wrote:It depends on how you want to define indexing. Let me write that a different way: "And ... this processing of negative indexes is not right, it's defensive programming: and will hide real bugs, e.g. when array index < 0" D array indexing is set in stone. Like really hard, billion-year-old stone. Again, if you want a different indexing scheme, write a type. D makes it really easy! -SteveOn Friday, 18 September 2020 at 21:11:58 UTC, Steven Schveighoffer wrote:And ... this [(sign + $) % $] is not right, it's defensive programming: and will hide real bugs, e.g. when array index > array.length.Well, if you don't care about verbosity. signs[(sign + $) % $] = ...;I want compiler writes this verbosity, instead of the user :-)
Sep 18 2020
On Friday, 18 September 2020 at 21:14:19 UTC, mw wrote:On Friday, 18 September 2020 at 21:11:58 UTC, Steven Schveighoffer wrote:It's not free, and not always desirable. This code would silently accept sign=100 for example.Well, if you don't care about verbosity. signs[(sign + $) % $] = ...;I want compiler writes this verbosity, instead of the user :-)
Sep 18 2020
On 9/18/20 5:14 PM, mw wrote:On Friday, 18 September 2020 at 21:11:58 UTC, Steven Schveighoffer wrote:A custom type will do this for you. Just write one. Would be as easy as: arr.pyIdx[-1]; // uses python indexing. -SteveWell, if you don't care about verbosity. signs[(sign + $) % $] = ...;I want compiler writes this verbosity, instead of the user :-)
Sep 18 2020
On Fri, Sep 18, 2020 at 09:14:19PM +0000, mw via Digitalmars-d wrote:On Friday, 18 September 2020 at 21:11:58 UTC, Steven Schveighoffer wrote:Yawn. struct MyArray(T) { T[] impl; alias impl this; this(T[] data) { impl = data; } ref T opIndex(ptrdiff_t idx) { return (idx < 0) ? impl[$ + idx] : impl[idx]; } } MyArray!int x = [ 1, 2, 3 ]; assert(x[-1] == 3); // not verbose anymore T -- Живёшь только однажды.Well, if you don't care about verbosity. signs[(sign + $) % $] = ...;I want compiler writes this verbosity, instead of the user :-)
Sep 18 2020
On Friday, 18 September 2020 at 20:56:30 UTC, mw wrote:On Friday, 18 September 2020 at 20:48:47 UTC, bachmeier wrote:signs[1+sign]I'm inclined to say typing a single character is not a hardship in exchange for extreme clarity of the code. Keep in mind thatIt not about saving "typing a single character". In the example I showed, signs[sign] = ...; // the sign can be -1, 0, 1 in D, to write the same code, you have to test the sign and branch: if (sign >= 0) { signs[ sign] = ...; } else { signs[$+sign] = ...; // remember + here }
Sep 18 2020
On Friday, 18 September 2020 at 20:48:47 UTC, bachmeier wrote:On Friday, 18 September 2020 at 19:53:41 UTC, mw wrote:I forgot to add when discussing C, that D already has negative index values, which mean something completely different than Python's usage: double[] x = [1, 2, 3, 4]; double * y = &(x.ptr)[2]; writeln(y[-2]); // 1In Python it's such a convenience to be able to access array element from the end: arr[-1] in D, we can do that too, but need an extra $: arr[$-1] I'm porting some code from Python to D: int[3] signs; // sign: -1, 0, 1 int sign = -1; // for example writeln(signs[sign]); // Range violation // Error: array index 18446744073709551615 is out of bounds signs[0 .. 3] (yes, I know I can use AA, int[int], but it just make things complicated) Can we have a DIP remove / make optional `$` in this usage? Thoughts?I'm inclined to say typing a single character is not a hardship in exchange for extreme clarity of the code. Keep in mind that Python is not the only language with a negative array index. For instance, C supports it: https://stackoverflow.com/questions/3473675/are-negative-array-indexes-allowed-in-c That's probably the place to look if you want to start, given the relationship of C and D. Then there's R, for which x[-1] means to drop the first element. That makes a lot of sense if x is treated as a vector of data. Python's usage, on the other hand, is not at all intuitive. Why -4 would mean the fourth to last element is unclear. I believe it was copied from Perl. Ruby does the same thing. Then there's PHP, which allows you to use a negative array index as an arbitrary reference to an element: x[-2] could be any of the elements. The strange one is Javascript, which has negative indexes that are actually properties or something like that. Bottom line is that the Python approach is one of many, it only makes sense if someone tells you what it means, and it saves you a single character in return for less clear code. As noted, it's really easy to create a struct that operates like Python if you want. That's the beauty of D.
Sep 18 2020
On Friday, 18 September 2020 at 20:57:04 UTC, bachmeier wrote:I forgot to add when discussing C, that D already has negative index values, which mean something completely different than Python's usage: double[] x = [1, 2, 3, 4]; double * y = &(x.ptr)[2]; writeln(y[-2]); // 1This is using array index syntax on a raw pointer.
Sep 18 2020
On Friday, 18 September 2020 at 20:48:47 UTC, bachmeier wrote:On Friday, 18 September 2020 at 19:53:41 UTC, mw wrote:The hardship isn't typing a single character, but requiring an explicit test to determine whether you should index with or without that single character. Consider: int ex(int i) { immutable int[3] ns = [1, 2, 3]; if (i < 0) { return ns[$+i]; } else { return ns[i]; } } void main() { import std.stdio, std.range, std.algorithm; iota(3) .map!(n => n - 1) .map!ex .each!writeln; } In Python you can calculate an index on a numeric plane that includes negative numbers and then use it; in D you have some syntax to conveniently refer to the size of the array.In Python it's such a convenience to be able to access array element from the end: arr[-1] in D, we can do that too, but need an extra $: arr[$-1] I'm porting some code from Python to D: int[3] signs; // sign: -1, 0, 1 int sign = -1; // for example writeln(signs[sign]); // Range violation // Error: array index 18446744073709551615 is out of bounds signs[0 .. 3] (yes, I know I can use AA, int[int], but it just make things complicated) Can we have a DIP remove / make optional `$` in this usage? Thoughts?I'm inclined to say typing a single character is not a hardship in exchange for extreme clarity of the code.
Sep 18 2020