What specific problems does a foreach statement give?

Developer
Apr 5, 2011 at 5:05 PM

Hello, I'm new to this, and would like to be able to contribute to the project, however in looking over the project, I have noticed that using a foreach statement causes problems. My coding usually contains a large number of these, as such it would be benificial to fix this problem, however, I can't do this unless I know the specific problems which are currently preventing this being fixed.

As such, my question to the community is this, what specific problems are preventing the use of a foreach statement?

Coordinator
Apr 5, 2011 at 5:15 PM
> Hello, I'm new to this, and would like to be able to contribute to the
> project, however in looking over the project, I have noticed that using
> a foreach statement causes problems. My coding usually contains a large
> number of these, as such it would be benificial to fix this problem,
> however, I can't do this unless I know the specific problems which are
> currently preventing this being fixed.
>
> As such, my question to the community is this, what specific problems
> are preventing the use of a foreach statement?

The compiler doesn't support interfaces yet. foreach uses IEnumerable.
Developer
Apr 5, 2011 at 5:25 PM

From my experience, an interface can generally be freely (everything must be declared virtual, and it's recommended to have an exception be thown so that you know that your calling the method on the correct class), interchanged with classes, and then just overriden instead of implemented. Would there be some difficulty in that that's causing a problem?

Coordinator
Apr 5, 2011 at 5:39 PM
> From my experience, an interface can generally be freely (everything
> must be declared virtual, and it's recommended to have an exception be
> thown so that you know that your calling the method on the correct
> class), interchanged with classes, and then just overriden instead of
> implemented. Would there be some difficulty in that that's causing a
> problem?

Becuase foreach as a language feature uses IEnumerable. Cosmos has to
compile the IL to x86, and our compiler does not support interfaces yet....
Developer
Apr 5, 2011 at 5:46 PM

Yes, I get that it doesn't support interfaces. What I'm suggesting is to add support for interfaces via the method I described above. Would it be at all possible? (If it is, then I'll start working on the transformation process when I get to a computer with visual studio on it)

Coordinator
Apr 5, 2011 at 6:53 PM
> Yes, I get that it doesn't support interfaces. What I'm suggesting is to
> add support for interfaces via the method I described above. Would it be
> at all possible? (If it is, then I'll start working on the
> transformation process when I get to a computer with visual studio on it)

I dont see how interface support can be done without changing the compiler.
Developer
Apr 5, 2011 at 7:11 PM

It could be done by transforming the assembly before being passed to the compiler, (for already compiled components), or if the source is available, it could be done before passing it to the compiler for C# (either the .net framework's, or mono's implementation). If you were to do that you would be able to simulate interface support, even if it's not true support for interfaces, it would still be enough to allow the usage of foreach statements in the code. (I would suggest making this an optional function in the build process, as this would probably mess up some not-so-trivial code.)

 

Also might i ask how difficult it would be to implement interfaces in the compiler?

Coordinator
Apr 5, 2011 at 8:29 PM
> It could be done by transforming the assembly before being passed to the
> compiler, (for already compiled components), or if the source is
> available, it could be done before passing it to the compiler for C#
> (either the .net framework's, or mono's implementation). If you were to
> do that you would be able to simulate interface support, even if it's
> not true support for interfaces, it would still be enough to allow the
> usage of foreach statements in the code. (I would suggest making this an
> optional function in the build process, as this would probably mess up
> some not-so-trivial code.)
>
>
>
> Also might i ask how difficult it would be to implement interfaces in
> the compiler?

Not sure, but the big issue is- that we have a big rework of the
compiler planned after the next MS.. and want to wait till then.
Coordinator
Apr 5, 2011 at 8:30 PM
> Also might i ask how difficult it would be to implement interfaces in
> the compiler?

BTW Matthijs will follow up with the "how hard" answer.
Coordinator
Apr 6, 2011 at 6:24 AM
blah: the option you describe is possible in a limited set of situations.

IEnumerable<string> xTest = new List<string>();

EVERYTHING you do on xTest now uses the interface methods.


Let me explain what our compiler does (and the area where the issue is):

<snippet>
int xInt = 3;
xInt.ToString();
<snippet>

Our compiler will see that System.Int32.ToSting() is used, and therefore compile it.

<snippet2>
int xInt = 3;
object xObj = xInt;
xObj.ToString();
</snippet2>

Our compiler will see that Object.ToString() is used, but because this means that ALL .ToString() overrides could be used (well, this situation it's clear, but you get the point), we include ALL .ToString() overrides.
This process is the VMT scan

The VMT scan has (very) limited support for interfaces, but due the the relative size of the "very" here, we consider interface support to not exist.

Have a look using reflector (and the il disassembler view) what code gets emitted when you do a foreach statement. you'll see that IEnumerable<string>.GetEnumerator is called, which means there's no way foor us to work around it, except for fixing the VMT scan.





On Tue, Apr 5, 2011 at 10:30 PM, kudzu <notifications@codeplex.com> wrote:

From: kudzu

> Also might i ask how difficult it would be to implement interfaces in
> the compiler?

BTW Matthijs will follow up with the "how hard" answer.

Read the full discussion online.

To add a post to this discussion, reply to this email (Cosmos@discussions.codeplex.com)

To start a new discussion for this project, email Cosmos@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com


Developer
Apr 6, 2011 at 12:49 PM

Yes I have noticed that using Reflector (I've been using it for a quite a while :P) the definition for an IEnumerable generates quite a few support classes, however, I haven't seen the behaviour your speaking of. I might very well just be missing it somewhere in the code. That, or Reflector's hiding it somewhere (unlikely, but possible). When I get home today, (this computer doesn't have any form of Visual Studio on it, and I'm not allowed to install anything :( ), I'll see what happens when I introduce my String SkipList data-structure, in which I have defined usability in a foreach statement, into the Cosmos environement. Hopefully this should help me to understand the difficulties encountered, and, possibly, work out a better solution than the one I originally suggested. (which, I would agree, does have only a limited usefulness.)

Developer
Apr 6, 2011 at 11:58 PM

Alright, after looking into it with reflector, the implementation of a foreach statement, in normal code is :


public IEnumerator<String> GetEnumerator()
{
Node cur = _head.Next[0];
while (cur != null)
{
yield return ASCIIEncoding.ASCII.GetString(cur.Value);
cur = cur.Next[0];
}
}

 

However, the actual compiled code is this:

public IEnumerator<string> GetEnumerator()
{
    <GetEnumerator>d__0 d__ = new <GetEnumerator>d__0(0);
    d__.<>4__this = this;
    return d__;
}
[CompilerGenerated]
private sealed class <GetEnumerator>d__0 : IEnumerator<string>, IEnumerator, IDisposable
{
    private int <>1__state;
    private string <>2__current;
    public SkipList <>4__this;
    public SkipList.Node <cur>5__1;

    [DebuggerHidden]
    public <GetEnumerator>d__0(int <>1__state)
    {
        this.<>1__state = <>1__state;
    }

    private bool MoveNext()
    {
        switch (this.<>1__state)
        {
            case 0:
                this.<>1__state = -1;
                this.<cur>5__1 = this.<>4__this._head.Next[0];
                break;

            case 1:
                this.<>1__state = -1;
                this.<cur>5__1 = this.<cur>5__1.Next[0];
                break;

            default:
                goto Label_007E;
        }
        if (this.<cur>5__1 != null)
        {
            this.<>2__current = Encoding.ASCII.GetString(this.<cur>5__1.Value);
            this.<>1__state = 1;
            return true;
        }
    Label_007E:
        return false;
    }

    [DebuggerHidden]
    void IEnumerator.Reset()
    {
        throw new NotSupportedException();
    }

    void IDisposable.Dispose()
    {
    }

    string IEnumerator<string>.Current
    {
        [DebuggerHidden]
        get
        {
            return this.<>2__current;
        }
    }

    object IEnumerator.Current
    {
        [DebuggerHidden]
        get
        {
            return this.<>2__current;
        }
    }
}

 This obviously shows there's a lot going on behind the scene's to facilitate just a simple foreach statement.

Coordinator
Apr 7, 2011 at 6:22 AM
wrong: this is not the foreach statement, but the implementation of an enumerator, which wasn't the initial question.

compile the following code, and have a look at the code:

public static void Test()
{
var xTest = new int[] { 1, 2, 3, 4};
foreach(var xItem in xTest)
{
Console.WriteLine(xItem);
}
}

On Thu, Apr 7, 2011 at 1:58 AM, blah38621 <notifications@codeplex.com> wrote:

From: blah38621

Alright, after looking into it with reflector, the implementation of a foreach statement, in normal code is :


public IEnumerator<String> GetEnumerator()
{
Node cur = _head.Next[0];
while (cur != null)
{
yield return ASCIIEncoding.ASCII.GetString(cur.Value);
cur = cur.Next[0];
}
}

However, the actual compiled code is this:

public IEnumerator<string> GetEnumerator()
{
    <GetEnumerator>d__0 d__ = new <GetEnumerator>d__0(0);
    d__.<>4__this = this;
    return d__;
}
[CompilerGenerated]
private sealed class <GetEnumerator>d__0 : IEnumerator<string>, IEnumerator, IDisposable
{
    private int <>1__state;
    private string <>2__current;
    public SkipList <>4__this;
    public SkipList.Node <cur>5__1;

    [DebuggerHidden]
    public <GetEnumerator>d__0(int <>1__state)
    {
        this.<>1__state = <>1__state;
    }

    private bool MoveNext()
    {
        switch (this.<>1__state)
        {
            case 0:
                this.<>1__state = -1;
                this.<cur>5__1 = this.<>4__this._head.Next[0];
                break;

            case 1:
                this.<>1__state = -1;
                this.<cur>5__1 = this.<cur>5__1.Next[0];
                break;

            default:
                goto Label_007E;
        }
        if (this.<cur>5__1 != null)
        {
            this.<>2__current = Encoding.ASCII.GetString(this.<cur>5__1.Value);
            this.<>1__state = 1;
            return true;
        }
    Label_007E:
        return false;
    }

    [DebuggerHidden]
    void IEnumerator.Reset()
    {
        throw new NotSupportedException();
    }

    void IDisposable.Dispose()
    {
    }

    string IEnumerator<string>.Current
    {
        [DebuggerHidden]
        get
        {
            return this.<>2__current;
        }
    }

    object IEnumerator.Current
    {
        [DebuggerHidden]
        get
        {
            return this.<>2__current;
        }
    }
}

This obviously shows there's a lot going on behind the scene's to facilitate just a simple foreach statement.

Read the full discussion online.

To add a post to this discussion, reply to this email (Cosmos@discussions.codeplex.com)

To start a new discussion for this project, email Cosmos@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com


Developer
Apr 7, 2011 at 3:42 PM

I have looked at foreach statements. They show up as exactly what they said before I compiled them.

Coordinator
Apr 7, 2011 at 4:08 PM
Dont look at the c# code, but at the msil code.. reflector optimizes code, detecting constructs like for each, but that doesn't show the problems (clear enough)

On Thu, Apr 7, 2011 at 5:42 PM, blah38621 <notifications@codeplex.com> wrote:

From: blah38621

I have looked at foreach statements. They show up as exactly what they said before I compiled them.

Read the full discussion online.

To add a post to this discussion, reply to this email (Cosmos@discussions.codeplex.com)

To start a new discussion for this project, email Cosmos@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com