# Ranges

Emanuele Torre torreemanuele6 at gmail.com
Sun Aug 7 20:06:18 UTC 2022

On Saturday, 6 August 2022 at 15:37:32 UTC, pascal111 wrote:
> On Friday, 5 August 2022 at 04:05:08 UTC, Salih Dincer wrote:
>> On Thursday, 4 August 2022 at 22:54:42 UTC, pascal111 wrote:
>>>
>>> I didn't notice that all what we needs to pop a range forward
>>> is just a slice, yes, we don't need variable here.
>>
>> Ranges and Slices are not the same thing. Slicing an array is
>> easy. This is a language possibility. For example, you need an
>> incrementing variable for the Fibonacci Series.
>>
>> SDB at 79
>
> What!!! so where's ranges?! I thought slices of any array are
> ranges, and understood it like that, and also there's no data
> type called ranges, it's like if you are talking about Ghostly
> data type!

A range is like an iterator in any other language (Java, C++,
python3, javascript, etc), it is how D implements (lazy)
generators https://en.wikipedia.org/wiki/Lazy_evaluation .

Ranges/Iterators don't necessarily have to be backed by memory,
they just have to implement the interface. In D, a `empty` bool
function that tells you whether you are at the end of the range
or not; a `front` function to get the current value if the range
is not `empty`; and a void function named `popFront` to advance
to the next value if the range is not `empty`.

Once you have implemented this interface, you can use your
"range" object with any function that accept a range; with
`foreach`; etc.

Example of a range that is not backed by memory is a range with
all the integer numbers.

```D
struct Integers {
private int z = 0;

/* or make it a bool attribute that starts as false, and you
set to
* true when popFront is called while z is equal to int.min */
public bool empty() { return false; }

public int front() { return this.z; }

public void popFront()
{
/* if (this.z == int.min) { this.empty = false; return; } */
this.z *= -1;
if (this.z <= 0)
--this.z;
}
}

void main()
{
import std.stdio : writeln;

/* foreach is syntax sugar for
*   for (auto r = Integers(); !r.empty(); r.popFront()) {
*     auto z = r.front(); /+ or  const z = r.front();  or ...
+/
*     ...
*   }
* that is why it only works with ranges.
*/
foreach (const z; Integers()) {
writeln(z);
if (z == 5)
break;
}
}
```

output:
```
0
-1
1
-2
2
-3
3
-4
4
-5
5
```

This will iterate all the integers, and the integers are of
course, not
all in memory, and don't remain in memory after they are used,
since
that would require infinite memory. (in the case of a range of
integers,
not infinite, because they are constrained by being int.sizeof
bytes,
but you could use a bignum implemenation that is not constrained
by
that and they would actually be infinite.)

---

The equivalent in Java is the Iterable/Iterator interface.

```java
import java.util.Iterator;

public class Integers
implements Iterable<Integer>
{
public class IntegersIterator
implements Iterator<Integer>
{
private int z = 0;
private boolean first = true;

public IntegersIterator(Integer z)
{
this.z = z;
}

@Override
public boolean hasNext() { return true; }

@Override
public Integer next()
{
if (this.first) {
this.first = false;
return this.z;
}

this.z *= -1;
if (this.z <= 0)
--this.z;
return this.z;
}
}

@Override
public IntegersIterator iterator() { return new
IntegersIterator(0); }

public static void main(String[] args)
{
/* syntax sugar for
*   {
*     final var it = newIntegers.iterator();
*     while (it.hasNext()) {
*       final int z = it.next();
*       ...
*     }
*   }
*/
for (final int z : new Integers()) {
System.out.println(z);
if (z == 5)
break;
}
}
}
```

The equivalent in python is a generator function:
```python
def integers():
z = 0
yield z
while True:
z *= -1
if z <= 0:
z -= 1
yield z

for z in integers():
print(z)
if z == 5:
break
```

etc