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@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.
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.
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:
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