Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mixed Language Build in One Project #21024

Closed
AlexanderMorou opened this issue Jul 21, 2017 · 47 comments
Closed

Mixed Language Build in One Project #21024

AlexanderMorou opened this issue Jul 21, 2017 · 47 comments

Comments

@AlexanderMorou
Copy link

Mixed Language Build in One Project

It would be nice to be able to construct a project within Visual Studio which enables the user to mix and match between C#, Visual Basic .NET, F# and MSIL (CIL).

Today C# already uses a DSL that has its own build step: WPF's XAML.

The main boon behind the feature would enable the VB-only features to be used in C# and vice-versa. Were this build-step approach generalized, you could even enable people to introduce MSIL (or CIL) directly to give you access to behaviors that are otherwise impossible (generics with an Enum constraint, for instance, or the XML Literals of VB.NET)

Possible Approach
Notice: I have not dug deep into the internals of the Roslyn code base, so this may be infeasible from the onset due to the work necessary to introduce it
A majority of the feature could rely on the notion that it's all CIL (+MZ-PE-COFF/ELF/PEF) in the end. So if you were adding a .vb file to a C# project, it could work in a few steps (I'm simplifying here, because there's, in reality, way too many steps!):

  1. VB/C# compiler validates the code is correct and free of any errors, syntactically, semantically or otherwise.
  2. Once it's verified, you can safely generate the IL that would be representative of the code
    a. This would need to work synchronously with the project's main language IL Generator to ensure that the IL for a specific class is fully present
    b. This is the cleanest way for it to work and allow partials in both languages to write the same class.
    c. Allowing partials would simplify mixing in constraints or other behaviors that you couldn't otherwise do in either language.

Caveat Emptor

