Reference

std/core/range

std/core/src/range.trb

The three ranges the syntax writes - Range for 0..10, RangeFrom for 0.., RangeTo for ..10 - the trait Bounds that reads any of them, and RangeIterator, what it takes to walk a range of integers.

The type says which ends there are. a..b has both, a.. has a start, ..b has an end, and no field is optional anywhere - so for index in ..10 and (0..).length() are refused where they are written and nothing has to panic at run time.

type Range

native type Range<Value> with Equals, Hash

0..10, 0..=10: a range with both ends. What for index in 0..list.length() counts through, and what a slice of a known part takes (samples[0..100]).

Examples

const bounded = 0..10
print bounded.contains(5)
const inclusive = 0..=10
print inclusive.contains(10)

Related

  • RangeFrom - 0.., open at the end.
  • RangeTo - ..10, open at the start.
  • Bounds - what a receiver takes to accept all three.

field start

start: Value

The first value the range covers.

field end

end: Value

The last value, which inclusive says whether the range covers itself.

field inclusive

inclusive: Bool = false

0..=10 contains its end, 0..10 does not. An adjective, because it is data and not a question.

type RangeFrom

native type RangeFrom<Value> with Equals, Hash

0..: a range with a start and no end. What a slice to the end of a value takes (text[2..]), and the one range that iterates forever.

Examples

const fromThree = 3..
print fromThree.contains(1000)

Related

  • Range - 0..10, the range with both ends.

field start

start: Value

The first value the range covers.

type RangeTo

native type RangeTo<Value> with Equals, Hash

..10, ..=10: a range with an end and no start. What a slice from the beginning of a value takes (items[..3]).

It is not a sequence: there is no first value to start counting at, which is why for index in ..10 is refused where it is written.

Examples

const upToTen = ..10
print upToTen.contains(9)

Related

  • Range - 0..10, the range with both ends.

field end

end: Value

The last value, which inclusive says whether the range covers itself.

field inclusive

inclusive: Bool = false

..=10 contains its end, ..10 does not.

trait Bounds

trait Bounds<Value: Compare>

What every range has in common: the two ends, each None where the range is open on that side.

This is what a receiver takes that accepts all three forms - a slice does (text[2..], items[..3], items[1..=2]), because an open end has a meaning there: the start or the end of the value. Whoever needs a start takes a Range or a RangeFrom instead and lets the type refuse the rest.

Examples

fn width(span: Bounds<Int>): String {
  "{span.lowest()} {span.highest()} {span.includesHighest()}"
}

print width(2..=5)
print width(2..)

fn lowest

fn lowest(): Value?

The low end, or None where the range is open at the start.

fn highest

fn highest(): Value?

The high end, or None where the range is open at the end.

fn includesHighest

fn includesHighest(): Bool

Whether Bounds.highest itself lies inside. A range that has no high end answers false, which says nothing.

fn contains

fn contains(value: Value): Bool

Whether the value lies within the range's bounds. An open end never excludes anything on its side.

extend Range<Value> with Bounds<Value>

extend<Value: Compare> Range<Value> with Bounds<Value>

Both ends are there, and inclusive says whether the high one is inside.

fn lowest

fn lowest(): Value?

fn highest

fn highest(): Value?

fn includesHighest

fn includesHighest(): Bool

extend RangeFrom<Value> with Bounds<Value>

extend<Value: Compare> RangeFrom<Value> with Bounds<Value>

Open at the end, so there is no high end to include.

fn lowest

fn lowest(): Value?

fn highest

fn highest(): Value?

fn includesHighest

fn includesHighest(): Bool

extend RangeTo<Value> with Bounds<Value>

extend<Value: Compare> RangeTo<Value> with Bounds<Value>

Open at the start.

fn lowest

fn lowest(): Value?

fn highest

fn highest(): Value?

fn includesHighest

fn includesHighest(): Bool

extend Range<Int> with Iterate<Int>, Length

extend Range<Int> with Iterate<Int>, Length

A range of integers with both ends is a sequence with a length. Other ranges of integers are less: 0.. iterates and has no length, ..10 does neither. Ranges of other types are bounds and nothing more - 'a'..'z' says what is inside of it, but there is no "the next value after a" in general.

fn iterate

fn iterate(): Iterator<Int>

fn length

fn length(): Int

How many values the range covers, never below zero: (5..3).length() is 0.

extend RangeFrom<Int> with Iterate<Int>

extend RangeFrom<Int> with Iterate<Int>

0.. counts on forever, which is what makes for index in 0.. and (0..).take(3) work.

fn iterate

fn iterate(): Iterator<Int>

extend Range<Value> with Show

extend<Value: Show> Range<Value> with Show

The source form, and not the fields: 0..10, 0..=10. A Show of its own rather than the derived one because a reader writes a range that way, and because the interpreter has printed it that way all along - the two have to agree to the character (design principle 5).

It is conditional on Value: Show, which is why it cannot be a member of the native type itself: a range of something unshowable is still a range.

fn show

fn show(): String

extend RangeFrom<Value> with Show

extend<Value: Show> RangeFrom<Value> with Show

0.., the source form.

fn show

fn show(): String

extend RangeTo<Value> with Show

extend<Value: Show> RangeTo<Value> with Show

..10, ..=10, the source form.

fn show

fn show(): String