Welcome! Please see the About page for a little more info on how this works.

+1 vote
in ClojureCLR by
    static void Main()
    {
        try
        {
            IFn load = clojure.clr.api.Clojure.var("clojure.core", "load");

            // Below code line seems to expect clojure code (non-compiled) in path
            // bin\Debug\net7.0\clojure\hello.test.clj
            // 
            // OR a compiled dll: 
            //
            // from folderstructure 
            // ./clojure/hello/test.clj
            // > clojure.compile clojure.hello.test
            // 
            // with content in clj file like:
            //   (ns clojure.hello.test)
            //   (defn output[] "ninja")
            var r = load.invoke("hello.test"); 
            IFn helloFn = clojure.clr.api.Clojure.var("clojure.hello.test", "output");
            var result = helloFn.invoke();
            Console.WriteLine("Calling compiled clj from C#, Got: " + result);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
by
My question(s):
Is there a simple example for how to go about calling a clojure function from C# code like above?

Any documentation for how to think in regards to namespaces and folder structure in general when trying to interop to clojure from C#?

My main goal right now is to have fun and finally get something running with the nREPL + CIDER.
I was trying to load (using load.invoke)  clojure.tools.nrepl, but getting confused about where to put dll and how to re-name it?!

// with following code
IFn load = clojure.clr.api.Clojure.var("clojure.core", "load");
var r = load.invoke("tools.nrepl");

I output the RT.cs static FileInfo FindFile(string path, string filename)
probePath property and found out:
... being absolute path to my framework folder (net7.0)

...\net7.0\clojure\tools.nrepl.cljr
...\net7.0\bin\clojure\tools.nrepl.cljr
...\net7.0\clojure\tools.nrepl.cljr
...\net7.0\clojure\tools.nrepl.cljc
...\net7.0\bin\clojure\tools.nrepl.cljc
...\net7.0\clojure\tools.nrepl.cljc
...\net7.0\clojure\tools.nrepl.clj
...\net7.0\bin\clojure\tools.nrepl.clj
...\net7.0\clojure\tools.nrepl.clj
...\net7.0\clojure.tools.nrepl.cljr.dll
...\net7.0\bin\clojure.tools.nrepl.cljr.dll
...\net7.0\clojure.tools.nrepl.cljr.dll
...\net7.0\clojure.tools.nrepl.cljc.dll
...\net7.0\bin\clojure.tools.nrepl.cljc.dll
...\net7.0\clojure.tools.nrepl.cljc.dll
...\net7.0\clojure.tools.nrepl.clj.dll
...\net7.0\bin\clojure.tools.nrepl.clj.dll
...\net7.0\clojure.tools.nrepl.clj.dll
Error: Could not locate clojure/tools.nrepl with extensions .cljr, .cljc, .clj, .cljr.dll, .cljc.dll, or .clj.dll on load path.

None of these matches the nuget supplied clojure.tools.nrepl.dll
Action: rename
clojure.tools.nrepl.dll -> clojure.tools.nrepl.clj.dll

Then dll is picked up, but fails to load
clojure.lang.Compiler.AssemblyInitializationException: 'Cannot find initializer
for clojure.tools.nrepl, Version=0.1.0.0, Culture=neutral,
  PublicKeyToken=null.clojure/tools.nrepl'

2 Answers

0 votes
by

Cross posted in clojurians

0 votes
by

I can't see where you are calling Assembly.Load which I think is necessary. Try something like this in Program.cs

using clojure.lang;
using System.Reflection;

// start up Clojure runtime including compiler
RT.Init();

// make .cljr file resources available from DLL
Assembly.Load("clojure.tools.nrepl");
Assembly.Load("clojure.tools.reader");

// compile nREPL lib
var ns = "clojure.tools.nrepl";
RT.var("clojure.core", "require").invoke(Symbol.intern(ns));

// create nREPL server (default port is 1667)
var startServer = RT.var(ns, "start-server!");
var server = startServer.invoke();

// allow exit on Ctrl-C by shutting down server
var stopServer = RT.var(ns, "stop-server!");
Console.CancelKeyPress += (_, _) => stopServer.invoke(server);

And here is a suitable example.csproj file:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Clojure" Version="1.12.0-alpha8" />
    <PackageReference Include="clojure.tools.nrepl" Version="0.1.0-alpha1" />
  </ItemGroup>

</Project>

I'm using dotnet 7.0.114 on Ubuntu 22.04 . With those two files in an empty directory just run

dotnet restore
dotnet run

Have fun!

by
Thanks for this, it works like a charm. Also potentially gave me some understanding the "internals" of Clojure : )   (RT.init, RT.var etc.).
I think the wiki could be improved with some more clear examples like yours above.
https://github.com/clojure/clojure-clr/wiki/Using-ClojureCLR-in-a-C%23-project

I'll try learn more and maybe contribute some day...
...