Fork me on GitHub
#clojure
<
2022-11-20
>
Ulises MC02:11:49

Hi all! I'm trying to run libGDX Clojure code on Android, and I'm facing some problems. I built a Clojure uberjar that is a dependency in the Android project, and some specific Clojure functions break the program (e.g. calling println & reset! isn't a problem). My stack trace is the following:

I/AndroidGraphics: Managed buffers/app: { }
E/AndroidRuntime: FATAL EXCEPTION: GLThread 691
    Process: com.flyhighware.rbhm, PID: 9403
    java.lang.ExceptionInInitializerError
        at clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:426)
        at com.flyhighware.rbhm.core_clj$_startGame$fn__262.invoke(core_clj.clj:99)
        at com.flyhighware.rbhm.core_clj.proxy$com.badlogic.gdx.Game$ff19274a.render(Unknown Source:12)
        at com.badlogic.gdx.backends.android.AndroidGraphics.onDrawFrame(AndroidGraphics.java:474)
        at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1573)
        at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1272)
     Caused by: java.lang.NoSuchMethodException: canAccess [class java.lang.Object]
        at java.lang.invoke.MethodHandles$Lookup.findVirtual(MethodHandles.java:923)
        at clojure.lang.Reflector.<clinit>(Reflector.java:38)
        at clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:426) 
        at com.flyhighware.rbhm.core_clj$_startGame$fn__262.invoke(core_clj.clj:99) 
        at com.flyhighware.rbhm.core_clj.proxy$com.badlogic.gdx.Game$ff19274a.render(Unknown Source:12) 
        at com.badlogic.gdx.backends.android.AndroidGraphics.onDrawFrame(AndroidGraphics.java:474) 
        at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1573) 
        at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1272) 
W/System: A resource failed to call close. 
As you can see, the problems is that someone is calling canAccess which doesn't exist. I found an answer in stack overflow: https://stackoverflow.com/a/53381284 Anyone has been able to run compiled Clojure code in Android? Thanks!

Ulises MC02:11:04

I already tried building my uberjar using java 1.8 & java 17, but nothing works 😞

phronmophobic02:11:58

I think running clojure on android is pretty rare. I'm not aware of anyone doing it successfully in the last few years (although I'd love to be proved wrong!). It looks like the specific error you're running into is related to reflection. If you (set! *warn-on-reflection* true) and get rid of all the reflection warnings, does that make a difference?

👀 1
Ulises MC02:11:16

It worked, I'll try to add type hints everywhere in my small project and l'll let you know

🎉 1
skylize02:11:13

Android is not Java, it just duplicated almost all of the Java API, as it existed when Android was created. Seems kind of strange to me that with Clojure being ported to JavaScript, .NET, and Dart (just the projects I know of), nobody has bothered with patching it up to run cleanly on the almost-Java system running on Android.

👍 1
Ulises MC03:11:42

Ok! by adding type hints on every reflection warning solves the problem

Ulises MC03:11:49

I successfully ran my libGDX code on Android using Clojure 🙂 But I probably don't want to add type hints everywhere since using libGDX uses lots of interop

🎉 2
phronmophobic03:11:05

It's probably possible to find/create a tool that helps with the type hints, but makes sense if that is more trouble than it's worth. There's also no guarantee that you won't run into other issues, but maybe it's not so bad. Thanks for the report!

👍 1
skylize03:11:48

You might be able to reduce the need for type hints with careful structuring of your code. E.g. In most cases type-hinting once a the top of a function is enough for everything that happens inside that function.

Ulises MC03:11:42

@U90R0EPHA Yeah, I agree. I set the type hints in the function's agrs.

SK15:11:51

hi! is there a a clojure utility function that allows easy templating of a map's values into a string? something like (str-template-fn "This is a {:adjective} {:what}" {:adjective "short" :what "template"}). Java's string formatter I know, but I don't want to keep repeating (:prop1 map}, {:prop2 map}, etc. in the paramter section.

p-himik16:11:50

(defn map-format [s m & ks]
  (apply format s (map m ks)))

(let [m {:name "%username%"
         :fun? "fun"}]
  (map-format "Hello %s! Formatting is %s."
              m :name :fun?))
:)

👍 1
p-himik16:11:21

Or, I suppose, you also want to have named placeholders?

Mark Wardle16:11:31

Have a look at Selmer https://github.com/yogthos/Selmer I’ve used successfully for this kind of templating job, and not just for HTML.

👍 1
pavlosmelissinos16:11:16

core.incubator has a macro that works like python's fstrings: https://github.com/clojure/core.incubator/blob/be509fd967df8ce1ee43c43bca52360cf710252a/src/main/clojure/clojure/core/strint.clj#L49 However: • You still have to do the destructuring of the map (only once but still it's not exactly what you asked...) • clojure.core.incubator is no longer developed edit: I just realized that this is the same code as funcool/cuerdas so if you like the approach just pick that...

👍 1
seancorfield17:11:37

Another vote for Selmer -- we use it very heavily at work and the maintainer is super responsive.

👍 1
SK19:11:24

thanks all, I look into all these

niwinz19:11:57

agree on selmer, we are also using it, but for a simple string interpolation, cuerdas macro is many orders of magnitude faster (on a simple test: 30000ns vs 200ns)

👍 2