-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Comments
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. |
Why do we require a primary language?
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. |
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. |
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. |
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:
|
@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. |
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 ( |
Concurrence and Story
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?!
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?
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 NicheSo, 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: ( 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.
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 DownThe 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):
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:
TLDR;Already partway there!
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 SummaryMy 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
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
Let's assume I'm referring to the core C#.NET, VB.NET, F#.NET, and POSSIBLY MSIL and J#.NET**...FOR NOW...**:
|
IIRC the only reason it works with ASP.NET WebForms with inline code is that:
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. |
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:
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. |
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. |
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. |
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: SORRY, just one more edit crosses fingers: To illustrate better with the words of someone who has talked about the concept on his blog, see:
|
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 :) |
@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". |
@paul1956 by inline, do you mean allowing c# code to be:
Also, in reference to the missing features:
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. 😄 |
@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.
or
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. |
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 |
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 |
@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. |
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 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). |
@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. |
@paul1956 You can also use this C# Eval library to evaluate C# code in VB.NET projects: I don't have time now to test them. Please give me a feedback if you used them. |
@MohammadHamdyGhanem 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. |
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
As noted, the key is to enable the Link Time Code Generation (LTCG) feature in I spent a bunch of time "diffing" the assembly produced by these steps with its equivalent, built with completely-stock 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 More significantly perhaps, |
Let me mention one more thing. Although I'm not totally sure, I believe that linking in a correct |
Hey there, @glenn-slayden , thanks for contributing! I've actually played around a little bit with ins0mniaque's GoToDefinitionSo far as not being able to get the Moving ForwardYour notes will help with my attempts to emulate this process but from a Questions
I'd love to dig in and compare what you've got to the This may help me to simplify the work necessary closer to what you've done, but also get the feature-set of the Thanks again for your input and suggestions. Hope that this is a turning point! 🙏 🤞 Links: |
@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 Unfortunately right now I don't really have time to pursue this line of inquiry much further. |
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 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 |
@glenn-slayden 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. |
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? |
You are, I assume, fully aware of the new VSProjectSystem effort (here also), right? Does it help with your goals?
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. |
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. |
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 proposal may make it happen at some scale: #34821 |
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. |
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. |
@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. |
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
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 |
@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 |
@cartermp: I did find out about
As for this, as far as I'm aware there's no Visual Studio for Linux. Edit: Just tried setting up a solution with |
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. |
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. |
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. |
@gafter wrote:
This response, while unfortunate, makes perfect sense. If it would require basically rearchitecting Roslyn from the ground up, the cost outweighs the benefit. |
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!):
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.
The text was updated successfully, but these errors were encountered: