Hi @oheil, sure, by self-contained c# application i mean the usual .NET Core self-contained publish step that ships the .NET core runtime, i was wondering if we could also ship the Julia runtime along and have both languages packaged into this self-contained published .exe.
Example, when we publish any .NET core application it packages a bunch of System.XXX.dll like System.Collections.dll, i was wondering if we could also package the libjulia.dlls and it’s dependencies in order to have everything in one package, i think this would allow for very powerful applications.
Ah, ok. No, I am not this far with my application yet. When it comes to publishing everything using a installer my thoughts were on NSIS just because I used it before.
I will check this out when times come but I expect some month to come .
Ah ok, i was just wondering the applicability of this approach since PackageCompiler.jl is not very nice yet. I think my problem is the fact that distributing a Julia application is so hard right now, maybe merging it with C# could mitigate this.
I recently got some likes on this thread, so I opened it again to see what I did here.
The project I worked on is publicly available: https://github.com/oheil/doTimeTable/
and shows how Julia can be embedded in a complete C# application installer. Which means, installing the application is all the user needs to do (no preinstalling of Julia or something like that).
The link from C# to Julia is mainly in GUI/doTimeTable/Julia.cs. Julia is called in a separate thread.
It uses the C-Interface of both languages to translate between the languages very quickly compared to normal server/client based systems.
Julia.Init();
JLFun fun = Julia.Eval("t(x) = sqrt(x)");
double result = (double) fun.Invoke(2);
object dotNetObject = fun.Invoke(3).Value;
Julia.Exit(0);
It is very new but it has support for various built in Julia features such as a JLArray to allow manipulating jl_arrays neatly.
You can also work with .NET from Julia (Experimental at the moment). It utilizes .NET reflection
In C#:
public class TestClass{
public long g;
public TestClass(long g) => this.g = g;
}
Working from Julia:
sharpType = SharpType("TestClass") #Retrieve Type
sharpCon = SharpConstructor(sharpType, 0) #Get Constructor at Index 0
o = sharpCon(6) #Create Instance
sharpField = SharpField(sharpType, "g") #Get Field
println(sharpField(o)) #Get Field Value
Oh lol I forgot about that part. Any thoughts on multiplatform Julia Dir lookup? I provided a method to give your own dir but it would probaly be a good idea to have a default lookup. Also there is a kernel32 call which is not multiplatform.
I think those are the only two things that make it not multiplatform. Unfortunately I dont know anything about macOS. If anyone knows how to do the setdlldirectory / finding julia dir on macos, let me know
I think I wrote it in .Net framework aswell since I made this for another project. Ill port it over to .Net 5
I actually just finished developing an interface between Julia and .NET for an internal project based on information from @oheil .
When I started that, I was a newcomer to both Julia and C#/VB.net so it seemed infeasible with the C interface.
So I did it using communications over pipes, like a client-server communication.
Though this takes time, (de-)serialization seems to be fine (i.e negligible to the user) in most cases, even with relatively large arrays (about tens of thousands of double precision numbers).
I do not know if you tackled this issue already but the main missing part for me in the documentation about julia’s C interface was how to use it properly to load and interact with modules and how to handle special types. I was completely lost i the whole packing / unpacking of pointers to structures…
Also, there are some base types that exist in Julia that do not in .NET, so some conversions need to be done explicitely. For instance I discovered that my .NET (maybe it is a matter of version) did not support Int8.
I found almost no documentation, I just straight up read the Julia source code instead lol.
Regarding primitive types that are not cannot be converted, I personally have not run into any issues but I can have it promote them into larger containers if need be (Int8 → Int32 etc) but I havent had any issues so far.
I have just released the .NET 5.0 version of the project
Thanks for the link to the other thread, Ill see if at @Shuhua is willing to work together as I see he has done some work on natively converting C# arrays to Julia etc
Btw, Thoughts on implementing an abstract method interface for functions like what RuntimeMethod has and stuff? Can make it seem like a normal “method” object
Once GitHub - JuliaLang/juliaup: Julia installer and version multiplexer becomes more widely deployed you can just execute juliaup api getconfig1 and get back a JSON with information about installed Julia versions. At the moment this only works on Windows and if the user installed Julia from the Windows store, but I am very, very close to releasing the Mac and Linux version of this as well. The VS Code extension already tries this method to find the Julia binary, and then falls back to other ways if that doesn’t work.
So, this is more a FYI, maybe not entirely ready yet to be used, but should be much more ready in a few weeks.
For the using implementation, probaly have it store them all in a list for each “using JuliaInterface” context? Is it possible to create a variable when a module is “used”?
Then read the list in reverse order so last added using statement is checked first?
Here is the current Julia.NET .NET → Julia Interface:
@netusing Test
@netusing System
val1 = T"ReflectionTestClass".TestStateField[] #< Requires [] to actually get the field. If you dont put [] or () then it will just return the FieldInfo object
val2= T"ReflectionTestClass".StaticMethod[]() #To call a method. If you dont put [] or () then it will just return the MethodInfo object
val3 = T"ReflectionTestClass".StaticGenericMethod[T"Int64"]() "To call a generic method, put the generic types in []
item = T"ReflectionTestClass"".new[](3) #To call a constructor. If you dont put [] or () then it will just return the ConstructorInfo object
val4 = item.InstanceMethod[](); #To call a instance method
val5 = item.g[] #To Access a instance field
myGenericItem = T"ReflectionGenericTestClass`1".new[T"Int64"](3) #To Create a generic instance of an object, put the generic types in [].
boxed5 = sharpbox(5) #Will return the sharp object of the long value "5"
shouldBe5 = shapunbox(boxed5) #Will unbox the sharp object and return to native julia value
myClass = T"Test.ReflectionTestClass" #<= Perform Assembly Search and Return the Sharp Type
myClass2 = P"Test.ReflectionTestClass" #<= Perform one time assembly search and store the sharp type in a internal array (Reccommended for fast lookups)
myClass3 = G"Test.ReflectionTestClass" #Get from internal array
myClass4 = R"Test.ReflectionTestClass" #Remove from internal array
handle = pin(sharpbox(5)) #Pin the Sharp object in the Sharp GC
free(handle) #Will also auto free. You can also treat it like stream and put it in do end block