This would still require a 'Primary Language' as part of the project. This is due to the differences in the private implementation details between the two languages (A C# project would likely not have any need of the My namespace, but may want to leverage XML literals without having to worry about the C# team saying 'Over my dead body' about the feature.)

F#'s paradigm is vastly different, I could see people being more willing to dabble in something wildly different if it's closer to home.

Were CIL to be directly allowed I suspect it could be abused; however, same thing applies to pointer logic in C# (and everything in C++? :) Perhaps were this to even be considered you'd need to apply the project language's member access rules to the CIL.

For me, the driving force for something like this is the ability to do one-offs that would hasten development without having to drop a wholly new project into the solution to test or introduce a single behavior or bit of data.

@paul1956
Copy link
Contributor

I would love this, an important benefit missing is the ability to have a shared project with VB, F# or something else providing the common code. Imaging a Xamarin UI with VB.net business layer or a VB.Net UI on Windows with Xamarin Forms on IOS and Android and business laying in whatever is appropriate. When I first saw shared projects this is what I expected to work.

@AdamSpeight2008
Copy link
Contributor

Why do we require a primary language?
Could we not have a "new" project class .net project that delegates parsing and compilation to the respective compilers? If the compilers are available via a compatible nuget package, we could import them.

MyDotNetProject.net
  + CS_Part.cs
  + VB_Part.vb
  + FS_Part.fs
  + Boo_Part.boo
  + CIL_Part.cil
  + IL_Part.il

I there a notation of a partial compilation in .net? Otherwise we'll run into a chicken and egg problem, how reference parts written in other language. Without introducing loads of errors.

@AlexanderMorou
Copy link
Author

The notion of 'Primary Language' is due to the fact that C# projects behave a certain way in their project configuration. Each language's project properties appears geared towards the language itself, I think this needs retained to make the most sense.

As for whether there's a preexisting notion of partial compilation in .NET that's more for someone on the Roslyn team to answer. It would be a necessity for the notion of sharing a partial class between languages.

I suspect whatever this feature would be, were it plausible, would be limited to Microsoft's core languages? I suspect it wouldn't be easy (maybe not even desirable) to enable introducing 3rd party languages.

@HaloFour
Copy link

I believe this was brought up on the Roslyn codeplex site before. From what I recall the project was never designed for this and thus it wouldn't be possible without a substantial rewrite. While there are some shared bits the C# and VB.NET compilers are largely self-contained and neither understands the syntax nodes of the other.

@jaredpar
Copy link
Member

I believe this was brought up on the Roslyn codeplex site before. From what I recall the project was never designed for this and thus it wouldn't be possible without a substantial rewrite

The problem extends far past Roslyn. It has implications for the project system, debugger, etc ... Basically most of the major features of Visual Studio for which there is an assumption of one language per project.

Overall my reaction is that this is a very high cost feature that has benefits to a very small set of customers. Also there is an existing pipeline that can simulate this today:

  • Have a set of independent projects written in different languages.
  • Use ILMerge to produce a final single assembly.

@paul1956
Copy link
Contributor

paul1956 commented Jul 31, 2017

@jaredpar I don't understand your solution. If I write a function in C# in one project and reference it in a VB project how does the reference get resolved so the solution compiles? Today using shared projects things just work as long as everything is in the same language. I write UI for Android, Windows and iOS in C# then put business logic and other common code into the shared project. If I want to use VB for shared code because I already have it, it doesn't work.

@HaloFour
Copy link

@paul1956

You've always been able to reference a C# project from a VB.NET project and vice versa. You can mix pretty much any CLR language together in this fashion, but each project will result in its own separate assembly (dll or exe). What @jaredpar is referring to is taking those individual assemblies and feeding them to ILMerge to produce a single assembly.

That said, using a language like VB.NET on iOS/Android might pose a separate set of issues since VB.NET requires its own assemblies on top of what the BCL provides (Microsoft.VisualBasic.dll). If that assembly isn't available on a particular platform then you might not be able to use that language on that platform either. Although, you should be able to theoretically merge that assembly with the others as well.

@seriussoft
Copy link

seriussoft commented Jan 25, 2018

Concurrence and Story

For me, the driving force for something like this is the ability to do one-offs that would hasten development without having to drop a wholly new project into the solution to test or introduce a single behavior or bit of data.

I second the ability to mix/match. There are features that as a C# first developer (as in I lean more heavily on C# because it was my first modern language alongside PHP outside of BASIC, QBASIC, VB6/VBA/TI-BASIC/Old-JS/etc) of many self-taught modern languages while going through school to learn the basics of C++/Java).

Sorry...this will be tad long, so you may want some coffee... but I wanted to share a situation I'm in now and remind some of the people in this discussion that when weighing the user-base that would be helped by a feature, it's worthwhile to ask about who it might help. Many times I've seen a new feature request come through that seems to target a very tiny niche but upon asking around other colleagues in the field and taking into consideration projects I've undertaken and companies I've worked for in the past: the feature seems to target a larger client base than it would have seemed at first.

I've included a TLDR; at the end that summarizes my points and a clickable TOC to help y'all out getting around it...

TOC

Anyways, I am currently working on a project that is old and relies on some antiquated and not-supported features of the older ASP.NET WebForms and VB.NET paradigms causing significant penalties to speed and literally preventing the web app from running on a host or machine past Windows 7.

The Accident that Shouldn't Be Possible?!

The problem extends far past Roslyn. It has implications for the project system, debugger, etc ... Basically most of the major features of Visual Studio for which there is an assumption of one language per project.

Part of the process to migrate over to MVC.NET v5.x involved dropping the existing files into a special directory of a newly created MVC.NET project targeting C# and .NET 4.7.0. The plan was to convert everything over to C# as I ported to MVC.NET from ASP.NET/WebForms piece-meal. Following Scott Hanselman's post, I discovered I could mix/match from the get-go allowing a simpler migration and running both at the same time. I accidently hit the run-with-debugger-attached hotkey while I was in process of copying the code over to a C# file behind one aspx page that was not even linked up to the aspx page itself yet... and to my wondering eyes did appear, but a chrome tab loading up the aspx page in question (i'd already added the extra routing so MVC controllers wouldn't stomp over it).

The MVC.NET project targeting C# and .NET 4.7.0 was both compiling the necessary page, loading up the debugger to the page, and not complaining about the already compiled controllers, routing manager, and models written in C#.

Shared Projects?

When I first saw shared projects this is what I expected to work.

I honestly thought this was the route we were going when shared projects were introduced due to the way that compiling of the projects using it were concerned. Under the hood, there are features that C# have and VB.NET don't and visa versa, but the MSIL underneath doesn't care and apparently in this instance, the debugger, IIS, and appropriate System.Web code base doesn't seem to mind when supporting a "compile only what you need" paradigm.

Benefiting the Not-So Niche

So, in favor of the proposition, I can see that there would be some hoops of fire and more to go through, BUT, as mentioned above, it would give support to those folk who desire features in both languages but don't want to add ONE more project every time they need a certain feature like XML->LINQ or even just the concept of XML Literals (for instance). This also serves a greater client base than JUST those doing quick feature additions or minor tweaks to test out new feature ideas. It ALSO helps those who are in the middle of a conversion process when migrating in older code or code that doesn't match what you are most familiar with.

I know some will say "why are you changing the language", but as a contractor who would have to support this project for several years, because the project is currently shut down and non-functional, because there's a complete migration already underway for a small-to-midsized web app that will grow significantly over time, and because the time-saving that will be earned over the next 3 weeks is significant compared to the time lost, it just makes sense.

I think that were it plausible to do something like this, and it feels like it just might be given what it can already do today: even if it were limited to certain subsets of project types for a test/trial run such as web, console/library, and/or universal-windows-app; you may find that the ends both justify the means AND have the potential to bring .NET framework into a new era. Afterall, once compiled to MSIL, everything is treated nearly the same (aside from VB.NET dependencies above and beyond the BCL such as: (Microsoft.VisualBasic.dll) and cares much less about where the bits came from - so why can't that be considered a worthwhile proposition: Bringing the major/primary languages of the .NET family of languages into a new light where they can work together like scripts do just as they work together like binaries?

Lastly, before I summarize, I don't think that the current system of treating all CORE languages in the .NET family as separate entities and not even part of the same family until they undergo sharing of blood or spit in a handshake after the compilation process is a fair or realistic solution.

Also there is an existing pipeline that can simulate this today:

  • Have a set of independent projects written in different languages.
  • Use ILMerge to produce a final single assembly.

Use of ILMerge against many/few libraries build from separate languages to produce a final product that is smaller (less files) isn't even solving the problem - instead it's adding complexity to solve a problem that isn't even being brought up. The problem isn't that one has to have multiple libraries, nor that one has to reference a bunch of them, or even that one might be cognizant of what is the underlying tech of each library when developing against them. The set of independent projects is part of the problem we are trying to resolve because it convulutes the code base, complicates the dependency chain, and makes solutions that were otherwise affordable or quick into something that needs even more testing, preparation, and OKs from our bosses' boss - not likely because we can't even prove it's efficacy because one has to do it all to see it work at all before proposing the change...

The Big Problem Broken Down

The big problem is that many of us need the ability to mix and match languages within a not-yet-compiled project to provide the following benefits (but not limited to just these benefits - others may chime in to append):

  • Simplify a standard problem set we deal with regularly
  • Allow us to take advantage of the final product of the .NET family of languages working together towards a single endpoint with all the features available and not just limited to some of them
  • Truly feel like you are working in a framework and family of languages and not in a language that happens to talk to the same underlying bits as another language
  • Learn how to use the best tool for the job in an environment where many businesses don't allow picking up the right tool because they see it as requiring the storage of multiple toolboxes and take on some concept of responsibility instead of trusting the professional developers they picked for the job
  • Remove the middleman, compiler(s), from the list of limitations when developing your project and rely on the compiler(s) to do what its made to do and turn it into a positive situation instead of a downer...
  • Much much more that I'm not going to go down a Rabbit Hole in Wonderland explaining in this already too long of a comment...

ILMerge Intended to Simplify Deployment, Installation, and Runtime/Client Needs, not Dev Needs...

ILMerge complicates the process as does having separate compiled projects - we are told by MS to lean more on dependencies of not-yet-compiled projects in our solutions to ensure less dependency fallout - building them all in a solution, then ILMerging them into a single assembly, then adding that as a reference in our core exe code that will point to the convoluded ILMerged assembly now requires us to jump through burning rings of fire to use our tools...ILMerge is just one extra step that doesn't accomplish anything for this problem. Separate projects with code in each that is of separate origin (VB.NET or C#.NET) is already too complicated - it makes a struggle out of code-reuse and refactoring as well as stripping our ability to maintain paradigms such as MVC, MVP, MVVM, etc by making us think more about where the code goes and how to separate them but still let them talk and reuse code and not rewrite the same code over and over again. It creates more problems than it solves and is why this is being brought up to begin with.

The **WHY**

WHY this problem needs solved is due to the desire for clean code, sensible code, and realistic code:

  • Use code across the language barriers in the same project or solution
  • Not add complexity, circular dependencies, or have to rewrite code in two different languages
  • Allow me to take full advantage of VB.NET features in a C# project or C# features in a VB.NET project while letting one separate paradigms and functionality by what it does and what it's purpose is rather than what language it's written in.

TLDR;

Already partway there!

The problem extends far past Roslyn. It has implications for the project system, debugger, etc ... Basically most of the major features of Visual Studio for which there is an assumption of one language per project.

I can already do this in an MVC.NET 5.X project (I'm using C#.NET as the primary language, the C# compiler that comes with VS 2017-v15.5.4, the VB.NET compiler that comes with VS 2017-v15.5.4, and .NET 4.7.02556). I know that the MVC site isn't building the full thing and running but rather building the controllers, routers, and core code, then only the aspx pages I'm needing at the time; however, that means that with my debugger attached and working - we are ALREADY partway there and not as far off as it may sound from the outside looking in...

Situation Summary

My current situation is that, to save money/time for a client now and later: I'm converting an antiquated and dysfunctional ASP.NET-4.0/WebForms+SQL-Membership website into an MVC.NET-5.X Website inline (aspx pages, vb.net codebehind dropped into a brand new MVC.NET/C# project and converting page by page with special routing to bypass the controllers for the aspx pages) This helps me to resolve issues with SQL-Membership, poor DB relationships, code-copy_and_pasted_everywhere-galore, limitations of using an older database file hardlinked to the SQL-Membership that I've no control over, over-complications that would arise when trying to update to work with a cleaner UI for both mobile AND desktop (currently is a narrow column that sits in the middle or right of the screen on non CRT monitors and is unusable on mobile), dysfunctional paypal integration, and locked into traditional email users with non-user-friendly UI constraints in form inputs that are out of my control - once again, thank you SQL-Membership...

Not so Niche Summary

Overall my reaction is that this is a very high cost feature that has benefits to a very small set of customers. Also there is an existing pipeline that can simulate this today

I'll explain below, but I feel that the market for this, while not likely affecting the Fortune 500 companies with their large projects, is not quite as niche as it may appear at the get-go - there's all sorts of situations and even Company IT/Dev Teams and Contractors who could benefit greatly from this as they don't follow the "Microsoft" way of doing things or the "Google" way of doing things - I could see this being of the level of benefit as the shared projects, LINQ/Lambda functionality, Extension Method feature, and even more effective and game changing than many of the items slated for .NET 4.6, 4.6.1, 4.6.2, 4.7, and 4.7.1. It would encroach (likely) on the VB.NET compiler team and C# Compiler team to some extent - but not to the point of requiring them to go against their beliefs or self-mandated-standards - but rather to add some hooks and supply the .different NET teams with dependency requirements and the likes. Take a look at MVC.NET (and I'm guessing here, but wouldn't be surprised if it's supported in ASP.NET/WebForms and WebAPI.NET projects as well due to the similarities behind all 3 project types and the underlying shared engines [i know that WebAPI.NET is an outlier here due to not being as integrated as the other two are into System.Web and the base rendering engines]).

Who this could help

I suspect whatever this feature would be, were it plausible, would be limited to Microsoft's core languages? I suspect it wouldn't be easy (maybe not even desirable) to enable introducing 3rd party languages.

Let's assume I'm referring to the core C#.NET, VB.NET, F#.NET, and POSSIBLY MSIL and J#.NET**...FOR NOW...**:

  1. Conversion of older projects to newer projects/codebases/frameworks
  2. Quick feature/PoC(ProofOfConcept)/tweak/hack modifications that would be replaced with the full deal once it was proven
  3. Individuals wanting to learn another language while sitting comfortably in the net of their preferred language
  4. Individuals trying to save time by taking advantage of a language they are more familiar with or prefer to work with while not having to force a complete conversion
  5. Individuals wanting to take advantage of features only found in one language while not losing the advantages and features in their preferred language
  6. Contractors who are faced with older projects that were left behind unfinished or broken by unnamed developers before them
  7. Schools that thankfully buy into Visual Studio, .NET, ASP.NET, or even .NET CORE instead of JUST teaching JS/C++.OLD/16bit-ASM/Java
  8. Projects shared by developers that only know 1 of the 2 languages (I've worked at shops with devs that only know vb6, were learning vb.net and the shop itself was primarily a c++/c# shop)
  9. Devs and SO frequent answerers who try to help individuals in both languages across SO or trying to determine the underlying MSIL of both for comparison's purposes
  10. ??? I'm sure there are others I'm missing or forgetting - The point of this was to suggest to others that before you count up the people you think it would help, consider asking around to see what other possible clients could benefit from this, the likelyhood that more good things could follow, does it appeal to any of the longstanding goals of .NET, && could it benefit .NET and its family of languages in the future?

@HaloFour
Copy link

@seriussoft

IIRC the only reason it works with ASP.NET WebForms with inline code is that:

  1. The code is compiled on demand at runtime.
  2. The nature of the project creates very strict demarcation between each individual view and any dependency classes. One compiled-on-demand view cannot rely on another compiled-on-demand view.

As such the compiler is only ever dealing with small individual "projects" without any concerns with cross-dependencies. That is a very unique situation and unlike any other "normal" project where the source files have access to every other type/member/etc. declared in any other source file.

@seriussoft
Copy link

@HaloFour

Thanks for offering your insights into why it works. They align with my guesses based on knowledge that hasn't stirred in a while (I've not been focuses on ASP.NET projects in a while).

Yeah, I'm sure it has to do with the order of building, separation of concerns, and limiting building to multiple actions instead of a run-and-gun approach such that the VB.NET and C#.NET code bases don't cross eachother.

However, my mention was mostly to make the point that it's not a Visual Studio limitation, as someone mentioned above, is not a limitation of the compiler to have more than one language in a project.

Rather, the limitation is involved solely in the compilation layer and mostly has to do with order of operation, separation of code, and things of that nature. IIRC, you couldn't even throw a VB.NET file into a C# asp.net/webforms project back in VS 2010 where my acquired site came from.

That said, it is still my belief, based on the fact that the compiler can stripe the individual files out separately into their own build-able "zones" if you will or "projects" like referred to them above:

  • that there is hope and feasibility behind this feature request. Obviously there's going to be some uphill climbing with such a change, but it's not like LINQ, extension methods, async magic, or similar amazing features were free or acquired with minimal effort, either. I think that given some limitations of scope and hammering a few ideas out, that there's something great that could happen.

I've personally considered doing something similar by means of creating an interpreter that could read pieces of a single code file, convert it to appropriate IL code, and then merge it into the C# built code files after the fact. My route would involve the creation of a compiler that you can attach to a file using the property window, a code highlighter to pick up the text in your csharp file for easier reading/manipulation, and then hide said lines behind a string or pre-compiler/directive not too different from how one can have sql code directly inside of a ruby file using a prefix and suffix.

My route is convuluted and really is meant for adding a DSL within a C# file and using Roslyn and my own lexer for having the DSL use syntax not valid in C#.

If it's possible to create a solution like that, then it would seem appropriate to consider if it would be possible for the .NET teams to come up with an equally functional, but more built-in solution that requires less work, config, and manual integration when scope is limited. Again, this is just my 2 cents, but I've seen this work before - There's a Razor-to-CS compiler you can use by attaching to the code file in the properties window. it then creates a class file that you can consume in your own code. As soon as you leave the file OR hit the compile/debug button in VS, it will force a compile of the file if any changes are detected BEFORE allowing the regular compilation process to begin. Mix that with tools that compile files as soon as changes are detected and only the files with changes and some kind of interface-like macrocosm concept for each file to be "separate" from each other (where each file represents an interface of sorts for communicating back and forth with). Again, just throwing things out there - the idea of mix-and-match seems awesome and worth the effort if enough people can justify it.

Thanks again for sharing and keeping things professional - I know it can be hard to maintain that when talking about things that can be as big and expensive sounding as something like this.

@AlexanderMorou
Copy link
Author

I wonder if it would be possible to greatly simplify this by the Roslyn team creating and maintaining a cross-language converter.

I recall some of the earlier samples with Roslyn showing off a very simple C#->VB or VB->C# converter.

If we had an official tool that triggered this on a given file, it could, upon detecting changes to the mix-in file, translate it into the proper language (familiar with how build tools add a dependent file underneath the file with a tool applied? It'd be like MyVb.vb => MyVB.cs)

One major down side is it would eliminate the ability to do CIL: if you wanted an Enum constraint on a type-parameter, you'd be SoL. The other major issue is you'd lose all intellisense feedback, unless you were viewing the generated file.

It'd be great if they could build the ability to cross-languages in a single solution: while it'd be difficult, for people trying to write their own languages it would be a nice segway into giving a proof of concept without the need to build an entire project type, templates, and related files.

@paul1956
Copy link
Contributor

The main reason to mix code (at least for me) is that no translator can translate perfectly and VB has no equivalent of some C# features, unchecked and unsafe are just a few examples, don't know about VB to C#. If I could get a few key C# library functions like Roslyn's gethash (which uses some of the missing features) available for VB then this feature would be less important. Right now I have one C# project in every VB solution that I use to hold routines I need but can't translate.

@seriussoft
Copy link

seriussoft commented Jan 31, 2018

@paul1956 , @AlexanderMorou

I second that stopping at JUST a converter would not serve most of the use-cases I've collected from friends and colleagues. Being able to even the scales for those wanting features from both language-sets would likely be able to get by with a converter if it were done at time-of-compile (instead of a one-off deal) and if there were some limitations such as if you reference the vb.net code from c#, then your vb.net code cannot reference c# might strike that balance of functionality-for-clients vs likelihood-of-initiating-and-completing on the end of the team(s) that would have to implement this.

I'm wondering if implementing it in the block of a "shared project" would allow it to be functional, save many of us lots of time in the long run, and still make it feasible - IIRC, there are similar stipulations in shared-projects so far as how they can be used. In that manner, it might limit the entry-points and exit-points enough that it becomes a more likely feature. The advantage being that it's not a full project with dll's in the sens of how it's built and utilized as the projects that use it build the code themselves into their own libraries, correct? I just wonder if there's someway to take advantage of an existing stack to get started on the feature so it's not a huge rebuild or monumental expense (some kind of container concept to isolate the code for the sake of the compiler while not feeling so isolated for those of us that would use it to get around problems stemming from being unable to separate the vb.net code from c# code in their own projects right now and still produce products that meet our needs and expectations. Whether that container is a "shared project", some kind of stripe like is done for asp.net vb.net webforms thrown into a c# mvc.net project, or even applying the region/area concept of .net websites (where an area dictates the purpose, code-paths, authentication-roles, etc of all assets and pages in said area) but instead to limit the scope of build for the compiler.

At this point, just shooting in the dark hoping something sounds less daunting. Not sure that having a one-off compiler, even if managed by the Roslyn team, would be enough - having it compile just before the compiler runs for the rest of the project(s) and after each change you make to it - say to MSIL such that your main project language sees it as a library and you see it as code - I wonder if that could work?! Naturally circular dependencies would break just like normal, but if there's a way for the compiler to see it as already written and compiled by a Roslyn intelligent compilation action and thenas you make changes to it, said changes are picked up. Your typical intellisense could then be maintained along with any XmlComment intellisense...

I really think that taking that idea that came from the Razor-Single-Page-Generator/RazorGenerator VS addins and paring it with @AlexanderMorou 's idea of a Roslyn/VB.NET/C# team maintained "converter" and THEN making it run after changes to the non-matching code-files would then allow the regular compilation to consume the compiled bits thereby limiting exits/re-entry points considerably while still allowing intellisense, full language functionality per @paul1956 , remove the necessity for separate projects, and pave the way for other languages being supported (such as IL for when you need to do something a step beyond what is supported in C#/VB.NET like mentioned by @AlexanderMorou ) in the future once this has amounted fans and supporters.

Check out:

Edit:
I believe after re-reading the OP, it appears that the last suggestion in this comment very closely relates to what was originally suggested, just with a little bit of detail added on the dimension of time and ordering of operation.

SORRY, just one more edit crosses fingers:
I read a post about the use of T4 templating to produce a file that lives "underneath" the template and is then what is read - so what if that's what happens? The .vb code file (in a c# primary project) gets converted into appropriate C# code with strings or something else to supply IL code to the Roslyn API for mixing in at final build-time. Everytime a change is made to the .vb code file, it triggers the conversion for the .cs code file "underneath" it such that the dev sees only the code they are writing in vb.net and the compiler that builds the final project state will read the .cs underlying files when a .vb file is present?

To illustrate better with the words of someone who has talked about the concept on his blog, see:

@CyrusNajmabadi
Copy link
Member

I wonder if it would be possible to greatly simplify this by the Roslyn team creating and maintaining a cross-language converter.

It woudl certainly simplify things for you :) But it would also add enormous cost to Roslyn :D

I wrote the original cross language converter sample. I wrote it to make porting over code from both languages easier. But it clearly became apparent that even with perfect info, porting over everything with correct semantics was likely never going to be possible. If you want to write this yourself, go ahead :)

@paul1956
Copy link
Contributor

paul1956 commented Feb 4, 2018

@CyrusNajmabadi working on it but it is going to need to be a cooperative effort, VB needs a few key features that would benefit the language and translation. I am learning some have been added but I didn't know they were there, some are "planned" like slice and some like unchecked need to be added. It will never be 100% but I think a converters will be usable. Adding the ability to include some c# code inline might enable 100% "translation".

@seriussoft
Copy link

seriussoft commented Mar 3, 2018

@paul1956 by inline, do you mean allowing c# code to be:

  1. inlined within a vb.net code file and then referred to from code directly
  2. inlined within a vb.net code file and then treated like dynamic in that no checks are made at design-time
  3. inlined within a vb.net code file as a string or text blob that can be programmatically run through the Roslyn API?
  4. some other meaning?

Also, in reference to the missing features:

  1. Could you share a list of the known missing features you refer to?
    1. (for instance, most of VB.NET's LInQ-to-XML syntax can be translated directly to LInQ-to-Xml using XElements)
  2. Does it seem possible that said missing features could be created as either extension methods, classes, and/or additional libraries in vb.net or c# to be directly called from VB.NET?
    1. Or are there fundamental issues that are syntactical or special in nature and would therefore require a considerable effort to mimic from the VB.NET side from your opinion?

As C# and VB.NET are both syntactically different, certain candy has no direct translation but can be mimicked with more effort and the use of a "Rosetta Stone" library in either language to offer up missing features programmatically. Which is where this idea would help others wanting to avoid the extra effort every single time they want to do something in a project that is better suited for a language that is NOT the primary language of the project.

The question is, though, how many of these discrepancies would require access to internals of the VB.NET's special library to implement such a translation aide and visa versa for VB.NET translation to a C#.NET project?

If there's a way to help, I offer my services as I've worked extensively in C# but have had a few jobs (and contracts) where VB.NET was the primary or only development language - so I'd be excited to share my experiences and skills with y'all if it'd potentially bring us developers closer to such a feature in the .NET realm. 😄

@paul1956
Copy link
Contributor

paul1956 commented Mar 3, 2018

@seriussoft I have not given any though as to how it should work except on a statement by statement basis when I run into something I can't translate today I wrap it in a comment and add a TODO and some text about what the issue is.

I started with the 2 or 3 open source Roslyn Translators and I have managed to get a translator almost complete including "most comments", enough to translate large parts of Roslyn and compile them without syntax errors. It is written entirely in VB except for a small helper library written in C# and taken directly from Roslyn source to handle Hash and related special types that use unsafe code (why Hash isn't public is a mystery to me). The translated code doesn't all run because there are lots of place where I detect unsupported features and just comment them out, and let the user handle it. My goal is not to port Roslyn (Roslyn is my test case), I would like to see if I can get the entire VB compiler ported to VB just for fun.

The most difficult features to get in order of importance and difficulty are unchecked( very difficult to duplicate except for some trivial but useful cases that I can handle), Extern Alias (not that I even know what it is used for), Implicit Elements with more that one argument (again don't know what it is and don't think I have seen many use cases) and Linq group by clause without into (which with work I think I can get to work). Also imbedded comments which I covered in another issue, (I can move comments around but then the aren't necessarily in a useful or correct place but they aren't lost). I am also working on trying to preserve the formatting, C# seems to be a better job formatting bracketed code and once you start adding CRLF to VB source the Visual Studio formatter mostly ignores your code. As a side note there should be a way to tell VS please just format my code and undo all my manual formatting, for VB Edit/Advanced/Format Document usually does nothing.

For Unchecked I just want to be able to do what I show below, the problem today is this gives a compiler error BC30439 or overflows at runtime before I could even pass the arguments into a routine written in C#. This is similar to the reason that NameOf needs to be supported by the compiler and not a NameOf helper function.

Dim X as Byte
CSharp(uncheck(x = 7 * 100);)

or

Dim hashCode as Byte
' Assume other variables are also defined
CSharp(hashCode = unchecked((hashCode ^ data[i]) * CodeRefactoringHash.FnvPrime);)

I have not spent any time on VB to C# but I suspect there are not may issues requiring Compiler support.

I would be happy to share the code but so far my attempts to use GitHub on my own have not been successful and I can't add my changes easily back to the original projects because large parts of their code is in C# and all of my VB code used explicate typing and Option Strict. I have learned a lot about SeparatedLists and I might do a Stack Overflow article on them because most of what I found searching and all of the examples lose formatting and comments. I also have my own NormalizeWhiteSpaceEx(....PreserveCRLF) which allows me to preserve more of the formatting, I have seem a few example of using the Roslyn Formatter but don't find enough documentations to figure out how to get it to work and don't want to get involved in WorkSpaces yet.

@MaStr11
Copy link
Contributor

MaStr11 commented Mar 3, 2018

why Hash isn't public is a mystery to me

It is part of .Net Core now. If you want the team to make it available as Nuget package on other frameworks to you may want to vote for it here dotnet/corefx#26412

@svick
Copy link
Contributor

svick commented Mar 3, 2018

@paul1956

For Unchecked I just want to be able to do what I show below, the problem today is this gives a compiler error BC30439 or overflows at runtime before I could even pass the arguments into a routine written in C#.

[…]

Dim hashCode as Byte
' Assume other variables are also defined
CSharp(hashCode = unchecked((hashCode ^ data[i]) * CodeRefactoringHash.FnvPrime);)

You can get pretty close to that using Roslyn Scripting. For example, it could look like this (full code):

hashCode = CSharp(Of Byte, Byte(), Integer, Byte)(
    "(hashCode, data, i) => unchecked((byte)((hashCode ^ data[i]) * 0x100000001b3))",
    hashCode, data, 0)

It has issues (verbosity, performance, references), but you can use it today, instead of waiting for a CSharp operator, which is unlikely to ever happen.

@paul1956
Copy link
Contributor

paul1956 commented Mar 3, 2018

@MaStr11 I am targeting .Net Standard 2.0 (Is this the same as Core?) so, how are we to track when things move from Roslyn to Core?

@svick Looks like a potential solution, thanks. I assume I would need to build a custom script for every use of unchecked and deal with constants that today produce compile time errors.

@MaStr11
Copy link
Contributor

MaStr11 commented Mar 3, 2018

@svick and @paul1956

There is a merged PR #24161 (I don't think it is already shipped) that generates good general purpose hash algorithms for C# and VB (it's worth a read as there are good alternatives as e.g. using tuples as hash combiner). It even considers the circumstance that VB lacks checked. An example of the generated code can be found here.

I am targeting .Net Standard 2.0

I assume you are asking for the availability of System.Hashcode. It is only available in the.net core framework. This framework is the younger small brother of the big .net framework. It is cross platform and supports console apps and asp.net only. From the developer point of view it has about the same API as the big framework or other frameworks such as mono. .net standard is a description of these APIs. .net standard defines about 20.000 methods. A framework is compatible to .net standard if it implements all these methods. System.Hashcode is not part of .net standard but I was thinking about asking Microsoft to consider adding it (see dotnet/corefx#2641). It is unknown whether System.Hashcode will be part of a future .net Framework release (the big, windows only one).

@paul1956
Copy link
Contributor

paul1956 commented Mar 4, 2018

@MaStr11 and @svick the Hash I am referring to is (as of 2.6.1) found in roslyn-master\src\Compilers\Core\Portable\InternalUtilities\Hash.cs it is referenced 100's of times from VB code and 1,000's indirectly and 20+ times in my translator, It is internal so I needed to port it or include the C# version in its own project, right now I chose the later. I don't know if a generic Hash routine would replace it, to me it is black box required by higher level VB functions that I use.

@ghost
Copy link

ghost commented May 16, 2018

@paul1956
You can use roslyn ScriptEngine class to excute or evaluate C# code. More details here:
http://blogs.msdn.com/b/csharpfaq/archive/2011/12/02/introduction-to-the-roslyn-scripting-api.aspx

You can also use this C# Eval library to evaluate C# code in VB.NET projects:
https://web.archive.org/web/20170718133154/http://csharp-eval.com/

I don't have time now to test them. Please give me a feedback if you used them.

@seriussoft
Copy link

@MohammadHamdyGhanem
IIRC, the roslyn ScriptEngine cannot process code that depends on context, though, right? I'm aware of the ability to read IL code from a string and assign it to a "Dynamic Method" whether that's an instance method for an already built class inside of a specific module/assembly OR living in it's own little domain.

Is the Roslyn ScriptEngine execution/evaluation of C# code able to essentially do the same? ie. does it perform in a way whereby I can attach my C# script to an existing object or let it float out in the ether to be consumed by the code that is around it? If so, is this requiring reflection, use of dynamic to access it, or is it different? I perused through the example you provided to @paul1956 above, and comments indicate the examples are now broke - the article seems to suggest, however that while you can access anything on a host or "bag" object, it doesn't seem to support compiling and storing said code or instructions onto the host object for running at a later code segment.

I've used the eval function for Razor and ASP.NET WebForms in the days of ol' and it was always for running that code then in that context and taking in information and/or running functions that were in the background code-files. Most of what I have found from perusing around github and some search engine research leads me to believe that the majority of Roslyn's documented and open-source usage/scenarios involve code evaluation within the editor/IDE to complain about non-standardized coding schemes (such as improper capitalization, naming schemes, methods with more than one purpose, and similar tropes).

This makes me wonder if there's a way to take advantage of the code Roslyn can read, throw it at a compiler to get the IL code, pass it through the reflection.emitter, and then provide some mechanism for accessing your newly compiled code; albeit in a much easier manner than reflection normally allows.

This would almost altogether remove the necessity to know/understand MSIL instruction set, drop the major missing feature of dynamic scripting via Roslyn, and then provide a mechanism either for the Editor window to provide syntax highlighting OR provide a means for your dynamic code (or in our case, the C# scripts we want to access directly from our VB.NET code file) to be accessible from the outer code file(s).

I just don't see that there's a plausible way to get both options if the route ventured was use of Roslyn to combine the c# text in a string via the ScriptEngine itself. Should there be a way to utilize it for direct compilation of code and if it or a similar technology exists for compilation of the VB.NET side as well, then I'd be more than happy to explore and dig into it some more.

I still like the idea of separate code files and marking the alien files (cs files if in a vb.net project or vb.net files in a csharp project) as no-compile, then providing an external compiler or compiler wrapper. This buys us the option of porting code from one language to another while not digging into post/pre compile-time IL injection or some wizardry such as compiling to IL, injecting IL into a temp module, finishing up compile of project sans the errors, trying to add-in the alien code to resolve errors and porting.

@glenn-slayden
Copy link

glenn-slayden commented Sep 14, 2018

In case anyone is interested, I have a mixed C#/IL project working quite fine in vs2017 15.8.4--including Intellisense--with the latest Roslyn compiler, just by adding one fairly straightforward customized MSBuild .targets file. With the approach outlined below, the only IDE feature I've noticed not working right is that F12 "Goto Definition" won't navigate from C# across to IL, but other than that most DesignTime stuff seems to work great. Here are the highlights.


Note: don't be fooled by mentions of ".netmodule" below; this procedure is for producing a normal, single-file mixed language .NET assembly--not a .netmodule multi-file assembly!


Note: This is also not "yet-another" ILMerge hackfest.


  1. Create extern ... forward declarations for the IL methods you want to access from C# and attribute them with [MethodImpl(MethodImplOptions.ForwardRef)]. Using static methods in static classes is easiest, but it is also possible to split instance code across these languages (in which case C# will likely insist on implementing the __ctor). Put all those C# stubs in an #if IL block.

  2. Duplicate the stubs, now with throwing bodies, in an #else clause. This alternate set is for the F12 "Goto" landing target in the IDE, and also to ensure that Intellisense can successfully build the target, but don't worry, the code in this #else block of stubs will never be built into the actual assembly.

  3. At the end of your .csproj file, include a target which overrides the MSBuild-provided CoreCompile target to run csc.exe twice: once with /DefineConstants:$(DefineConstants);IL, /TargetType:Module, and /ModuleAssemblyName:$(TargetType), which produces a .netmodule, and then again using the normal (or original) .dll settings (.exe also works). The latter binary is used by DesignTime; have csc.exe put it in an alternate location. You can exclude managed resources from both of these csc builds: the concept is undefined for a .netmodule, and DesignTime might not need them in your binary.

  4. Using ILAsm, now assemble all your IL files, also into a single .netmodule. To get this type of output from ILAsm, just omit the assembly section from your IL source and alter the file extension.

  5. Prepare native Win32 resources: FILE_VERSION_INFO (mapping certain fields from AssemblyInfo.cs) and an assembly manifest, if necessary (for .exe). Create a simple .rc file with these two resources and run rc.exe and cvtres.exe to prepare an object module containing these.

  6. Use link.exe with the /LTCG command line option to fuse the two .netmodules--one each for the C# and IL--plus the Win32 resource obj. Also include any managed resources, using linker switch /assemblyresource for each.

  7. Substitute the linked binary as a CoreCompile product by propagating it to the MSBuild entity @(IntermediateAssembly)

As noted, the key is to enable the Link Time Code Generation (LTCG) feature in link.exe linker, whereby the venerable SDK tool will merge the IL from managed classes spread across disparate linker input sources, based on exact method-and-class-name identity, into a single class by taking method implementations from either or both, piecemeal-wise.

I spent a bunch of time "diffing" the assembly produced by these steps with its equivalent, built with completely-stock csc.exe/Roslyn-latest settings, in order to ensure that my result had the same CORFLAGS, PEHeader, etc., and was a fully correct and legitimate .NET binary. I did this for managed exe as well as dll targets. By understanding or accounting for any/all diffs, I converged on the following link.exe switch settings for producing modern managed assemblies. This was a bit painstaking, so someone might benefit from this info:

Condition="'$(DebugType)' == 'full'"
     /debug:full
     /editandcontinue
     
Condition="'$(DebugType)' == 'pdbonly'"
     /debug
     
Condition="'$(DebugType)' != 'full'"
     /opt:icf
     /opt:ref
     
Condition="'$(OutputType)' == 'Library'"
     /dll
     
Condition="'$(OutputType)' == 'Exe' or '$(OutputType)' == 'WinExe'"
     /entry:$(StartupObject).Main
     /tsaware
     
Always    
     /nologo
     /verbose
     /nodefaultlib
     /novcfeature
     /nocoffgrpinfo
     /osversion:4.0
     /subsystem:console,6.0
     /highentropyva
     /largeaddressaware
     /filealign:512
     /ltcg                     <-- this is the key
     /clrimagetype:safe        <-- use 'pure' if you want a PE32+
     /assemblyresource:my.bin  <-- managed resource(s) if any
     /pdb:my.pdb
     /out:@(IntermediateAssembly)

Sources:
    mytarget.cs.netmodule
    mytarget.il.netmodule
    ver-inf_manifest.obj       <-- via rc.exe/cvtres.exe

As an example of the kind of differences I methodically ran down, here's a collateral Roslyn "bug": when Roslyn creates a managed DLL it incorrectly sets the "Terminal Services Aware" bit; according to link.exe, who refuses to do the same, it is only semantically appropriate for EXEs.

More significantly perhaps, link places much more of the readonly data in non-execute memory pages. In any case, the non-Roslyn /LTCG-built assembly works just fine in several .NET scenarios I've tested with.

@glenn-slayden
Copy link

glenn-slayden commented Sep 15, 2018

Let me mention one more thing. Although I'm not totally sure, I believe that linking in a correct FILE_VERSION_INFO resource as described above may be mandatory. In particular, it's possible that numerous DesignTime issues I was experiencing in the IDE only went away at the moment when I correctly established these ancient text properties in the DLL or EXE. I'm especially suspicious of "InternalName", "OriginalFilename" and "Assembly Version" ... and note the space in the name of this last one (a Win32-unsanctioned property, btw). Pay attention to the very quirky mapping described in the StackOverflow link above. Refer/defer to the Roslyn result as your guide/arbitrator.

@seriussoft
Copy link

Hey there, @glenn-slayden , thanks for contributing! I've actually played around a little bit with ins0mniaque's ILSupport project and VS Extension that behaves very much like the Mixed C#/IL buildproject that you mentioned recreating above. It seems to be a very practical application of mixed projects and based on your explanation, as well your simplifying/summarizing the how & why for getting it done, does indeed add fire to the likelihood of this being the best option for getting a prototype out there.

GoToDefinition

So far as not being able to get the GoToDefinition to sync up (understandably), I've given some thought to how the extension could include a modifier to allow the lookup necessary to support GoToDefinition much in the same way that we currently support GoToDefinition for objects with a complex inheritance hierarchy. I've talked a bit with some of the folk who work on the Roslyn and C# compiler stuff behind the scenes and have a general direction and some things to avoid and/or look for. If you'd like, I can get you the discussion about that part of it (has some good "what not to do" bits in there to avoid thrashing the drive, memory, or CPU each time it's necessary to activate and generalized directions).

Moving Forward

Your notes will help with my attempts to emulate this process but from a C# with VB.NET and/or VB.NET with C# joint/mixed project types. I will likely be starting with C# as the Main or Native language and VB.NET as the Alien language (C# in your project is the Native and IL the Alien). You can see some of my notes in comments here: #26765 (it's a separate but same topic/feature-request with some info not found on this issue. The comment that aligns with your suggestions is found at: Issue: 26765 - "Allow Creating Mixed Language Projects" .

Questions

  1. Do you happen to have a gist or repo with an example of what you've got working so far?
  2. If so, do you mind making it available?
  3. Would you be interested in working jointly and/or helping test/drill/break things once there's a "viable product" or prototype going?

I'd love to dig in and compare what you've got to the ILSupport project to see what's different, necessary, missing, or bloat (the ILSupport project is fairly large compared to the instructions in your summary, so likely are things that aren't necessary in it and some things that handle problems not encountered yet).

This may help me to simplify the work necessary closer to what you've done, but also get the feature-set of the ILSupport that's had some time to get a little bit of a following and feature-set going over time.

Thanks again for your input and suggestions. Hope that this is a turning point! 🙏 🤞

Links:

@glenn-slayden
Copy link

@seriussoft Thanks for the reply. Here's the .target file as it stands; it's not too hard-coded to anything and works for me in vs2017 for mixing IL with EXE or DLL. Add it after the last import in the .csproj file. Set your IL items as <ILAsm>...</ILAsm>. Snoop around in it for more info.

Unfortunately right now I don't really have time to pursue this line of inquiry much further.

@glenn-slayden
Copy link

@seriussoft wrote:
...in your project [C#] is the "Native" and IL the "Alien"...

I really don't see it that way; I feel that a strength of the /LTCG approach, conceptually at least, is its equalizing nature, meaning, once gathered, each .netmodule in the set of linker inputs is an undistinguished peer where none is above another (perhaps modulo the /entry provision on .exe targets).

But perhaps you're referring to the IDE and MSBuild complications; it's true that my scheme is inherently and fundamentally based on a stock .csproj.

@seriussoft
Copy link

@glenn-slayden
Thanks for the share, I'm actually looking into it now. 😄

Thanks for your provided info and help, and I can respect that you are busy with projects and personal responsibilities already, so the offer will be still there on the table if you do decide you want to and have time, but no hard feelings if you are unable for whatever reasons. I'm really excited to see what comes of this! Thanks again for sharing.

@seriussoft
Copy link

@glenn-slayden wrote:
I really don't see it that way; I feel that a strength of the /LTCG approach, conceptually at least, is its equalizing nature, meaning, once gathered, each .netmodule in the set of linker inputs is an undistinguished peer where none is above another (perhaps modulo the /entry provision on .exe targets).

But perhaps you're referring to the IDE and MSBuild complications; it's true that my scheme is inherently and fundamentally based on a stock .csproj.

Yeah, your last bit was correct. I was referring not as 1st class and 2nd class citizens but rather in the context of the msbuild and visual studio projects, and setup which needs a project to actually have an owner or representative to initiate the process, some "which comes first, chicken or the egg" necessities, and to pick certain libs that are specific to said language as not all features exist in both languages (not for instance IL is not a subset of C# but rather C# offers a subset of what is available to IL and for where a lot of us would like to go, VB.NET and C# will continue to diverge so this will allow us to get best of many worlds without tanking the .NET ecosystem by requiring each language to retain parity with eachother), etc.

But mostly, in summary, the alien/native concept is purely technical in nature, not in the sense of the developer really needing to be all that cognizant of it nor it holding a flame to anything other than the grim reality of there being things outside our control with msbuild and VS (neither good nor bad, just is 😄 ).

With us having to have a starting project type (csproj, vbproj, etc, that was 99.9% what I mean by native and alien with the rest being stuff you either know already or can read about when digging into the differences between project types).

Would be awesome if one day there's a potential candidate for a combined project type that isn't csproj or vbproj but...something else entirely....vsjproj (VS Joint) for example? But gotta start somewhere, right?

@glenn-slayden
Copy link

glenn-slayden commented Sep 18, 2018

You are, I assume, fully aware of the new VSProjectSystem effort (here also), right? Does it help with your goals?

Would be awesome if one day there's a potential candidate for a combined project type that isn't csproj or vbproj but...something else entirely....vsjproj (VS Joint) for example?

Wouldn't that be what a vanilla MSBuild file, i.e. "from scratch," is or can/would be?

@seriussoft
Copy link

@glenn-slayden

Would be awesome if one day there's a potential candidate for a combined project type that isn't csproj or vbproj but...something else entirely....vsjproj (VS Joint) for example?

Wouldn't that be what a vanilla MSBuild file, i.e. "from scratch," is or can/would be?

yes, one day, i would love for vsproj to be not just a vanilla project with files and no real aim or underlying purpose besides hosting similar minded things, but also to support entries making it more custom and without requiring a separate project type such as vsjproj that i was half-hazardly offering up.

I think, though, that the idea of a vanilla project type that holds indicators and entry points for the external project types while still holding it's intended vanilla/agnostic purpose, could really be a great idea. (If you haven't noticed, I love to take people's ideas or comments and build upon them to see what possibilities abound). Anyways, that would let the vsproj be the meat and potatoes and the csproj, vbproj, and/or other *proj files being the necessary platform and language specifics - it has merit and could be a valid direction.

Like...the appconfig extensions. Are you familiar with how you can create app.config, dev.app.config, qa.app.config, prod.app.config, etc? How it utlizes xml transforms and some other xml black box magic (only black box til you get in and play with it) to allow one to have a single entry point with only the differences held in the respective dev, qa, prod, etc configs? this allows pre-build/post-build transforms and also allows for you to do your own transforms at a later date such as on the fly, during install, or even updates or side-by-side installs. we used it pretty heavily at one of my prior companies and it's a lifesave. I imagine that having a similar application for vsproj, csproj, vbproj, etc could yield a net gain with fair ROI for the effort that goes in. People like Scott Hanselman have already suggested using csproj and appconfig transforms for pre-build/post-build magic, especially when you are dealing with environment specific or situational problems at build/publish/runtime across multiple clients/environments.

There's some potential there, especially at this stage of conceptualizing, prototyping, and designing.

@seriussoft
Copy link

You are, I assume, fully aware of the new VSProjectSystem effort (here also), right? Does it help with your goals?

To answer your 1st question, though, I was unawares of this extension nor the efforts behind it. This one and another used for aiding creation of VS extensions could both prove useful aids here and later (the syntax highlighting, GoToDefinition, and a couple other secondary but important aspects will likely require a bit of extension magic for the prototype).

That project system extension could help quite a bit if it is what it purports to be. I've been considering other languages gaining the benefit of .NET like the iron languages did, and something like this and the c#+vb.net project type all aim towards this direction a bit. would also make those pesky projects where one normally depends on external assemblies (like when working on ImageMagick.NET dev) that could one day benefit from this issue as a whole. Just gotta get the ball rolling and the dominoes falling in the right directions.

Thanks for sharing.

@gafter
Copy link
Member

gafter commented Dec 5, 2018

The possibility of doing this was discussed early in the Roslyn design, as there would have been a significant investment at that time in order for Roslyn to be capable of working that way. But that would have been the time to start the work. We decided not to do it, and subsequently we designed the internals of the C# and VB compilers using separate data structures and algorithms. It is too late to reasonably change the design at this time - it would essentially require a deep redesign of much code that already exists. We have no plans to do that and I don't think we ever would.

@gafter gafter closed this as completed Dec 5, 2018
@VBAndCs
Copy link

VBAndCs commented Apr 7, 2019

This proposal may make it happen at some scale: #34821

@dancojocaru2000
Copy link

This has been one of my major disappointments with .NET.

In the Java world, you can have Java, Kotlin and Scala in the same project.

.NET feels less like an integrated family of languages and more like a Foreign Function Interface kind of deal without having to write the glue code.

@HaloFour
Copy link

@dancojocaru2000

In the Java world, you can have Java, Kotlin and Scala in the same project.

This is admittedly pretty slick and I've used it myself a number of times. But I think it only really works because those languages have strict requirements as to the name and location of each source file based on the class and package name, and the output of the compilers is a separate artifact per class. Those compilers can identify that you're referencing a type by name, identify that said type does not exist in the classpath and locate the source where that type is defined by name without having to understand the syntax of the source files.

@dancojocaru2000
Copy link

@HaloFour But does F# know the syntax of VB.NET source files? In a way, it feels like .NET is able to do kind of the same thing, just on a project-by-project level, not file-by-file level.

@HaloFour
Copy link

@dancojocaru2000

But does F# know the syntax of VB.NET source files?

No, the .NET compilers have no idea how the syntax works in the other compilers. If the F# compiler were to come across a type name that it could not find in any referenced assemblies it would have no idea what to do with it. But the Scala compiler can identify where the source for such a type exists because of those strict source file naming rules, and it can identify that the file extension happens to be .java, and then it can invoke the Java compiler to compile that source file into a .class file which it sticks into the classpath before it continues compiling the Scala file. (I'm massively trivializing how that process works in JVM languages, although pretty much all of that effort was put in by the Scala and Kotlin teams as the Java compiler has no concept of any language other than Java.)

In a way, it feels like .NET is able to do kind of the same thing, just on a project-by-project level, not file-by-file level.

Sure, you can always have a solution comprised of projects using different languages.

@dancojocaru2000
Copy link

dancojocaru2000 commented Jan 28, 2021

In a way, it feels like .NET is able to do kind of the same thing, just on a project-by-project level, not file-by-file level.

Sure, you can always have a solution comprised of projects using different languages.

But that's exactly the inconvenience that is to be avoided. Especially when not using Visual Studio and instead using dotnet and something else, there aren't even solutions, just some projects separate of each other, so it's a lot of extra work to get it all working together.

@cartermp
Copy link
Contributor

@dancojocaru2000 the .NET CLI has the ability to create a new sln a link up each project, and do p2p references. You don't have to even edit any project files (though I personally do). It's not as fast as using visual studio, but that's the sort of reason why IDEs exist in the first place

@dancojocaru2000
Copy link

dancojocaru2000 commented Jan 29, 2021

@cartermp: I did find out about dotnet sln, but can you please link me somewhere where I can read more about how dotnet links them all up? I can't seem to find that info.

but that's the sort of reason why IDEs exist in the first place

As for this, as far as I'm aware there's no Visual Studio for Linux.

Edit: Just tried setting up a solution with dotnet, can't have circular dependencies. So C# <-> VB is okay, but C# -> VB -> C# doesn't work. Back to my example above, Java code that uses Scala code that in itself uses Java code works just fine. So the "just use multiple projects" solution isn't really a solution either.

@cartermp
Copy link
Contributor

So it's circular dependencies between languages that you're looking for? If so, then F# definitely wouldn't be a good choice since it also (generally) disallows that practice wholesale.

@dancojocaru2000
Copy link

Not exactly. But if you want to define base class A in C#, derive class B from it in VB and then derive class C from B back in C#, you now need 3 projects.

@iam3yal
Copy link

iam3yal commented Nov 14, 2021

Maybe it would be much easier to make the interoperability stories between C#, F# and VB.NET easier for consumers be it at the language level or IDE level or tooling in general than to try and mix languages in the same project.

It might be possible to add some sort of virtual project in Visual Studio that allows you to mix different languages so when you add a file of a specific language to that project it actually creates a physical project behind the scene that corresponds to that language but then the IDE also takes care of referencing it and depends on compilation settings it also add ILMerge as a build step or something, just an idea.

@AlexanderMorou
Copy link
Author

AlexanderMorou commented Dec 28, 2021

@gafter wrote:

The possibility of doing this was discussed early in the Roslyn design, as there would have been a significant investment at that time in order for Roslyn to be capable of working that way. But that would have been the time to start the work. We decided not to do it, and subsequently we designed the internals of the C# and VB compilers using separate data structures and algorithms. It is too late to reasonably change the design at this time - it would essentially require a deep redesign of much code that already exists. We have no plans to do that and I don't think we ever would.

This response, while unfortunate, makes perfect sense. If it would require basically rearchitecting Roslyn from the ground up, the cost outweighs the benefit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests