Jump to page: 1 2 3
Thread overview
number ranges
Jan 17, 2022
forkit
Jan 17, 2022
Paul Backus
Jan 17, 2022
Salih Dincer
Jan 17, 2022
forkit
Jan 17, 2022
H. S. Teoh
Jan 17, 2022
forkit
Jan 17, 2022
H. S. Teoh
Jan 17, 2022
forkit
Jan 17, 2022
H. S. Teoh
Jan 18, 2022
Tejas
Jan 18, 2022
H. S. Teoh
Jan 19, 2022
Tejas
Jan 18, 2022
forkit
Jan 18, 2022
Ali Çehreli
Jan 18, 2022
forkit
Jan 18, 2022
Ali Çehreli
Jan 19, 2022
Salih Dincer
Jan 19, 2022
Ali Çehreli
Jan 20, 2022
Salih Dincer
Jan 20, 2022
Ali Çehreli
Jan 21, 2022
Salih Dincer
Jan 21, 2022
Ali Çehreli
Jan 21, 2022
Salih Dincer
Jan 21, 2022
H. S. Teoh
Jan 19, 2022
Tejas
Jan 19, 2022
forkit
Jan 19, 2022
Era Scarecrow
January 17, 2022
so I'm wondering why the code below prints:

1 2 3 4

and not

1 2 3 4 5

as I would expect.

foreach (value; 1..5) writef("%s ", value);

also, why is this not possible:

int[] arr = 1..5.array;


January 17, 2022
On Monday, 17 January 2022 at 10:24:06 UTC, forkit wrote:
> so I'm wondering why the code below prints:
>
> 1 2 3 4
>
> and not
>
> 1 2 3 4 5
>
> as I would expect.
>
> foreach (value; 1..5) writef("%s ", value);

This kind of half-open interval, which includes the lower bound but excludes the upper bound, is used in programming because it lets you write

    foreach (i; 0 .. array.length) writef("%s ", array[i]);

...without going past the end of the array.

Edsger W. Dijkstra, a well-known academic computer scientist, has written in more detail about the advantages of this kind of interval: https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html

> also, why is this not possible:
>
> int[] arr = 1..5.array;

The `lower .. upper` syntax only works in foreach loops. If you want to create a range of numbers like this in another context, you must use the library function std.range.iota:

    import std.range: iota;
    int[] arr = iota(1, 5).array;

(Why "iota"? Because in APL, the Greek letter iota (ι) is used to create a range of numbers like this.)
January 17, 2022

On Monday, 17 January 2022 at 11:58:18 UTC, Paul Backus wrote:

>

On Monday, 17 January 2022 at 10:24:06 UTC, forkit wrote:
Edsger W. Dijkstra, a well-known academic computer scientist, has written in more detail about the advantages of this kind of interval: https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html

Thank you for this valuable information you have given. There is a nice feature used in uniform():

    import std;

    enum a = 9;
    enum b = 10;

void main() {
  auto sonYok = generate!(() => uniform!"[)"(a, b)).take(10);
       sonYok.writeln; // only 9 (default)

  auto ilk_son = generate!(() => uniform!"[]"(a, b)).take(10);
       ilk_son.writeln; // may contain 9 & 10

  auto orta = generate!(() => uniform!"()"(a, b + 1)).take(10);
       orta.writeln; // only 10

  auto ilkYok = generate!(() => uniform!"(]"(a, b + 1)).take(10);
       ilkYok.writeln; // Does not contain 9
}

It would be nice if this feature, which we set up with templates, could be applied everywhere in D. Because sometimes it is needed.

As for other, I never used this feature until I got used to it. Of course, it's practical like this, it will do 10 reps:

foreach(_;0..11)

Salih

January 17, 2022
On Monday, 17 January 2022 at 11:58:18 UTC, Paul Backus wrote:
>
> This kind of half-open interval, which includes the lower bound but excludes the upper bound, is used in programming because it lets you write
>
>     foreach (i; 0 .. array.length) writef("%s ", array[i]);
>
> ...without going past the end of the array.

Yes. But the intent here is clearly stated and cannot be misunderstood -> array.length

Whereas 1..5 is just an opportunity to shoot yourself in the foot.

"the heretic must be cast out not because of the probability that he is wrong but because of the possibility that he is right." - Edsger W. Dijkstra
January 17, 2022
On Mon, Jan 17, 2022 at 09:37:31PM +0000, forkit via Digitalmars-d-learn wrote:
> On Monday, 17 January 2022 at 11:58:18 UTC, Paul Backus wrote:
> > 
> > This kind of half-open interval, which includes the lower bound but excludes the upper bound, is used in programming because it lets you write
> > 
> >     foreach (i; 0 .. array.length) writef("%s ", array[i]);
> > 
> > ...without going past the end of the array.
> 
> Yes. But the intent here is clearly stated and cannot be misunderstood -> array.length
> 
> Whereas 1..5 is just an opportunity to shoot yourself in the foot.

The compiler cannot discern intent. Both `5` and `array.length` are
expressions, as far as the compiler is concerned. So is `5 +
(array.length - sin(x))/2*exp(array2.length)`, for that matter.  The
compiler does not understand what the programmer may have intended; it
simply follows what the spec says.

