Draco-lang / Language-suggestions

Collecting ideas for a new .NET language that could replace C#
75 stars 5 forks source link

Foreach loop #124

Open LPeter1997 opened 1 year ago

LPeter1997 commented 1 year ago

Even in very basic sample code, the lack of a foreach loops is really painful. I don't think it would hurt the language, if for now we define the exact same structure for foreach loops as C# does, basing them off of IEnumerable<T>. Even if we'll come up with our own abstractions later, we likely want to stay compatible to them.

Syntax

I'd like to propose the following syntax:

for (x: int32 in enumerable) { ... }

I believe that with decent range-construction mechanisms, there won't be need for an old-style for-loop anymore, so I propose we use the shorter keyword.

The declared iterator variable is implicitly val, it can not be re-bound. The type annotation is completely optional and can be inferred:

for (x in enumerable) { ... }

Internals

Eventually, we'll want this to be equivalent to the following - just like C#:

var enumerator = enumerable.GetEnumerator();
try
{
    var x;
    while (enumerator.MoveNext())
    {
        x = enumerator.Current;
        // ...
    }
}
finally
{
    var disposable = enumerator as IDisposable;
    disposable?.Dispose();
}

Until we have language elements like try-catch-finally or as casts, the following should suffice for the majority of cases:

var enumerator = enumerable.GetEnumerator();
var x;
while (enumerator.MoveNext())
{
    x = enumerator.Current;
    // ...
}
jl0pd commented 1 year ago

exact same structure for foreach loops as C# does, basing them off of IEnumerable

C# uses duck typing sometimes and foreach is one of cases. Compiler doesn't look for IEnumerable, it looks for type that have accessible instance or extension method called GetEnumerator, returning type that have method MoveNext: () -> bool and property Current

Following compiles:

foreach (int x in new MyEnumerable())
{
}

class MyEnumerable
{
    public MyEnumerator GetEnumerator()
    {
        return new MyEnumerator();
    }

    public class MyEnumerator
    {
        public bool MoveNext() => false;
        public int Current => 0;
    }
}