Z# (Zee-sharp)

A new .NET language

Range

A Range encapsulates a range of indices and optionally a step value or a sequence of numbers.

Given an array of integers:

Array 1 2 3 4 5 6 7 8
Index 0 1 2 3 4 5 6 7
Reverse -8 -7 -6 -5 -4 -3 -2 -1

Syntax

Note: Range’s stop or end term is exclusive!

[1..4]      // closed range (skip first)
[..4]       // from start
[4..]       // till end
[..]        // all
[0]         // first
[-1]        // last
[..-1]      // till one before end

// TBD
[3..=9]      // inclusive end?

Note negative values in ranges used for indexing arrays and lists, mean ‘count backward from the end of the array’. Negative numbers in range expressions to generate number sequences mean literal negative numbers.

rng := Range(1, 6)     // allow??
arr := (1, 2, 3, 4, 5, 6)
// index-based array composition?
x := arr[0, 3, 1, 4]
// x: Array<U8> = (1, 4, 2, 5)
// x cannot be a Slice

TBD

A range results in a (virtual) list with numbers. So shouldn’t the syntax reflex a list?

rng := (0..10)       // range from 0 to 9 -incl.
stp := (0..10: 2)    // 0, 2, 4, 6, 8
stp := (0..10+ 2)    // alternate syntax? (bc ':' is for type)

TBD: use list syntax () when creating range objects. Use index syntax [] when extracting from Array or List objects.

Step

A third optional parameter for a range is the step the value takes on each iteration.

// forward
[0..5]
[0..5: 1]   // same
[5..0: 1]   // does not iterate.

// backward
[5..0: -1]

If no step is specified it is always 1. This means that non-normalized ranges with start > end, will not iterate - a behavior that is most useful/common/expected I think.

.NET: how does C# behave concerning non-normalized ranges and iteration? => Throws an ArgumentOutOfRangeException on Range ctor.

Dimensions

TBD

Multi-dimensional ranges.

// 2D range
[..5, 3..5]
// 3D range
[..5, 3..5, -1]

Static

[1..10]

Dynamic

i := 42
[0..i]

Range Type

Keeps track of the indices that define a range.

Range
    begin: U32?
    end: U32?
    step: U32 = 1

Ranges convert to Slices when paired with an array or list.

a: Array<U8> = (1, 2, 3, 4, 5)
r := [0..]       // Range object
s := Slice(a, r) // Slice<T> object
i := GetIter(s)  // Iter<T> object

Use ranges for value range checking (range-condition).

x := 42
// 'in' is interpreted differently than in a loop!
if x in [0..100]
    // true

That would also mean this: Range<T> to allow for floats etc. Step would only be optional for integers but mandatory for floating point numbers.

flt := [0.0..1.0: 0.2]  // 0.0, 0.2, 0.4, 0.6, 0.8

Iterators

Iter<S, T>      // interface
    Next: (self: S): Bool _
    Current: (self: S): T _
GetIter: <T>(self: Array<T>, rng: Range?): Iter<T>
GetIter: <T>(self: List<T>, rng: Range?): Iter<T>
GetIter: <T>(self: Slice<T>): Iter<T>
ArrIter<T>
    arr: Ptr<Array<T>>
    i: U8

Next: <T>(self: ArrIter<T>)
    if self.arr()#Count > self.i
        i = i + 1
        return true
    return false

Current: <T>(self: ArrIter<T>)
    return self.arr()[self.i]

Slices

A pointer and a length

Slice<T>
    ptr: Ptr<T>     // ptr to first element
    length: U32

Slice<T>
    ptr: Ptr<T>     // pointer to object
    offset: U32     // offset to first element
    length: U32

Examples

arr := (1, 2, 3, 4, 5)

loop v in arr[1..-2]    // 2, 3
    ...

TBD

Add a negative sign to do a reverse range?

loop n in [8..0]    // reverse range
loop n in -[0..8]   // neg operator on fwd range
    for_n_7_6_5_4_3_2_1_0

TBD

Have syntax for standard ‘sub-array’ behavior of .NET Range usage?

I think .NET copies over the array elements when indexing with a range.

arr := (0, 1, 2, 3, 4, 5, 6, 7, 8)
sub := arr.[0..5]        // dot operator
sub := arr.copy([0..5])  // explicit function

TBD

Use a specific range syntax to indicate if the indices are inclusive or exclusive.

incl := [1..6]       // 1 and 6 are both part of the range
excl := (1..6)       // 1 and 6 are not part of the range
half := [1..6)       // 1 is incl, 6 is excl
other := (1..6]      // 1 is excl, 6 is incl

https://www.cuemath.com/algebra/interval-notation