Collections and queries in Raven.
func Read(values: Sequence<int>) {
WriteLine(values.Count)
WriteLine(values[0])
WriteLine(values.ToList().Count)
}
func Replace(values: MutableSequence<int>, value: int) {
values[0] = value
}
func Append(values: List<int>) {
values.Add(11)
}The full sample reads both arrays and lists, replaces elements through MutableSequence, and grows a List. A Sequence view sees changes made through another alias: read-only access does not mean immutable storage.
Filter, then map.
Import System.Linq.* for the query operators. Filter keeps matching elements; Map transforms them. This development sample prints 10, then 30. Neither operator invokes its callback until iteration begins.
import System.Linq.*
import System.Console.*
func Main() {
let values: int[] = [1, 2, 3]
let query = values.Filter(value => value != 2)
.Map(value => value * 10)
for value in query {
WriteLine(value)
}
}Complete executable sample → · Expected output →
When moving from Preview 8, replace Where with Filter and Select with Map, then rebuild against the matching development references and runtime library. The old names are not aliases. First, Last, Single and ToList retain their names.
A basic operator set.
Development after Preview 8. Any and All test elements; Count counts them. Take and Skip select a page. Concat joins two sequences in order, and FlatMap turns each element into a sequence and flattens the results. Fold accumulates from an explicit seed, returning that seed for empty input.
import System.Collections.*
import System.Linq.*
import System.Console.*
public func Pair(value: int) -> Iterable<int> {
return [value, value * 10]
}
func Main() {
let values: int[] = [1, 2, 3, 4]
let page = values.Skip(1).Take(2)
for value in page {
WriteLine(value)
}
if values.Any(value => value > 3) {
WriteLine("True")
}
if values.All(value => value > 0) {
WriteLine("True")
}
WriteLine(values.Count(value => value > 2))
WriteLine(values.Fold(0, (total, value) => total + value))
let extra: int[] = [5]
for value in page.Concat(extra).FlatMap(value => Pair(value)) {
WriteLine(value)
}
}The page contains 2 and 3. Both tests are true, the matching count is 2, and the total is 10. The final pipeline prints 2, 20, 3, 30, 5 and 50.
Complete executable sample → · Expected output →
Any and All stop as soon as the answer is known. Empty Any is false and empty All is true. Take, Skip, Concat and FlatMap are lazy. Non-positive Take yields nothing; non-positive Skip skips nothing. Fold consumes its input from left to right. These methods require the development library; they are not included in Preview 8 downloads.
From .NET LINQ to neoCLR.
This maps the current development API. It is not a promise of full LINQ compatibility; Preview 8 retains Where/Select and has fewer operators.
| .NET Enumerable | neoCLR | Behavior |
|---|---|---|
Where(predicate) | Filter(predicate) | Lazy filtering. |
Select(selector) | Map(selector) | Lazy projection. |
SelectMany(selector) | FlatMap(selector) | Lazy flattening; no indexed or result-selector overloads. |
Any(), Any(predicate) | Any(), Any(predicate) | False for empty input; short-circuits. |
All(predicate) | All(predicate) | True for empty input; short-circuits. |
Count(), Count(predicate) | Count(), Count(predicate) | Int32 result; overflow is a runtime fault, not OverflowException. |
Aggregate(seed, accumulator) | Fold(seed, accumulator) | Left-to-right, seeded accumulation; empty input returns the seed. |
Take(count), Skip(count) | Take(count), Skip(count) | Lazy prefix/suffix; non-positive bounds follow .NET behavior. |
Concat(second) | Concat(second) | Lazy concatenation in source order. |
ToList() | ToList() | Materializes an ArrayList rather than a .NET List. |
First(), First(predicate) | First(), First(predicate) | Returns Option; empty/no match is None rather than an exception. |
Last(), Last(predicate) | Last(), Last(predicate) | Returns Option; empty/no match is None rather than an exception. |
Single(), Single(predicate) | Single(), Single(predicate) | Returns Result with distinct Empty/Multiple errors. |
FirstOrDefault / LastOrDefault / SingleOrDefault | No direct equivalent | Use the Option/Result outcome and an explicit fallback. |
Aggregate without a seed, Sum, Average, Min, Max | Not yet implemented | Seeded Fold can express basic accumulation. |
OrderBy, ThenBy, GroupBy, Join, Distinct, Union, Intersect, Except, Zip | Not yet implemented | Ordering, equality and pairing contracts remain future work. |
Behavior and limits.
The roles are comparable to .NET collection interfaces, with replacement separated from growth. More precise contracts help describe what an algorithm requires, at the cost of more interface distinctions. Filter and Map are lazy; ToList materializes, First/Last return Option and Single returns Result.
Detailed contract and comparisons →PROPOSED DIRECTION
Where we’re heading.
Variance, immutable or frozen providers, and broader query coverage need separate decisions. The aim is useful collection contracts, not reproducing every .NET collection type. Iterator and mutation behavior should stay explicit.
Related proposals and open questions →What would you try?
Bring a small use case, the code you tried and the behavior you expected. Which part of this contract helps, and which part should change?
Share feedback on GitHub ↗