Go Back

Why Do Some Extension Methods Not Work After Importing a C# Project?

When attempting to import C# Projects via the C# to DBLNET Conversion Tool (C# to Synergy DBL Conversion Tool):

The following Toy C# Program will generate a DBL-E-NFND () it appears to affect some, but not all Linq Extension Methods?

The toy program is straight forward and will remove all Nodes from the given XML File, this works without issue in C#.

C#

using System.Linq;
using System.Xml.Linq;
namespace LinqDoesNotWorkRemove
{
    class Program
    {
        static void Main( string[] args )
        {
            XDocument projFile = XDocument.Load("Sample.xml");
            XElement[] nodes = projFile.Descendants().ToArray();
            nodes.Remove();
        }
    }
}

DBLNET (Generated)
import System.Linq
.array 0
import System.Xml.Linq
namespace LinqDoesNotWorkRemove
    class Program
        public static method Main, void
            args, [#]string
            endparams
        proc
            data projFile, @XDocument, XDocument.Load("Sample.xml")
            data nodes, [#]@XElement, projFile.Descendants().ToArray()
            nodes.Remove()
        endmethod
    endclass
    main
    proc
        Program.Main(Environment.GetCommandLineArgs())
    endmain
endnamespace

What is the Technical Reason and where is the documentation that outlines this limitation?

5 Answers
0   | Posted by Ace Olszowka to Synergy .NET on 11/5/2018 10:38 PM
Ace Olszowka
The plot thickens; here's another usage where we get TYPMISMCH if you get any more than a little complex in your Linq statements; its like the ToArray() call just is not liked; maybe a bug?

C#
using System.Collections.Generic;
using System.Linq;
namespace LinqDoesNotWorkIEnumerableReturns
{
    class Program
    {
        static void Main( string[] args )
        {
            IEnumerable<int> result = GetFirst100OddNumbers();
            IEnumerable<string> result2 = GetNumerics();
        }
        internal static IEnumerable<int> GetFirst100OddNumbers()
        {
            IEnumerable<int> first100Numbers = Enumerable.Range(1, 100);
            // The file names at this point are relative; therefore we need to get the full path
            IEnumerable<int> result = first100Numbers.Where(number => number % 2 == 0);
            return result;
        }
        internal static IEnumerable<string> GetNumerics()
        {
            string[] inputs = new string[] { "A", "B", "C", "1", "2", "3" };
            IEnumerable<string> result = inputs.Where(str => char.IsNumber(str.AsEnumerable().First()));
            return result;
        }
        internal static IEnumerable<string> GetNumericsToArray()
        {
            string[] inputs = new string[] { "A", "B", "C", "1", "2", "3" };
            IEnumerable<string> result = inputs.Where(str => char.IsNumber(str.AsEnumerable().First())).ToArray();
            return result;
        }
    }
}


DBLNET (Generated)
import System.Collections.Generic
.array 0
import System.Linq
namespace LinqDoesNotWorkIEnumerableReturns
    class Program
        public static method Main, void
            args, [#]string
            endparams
        proc
            data result, @IEnumerable<int>, GetFirst100OddNumbers()
            data result2, @IEnumerable<string>, GetNumerics()
        endmethod
        internal static method GetFirst100OddNumbers, @IEnumerable<int>
            endparams
        proc
            data first100Numbers, @IEnumerable<int>, Enumerable.Range(1, 100)
            ;;  The file names at this point are relative; therefore we need to get the full path
            data result, @IEnumerable<int>, first100Numbers.Where(lambda (number) { (number .mod. 2) == 0 })
            mreturn result
        endmethod
        internal static method GetNumerics, @IEnumerable<string>
            endparams
        proc
            data inputs, [#]string, new string[#] {"A", "B", "C", "1", "2", "3"}
            data result, @IEnumerable<string>, inputs.Where(lambda (str) { char.IsNumber(str.AsEnumerable().First()) })
            mreturn result
        endmethod
        internal static method GetNumericsToArray, @IEnumerable<string>
            endparams
        proc
            data inputs, [#]string, new string[#] {"A", "B", "C", "1", "2", "3"}
            data result, @IEnumerable<string>, inputs.Where(lambda (str) { char.IsNumber(str.AsEnumerable().First()) }).ToArray()
            mreturn result
        endmethod
    endclass
    main
    proc
        Program.Main(Environment.GetCommandLineArgs())
    endmain
endnamespace

11/6/2018 12:00 AM   0  
Best Answer chosen by Ace Olszowka
Kish Baley
The NFND error is because arrays don't expose the IEnumerable<T> interface until later (.Remove() is an extension of IEnumerable<T>). See this link for details https://docs.microsoft.com/en-gb/dotnet/api/system.array?view=netframework-4.7#remarks. The pertinent remarks are: "Single-dimensional arrays implement the ..., System.Collections.Generic.IEnumerable<T>, … generic interfaces.
The implementations are provided to arrays at run time, and as a result, the generic interfaces do not appear in the declaration syntax for the Array class.

So it seems the C# compiler is aware of the availability of IEnumerable<T> for arrays, but the DBL compiler is not. Adding an explicit cast will resolve the DBL error:
((IEnumerable<XElement>)nodes).Remove()

The TYPMISMCH error is interesting because the C# compiler resolves the Linq .ToArray() as a []string, but the DBL compiler resolves as a []char (per Intellisense). Splitting the code into two lines seems to work:
data result, @IEnumerable<string>, inputs.Where(lambda (str) { char.IsNumber(str.AsEnumerable().First()) })
result = result.ToArray()

You may want to pass along the TYPMISMCH example to Support as IMO it should resolve as a single line.

FYI, when I do use the C# to DBL Converter, my expectation is that it'll get me about 95% of what I need. There's so many nuances to how C# code can be written that I'm not sure it can ever get 100% converted code (but I'd sure be pleased if it did!). That's just my opinion, someone from the Development team may be able to provide a more accurate expectation of the converter.

11/9/2018 9:25 PM   1  
Ace Olszowka
@Kish Thank you for taking the time to study these in depth.

> You may want to pass along the TYPMISMCH example to Support as IMO it should resolve as a single line.

Is the crux of the question, should we be filing these as bugs or what?

In a perfect world the C# to DBL Converter would be reliable enough for me to implement "Midnight Monkey Madness" in order to stress test the DBLNET Compiler to preemptively identify weaknesses/bugs in the compiler (PEVerify Errors) ideally before I find in in our production code base.

"Midnight Monkey Madness"
  1. Take Random C# Projects From GitHub
  2. Build them (make sure they build green)
  3. Shove them through the DBLNET Converter
  4. Check if the DBLNET Converter Fell Over <- If So Bug Report (DBLNET Converter)
  5. If the DBLNET Converter Worked; Compile, Check if the Compiler Fell Over <- If So Bug Report (DBLNET Compiler)
  6. If the Compile was successful check for PEVerify Errors <- If Error Bug Report (DBLNET Compiler/PEVerify)
It would be trivial enough to write such a utility to perform this in automation. From there we can "DevOps The Heck Out Of It"; spinning up as many Virtual Machines ("Monkey") as the Company Credit Card will allow, then running these overnight ("Midnight"), then automate reporting bugs to Support ("Madness").

It all depends on if we could rely on the DBLNET Converter to do its job...




** Midnight Monkey Madness is a Simpsons Quote (Treehouse of Horror XVIII):

Homer Simpson: I'll be going out late tonight. It's midnight monkey madness at the zoo.
Marge Simpson: Me too. I'll be overturning all the wheelbarrows in case it rains.
Homer Simpson: Well, enjoy your pointless activity.
Marge Simpson: Have fun at your preposterous event.

11/9/2018 9:35 PM   0  
Kish Baley
Yes I believe the TYPMISMCH error and the work-around that requires splitting the line into 2 lines of code should be reported to Support. Whether it is deemed a bug or not is not for me to say. As for the NFND error, this feels more like an enhancement and so the Community site is probably the best place to present it.

I'm going to defer to Development to define expectations on how robust the C# to DBL converter should be. I don't think the intent was ever to have it perform "Midnight Monkey Madness", specially given the variety of C# code and coding styles. I believe what you'll end up testing is "how well did the converter convert the code" vs. "there's an issue with a particular piece of DBL code".

As for me, I use it when I search for a specific problem and what I find are C# solutions; I'll use the converter when the code is too big to convert manually. I believe this is the intended use for the converter.

11/9/2018 10:39 PM   0  
Ace Olszowka
For anyone still interested in this; Midnight Monkey Madness is not an Ace creation; Google did it back in 2011 and found 400+ unique crashes in Flash https://security.googleblog.com/2011/08/fuzzing-at-scale.html

Again proves that there is no original content on the Internet.

2/27/2019 7:29 PM   0  
Please log in to comment or answer this question.