Of course, to a *human* the semantics of `1..5` can be totally confusing if you're not used to it.  The bottom-line is, in D (and in other C-like languages) you just have to get used to 0-based indexing, because ultimately it actually makes more sense than the 1-based counting scheme we were taught in school. 1-based counting schemes are full of exceptions and off-by-1 errors; it's needlessly complex and hard for the mortal brain to keep track of all the places where you have to add or subtract 1.  Whereas in 0-based index schemes, you *always* count from 0, and you always use `<` to check your bounds, and you can do arithmetic with indices just by adding and subtracting as usual, without off-by-1 errors.

Basically,

	foreach (i; a .. b)

is equivalent to:

	for (auto i = a; i < b; i++)

Just think of that way and it will make sense.

And never ever write 1..n unless you actually intend to skip the first element. Remember: 0-based counting, not 1-based counting. You always start from 0, and count up to (but not including) n.  Which also means you should always write `<`, never write `<=`. So your upper bound is always the element *past* the last one. I.e., it's the index at which a new element would be added if you were appending to your list. I.e., the index at which a new element should be added is simply array.length (not array.length+1 or array.length-1 or any of that error-prone crap that nobody can remember).

If you adhere to these simple rules, you'll never need to add or subtract 1 to your counters, loop indices, and lengths (because nobody can remember when to do that, so not having to do it significantly reduces the chances of bugs).


T

-- 
People say I'm arrogant, and I'm proud of it.
January 17, 2022
On Monday, 17 January 2022 at 22:06:47 UTC, H. S. Teoh wrote:
>
> Basically,
>
> 	foreach (i; a .. b)
>
> is equivalent to:
>
> 	for (auto i = a; i < b; i++)
>
> Just think of that way and it will make sense.
>

I think it's fair to say, that I'm familiar with 0-based indexing ;-)

my concern was with the 1..5 itself.

In terms of what makes sense, it actually makes more sense not to use it, at all ;-)

January 17, 2022
On Mon, Jan 17, 2022 at 10:22:19PM +0000, forkit via Digitalmars-d-learn wrote: [...]
> I think it's fair to say, that I'm familiar with 0-based indexing ;-)
> 
> my concern was with the 1..5 itself.
> 
> In terms of what makes sense, it actually makes more sense not to use it, at all ;-)

If I ever needed to foreach over 1-based indices, I'd write it this way in order to avoid all confusion:

	foreach (i; 1 .. 5 + 1)
	{
	}

This will immediately make whoever reads the code (i.e., myself after 2 months :D) wonder, "why +1?" And the answer will become clear and enlightenment ensues. ;-)


T

-- 
Change is inevitable, except from a vending machine.
January 17, 2022
On Monday, 17 January 2022 at 22:28:10 UTC, H. S. Teoh wrote:
>
> If I ever needed to foreach over 1-based indices, I'd write it this way in order to avoid all confusion:
>
> 	foreach (i; 1 .. 5 + 1)
> 	{
> 	}
>
> This will immediately make whoever reads the code (i.e., myself after 2 months :D) wonder, "why +1?" And the answer will become clear and enlightenment ensues. ;-)
>
>
> T

If I were able to write a compiler, my compiler would warn you:

"This is ill-advised and you should know better! Please rewrite this."

January 17, 2022
On Mon, Jan 17, 2022 at 10:35:30PM +0000, forkit via Digitalmars-d-learn wrote:
> On Monday, 17 January 2022 at 22:28:10 UTC, H. S. Teoh wrote:
> > 
> > If I ever needed to foreach over 1-based indices, I'd write it this way in order to avoid all confusion:
> > 
> > 	foreach (i; 1 .. 5 + 1)
> > 	{
> > 	}
> > 
> > This will immediately make whoever reads the code (i.e., myself after 2 months :D) wonder, "why +1?" And the answer will become clear and enlightenment ensues. ;-)
[...]
> If I were able to write a compiler, my compiler would warn you:
> 
> "This is ill-advised and you should know better! Please rewrite this."

:-D  If *I* were to write a compiler, it'd come with a GC built-in. It'd throw up 90% of programs you feed it with the error "this program is garbage, please throw it away and write something better". :-D


T

-- 
If blunt statements had a point, they wouldn't be blunt...
January 18, 2022

On Monday, 17 January 2022 at 22:48:17 UTC, H. S. Teoh wrote:

>

On Mon, Jan 17, 2022 at 10:35:30PM +0000, forkit via Digitalmars-d-learn wrote:

>

On Monday, 17 January 2022 at 22:28:10 UTC, H. S. Teoh wrote:

>

[...]
[...]
If I were able to write a compiler, my compiler would warn you:

"This is ill-advised and you should know better! Please rewrite this."

:-D If I were to write a compiler, it'd come with a GC built-in. It'd throw up 90% of programs you feed it with the error "this program is garbage, please throw it away and write something better". :-D

T

Newer languages nowadays use start..<end to denote the intent, think it's something we should follow?

« First   ‹ Prev
1 2 3