Reputation: 583
C# compiles into IL which is then easy to decompile back to C# using ILSpy or dotPeek.
Is there any tool that allows that same IL to be decompiled into F#?
i.e. is there a sneaky way to translate C# into F#, via IL?
RATIONALE:
i.e. would this be faster than writing everything from scratch in F#.
We are not yet experienced in F# hence the possible naivety of this question.
FURTHER NOTE Yes, we are using the functional stuff in C# but for various reasons we want to go fully functional with F#. That choice isn't up for debate here but thanks for the comments on this.
Upvotes: 3
Views: 762
Reputation: 227
I am just a hobbyist so I am not guaranteeing that the following is completely accurate... First off, I am going to assume that your current C# base is written in idiomatic C# so your current c# project follows the Object-Oriented paradigm. If this is accurate, and you are looking to go "fully functional" then your only real option is to re-write your project following the functional paradigm. If such an IL converter existed, then the converted would compile your C# into F# in an object-oriented manner (F# is a functional-first language but can also be used as an object-oriented language). Furthermore, as others have noted, you can call your C# code from F#, but that is not going to convert your C# project to act in a functional manner. You're still going to have to use your C# project in the manner it is designed to be used - in an object-oriented manner via F#. You might be able to write some form of wrapper around your C# program in F# to make it behave in a functional manner but if your C# project is based on an object hierarchy then this may not be too trivial and you may find that you don't end up with a fully functional wrapper.
Upvotes: 1
Reputation: 12687
As echoed here, you're losing precious information when you compile to IL. It's much more feasible to read the C# code to translate all of that high level info.
Just hacked together a SyntaxWalker
.
public class FsVisitor : CSharpSyntaxWalker
{
public override void VisitUsingDirective(UsingDirectiveSyntax node)
{
PrintLn("open {0}", node.Name);
}
public override void VisitClassDeclaration(ClassDeclarationSyntax node)
{
PrintLn("type {0} =", node.Identifier);
Enter();
base.VisitClassDeclaration(node);
Exit();
}
public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
{
var isStatic = node.Modifiers.Any(t => t.ValueText == "static");
var modifiers = String.Join(" ", node.Modifiers);
PrintLn("{0}{1} ({2}) = ",
isStatic ? $"{modifiers} member " : $"member {modifiers} this.",
node.Identifier,
String.Join(", ", node.ParameterList.Parameters.Select(p => $"{p.Identifier} : {p.Type}")));
Enter();
base.VisitMethodDeclaration(node);
Exit();
}
public override void VisitInvocationExpression(InvocationExpressionSyntax node)
{
PrintLn("{0}", node);
base.VisitInvocationExpression(node);
}
private StringBuilder builder = new StringBuilder();
private int intendLevel = 0;
void Enter() => intendLevel++;
void Exit() => intendLevel--;
void Print(string format, params object[] args)
{
if (format == null) return;
builder.Append('\t', intendLevel);
builder.AppendFormat(format, args);
}
void PrintLn(string format = default, params object[] args)
{
Print(format, args);
builder.AppendLine();
}
public override string ToString() => builder.ToString();
}
I tried it with a simple C# program:
var code =
@"
using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine(""Hello World"");
Console.ReadKey();
}
private void SayHello()
{
Console.WriteLine(""Hello"");
}
}";
var visitor = new FsVisitor();
visitor.Visit(CSharpSyntaxTree.ParseText(code).GetCompilationUnitRoot());
Console.WriteLine(visitor.ToString());
Output:
open System
type Program =
static member Main (args : string[]) =
Console.WriteLine("Hello World")
Console.ReadKey()
member private this.SayHello () =
Console.WriteLine("Hello")
Of course, the output is for a trivial program. It would take a lot more work to support a reasonable conversion, but maybe the conversion doesn't have to be perfect. Maybe if it gets you the scaffold, you could probably fill it in yourself in idiomatic F#.
And as always in automation:
Upvotes: 4
Reputation: 63772
Idiomatic F# code uses different types, approaches and structure. There isn't much to gain from "decompiling" C#-generated IL to F#, especially when you consider that you can interface with C# code quite easily. To make things worse, decompiling anything makes you lose lots of information - names of locals, constants, comments all sort of mangling. It's not impossible, but you're wasting lots of effort rebuilding something that is an intermediate step anyway.
Break your C# code into parts that you can slowly replace with F# code. This way, you have a chance of producing good F# code, and incrementally replace everything as needed. Do not start writing anything from scratch - keep as much of the old code as possible, and only change what needs to be changed to improve the interfacing with the F# code.
C# is already quite a "functional-capable" language - not quite as neat and expressive as F#, but there's very few things you can do in F# but not in C# in a reasonably simple way. This means incrementally changing over to functional style isn't as difficult as it might sound - and it's work you can't avoid anyway, if your goal is (for some reason; I hope you have an actual goal as well, and this is just an intermediate step :) functional code.
Upvotes: 9