this post was submitted on 19 Oct 2023
1 points (100.0% liked)

Lisp

53 readers
3 users here now

founded 1 year ago
MODERATORS
 

I have the following code (reduced to a minimum working example):

(ns timer.core (:gen-class))

(defn handle2 [x]
  (if (string? x) (Integer/parseInt x) x))

(defn -main
  ([max-time]
   (println (format "Going to sleep %d seconds" (handle2 max-time)))  
   (let [sleep-time (* (handle2 max-time) 1000)]  
     (Thread/sleep sleep-time)  
     (println (format "Waken up"))))  
  ([] (-main 10)))  

that works in the cider REPl on emacs and also works with > lein run on a windows terminal (x64 Native Command Prompt for VS 2022) and also can be compiled into an uberjar with leiningen and calling the java -jar command works. All the previous work with or without the max-time argument, as it is expected.

But when I build a executable from the uberjar with the GraalVM using the command

>  native-image --report-unsupported-elements-at-runtime --initialize-at-build-time -jar .\target\timer-0.1.0-SNAPSHOT-standalone.jar -H:Name=timer-cli

although it compiles a timer-cli.exe executable binary, this fails when is run with this error:

exp-timer-cli.exe
Going to sleep 10 seconds
Exception in thread "main" java.lang.IllegalArgumentException: No matching method sleep found taking 1 args
        at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:127)
        at clojure.lang.Reflector.invokeStaticMethod(Reflector.java:332)
        at timer.core$_main.invokeStatic(core.clj:72)
        at timer.core$_main.invoke(core.clj:68)
        at timer.core$_main.invokeStatic(core.clj:76)
        at timer.core$_main.invoke(core.clj:68)
        at clojure.lang.AFn.applyToHelper(AFn.java:152)
        at clojure.lang.AFn.applyTo(AFn.java:144)
        at timer.core.main(Unknown Source)

with or without parameter. But if I substitute (handle2 max-time) by an actual number (let's say 2), the program works, but of course with the hardcoded variable as sleep time, and prints the parameter value on the message string.

Does any one have experience with the GraalVM and knows why this happens? And how to solve this would be greatly appreciated.

Using:

  • Leiningen 2.10.0 on Java 19.0.2 OpenJDK 64-Bit Server VM
  • GraalVM 22.3.1
top 10 comments
sorted by: hot top controversial new old
[–] p-himik@alien.top 1 points 1 year ago (2 children)

Try using (Thread/sleep ^long sleep-time).

[–] hunajakettu@alien.top 1 points 1 year ago

Ok, this worked, but why? Somewhere to read about this?

[–] hunajakettu@alien.top 1 points 1 year ago (2 children)

Another question, I'm experimenting a bit, and if I use ^long further up (for example in the let declaration[sleep-time (* ^long (handle2 max-time) 1000)]) it also seems to work.

Does it matter where it goes?

[–] pwab@alien.top 1 points 1 year ago

The compiler is smart enough to keep track of type hints, so if you set it higher up, and the reference remains unambiguous, the compiler will “remember” the type later on.

[–] p-himik@alien.top 1 points 1 year ago

Sometimes, depends on whether or not the compiler knows or can figure out which type a function returns. E.g. 1000 is a long, you've marked (handle2 max-time) as long, (* ...) is expanded into (clojure.lang.Numbers/multiply ...), and that static Java method for long arguments returns a long.

[–] zerg000000@alien.top 1 points 1 year ago (1 children)

It is because of reflection. You can detect this type of error by https://clojuredocs.org/clojure.core/warn-on-reflection

[–] hunajakettu@alien.top 1 points 1 year ago

Ok, so reflection is something that is to be avoided in graalVM ? Or in general with clojure?
Reading [this](https://clojure.org/reference/java_interop#typehints) I get the impression that it should be used for performance, why would it affect the compiled object, if I don't care about performance?

(Sorry if it seems that I'm obtuse.)

[–] deaddyfreddy@alien.top 1 points 1 year ago (1 children)

Not related to your question (you've got the answer anyway), but you call (handle2 max-time) twice, I'd bind the result in let instead.

[–] hunajakettu@alien.top 1 points 1 year ago

Oh, yes, well this is a code hack to make it as small as possible, but still having the same issue, without thinking much, thanks anyway!

[–] ahmadrasyidsalim@alien.top 1 points 1 year ago