athos / jise Goto Github PK
View Code? Open in Web Editor NEWJiSE: Java in S-Expression
License: Eclipse Public License 2.0
JiSE: Java in S-Expression
License: Eclipse Public License 2.0
One problem that I've always faced with clojure is that it's not possible to derive things from Abstract classes.
Can you create an example showing how to do it with JiSE?
Hello, this is a really nice library. There's a discussion over on zulip over porting a java implementation of a method that generates random strings, where most of the path is going through char arrays. We seem to be paying an unavoidable cost in uncheckedIntCast when doing any array access with literals (since the literal numbers are always longs), where javac gets away with this. I have a repo here with the corresponding java implementation and my current attempt at porting it to JiSE, cited below. I was using both aset and aget, per some of the examples, and it looks like we're as fast as the clojure example if unchecked-math is enabled (which will emit uncheckedIntCast s for us). That still tends to be about 8% slower on my machine, worse on others (if you believe in the ns accuracy of criterium). Is there a way to ensure that the indices for aset are actually being represented as ints in the resulting class definition (such as a different array set syntax, I was unable to figure out..)? Or is the expected path to use aset/aget as I have done? I found that the direct array access is possible in the benchmark example you provided. Thanks for any insight!
^:public
(defclass Rand
(def ^:public ^:static ^chars tbl
(new [char] [\- \0 \1 \2 \3 \4 \5 \6 \7 \8
\9 \A \B \C \D \E \F \G \H \I
\J \K \L \M \N \O \P \Q \R \S
\T \U \V \W \X \Y \Z \_ \a \b
\c \d \e \f \g \h \i \j \k \l
\m \n \o \p \q \r \s \t \u \v
\w \x \y \z]))
^:public ^:static ^String
(defm genId []
(let [^ThreadLocalRandom tlr (ThreadLocalRandom/current)
^long l1 (.nextLong tlr)
^long l2 (.nextLong tlr)
^chars rt (new [char] 22)]
(aset rt 21 (tbl ^int (& l1 0x3f)))
(aset rt 20 (tbl ^int (& (>>> l1 6) 0x3f)))
(aset rt 19 (tbl ^int (& (>>> l1 12) 0x3f)))
(aset rt 18 (tbl ^int (& (>>> l1 18) 0x3f)))
(aset rt 17 (tbl ^int (& (>>> l1 24) 0x3f)))
(aset rt 16 (tbl ^int (& (>>> l1 30) 0x3f)))
(aset rt 15 (tbl ^int (& (>>> l1 36) 0x3f)))
(aset rt 14 (tbl ^int (& (>>> l1 42) 0x3f)))
(aset rt 13 (tbl ^int (& (>>> l1 48) 0x3f)))
(aset rt 12 (tbl ^int (& (>>> l1 54) 0x3f)))
(aset rt 11 (tbl ^int (& (>>> l1 60) 0x3f)))
(aset rt 10 (tbl ^int (& l2 0x3f)))
(aset rt 9 (tbl ^int (& (>>> l2 6) 0x3f)))
(aset rt 8 (tbl ^int (& (>>> l2 12) 0x3f)))
(aset rt 7 (tbl ^int (& (>>> l2 18) 0x3f)))
(aset rt 6 (tbl ^int (& (>>> l2 24) 0x3f)))
(aset rt 5 (tbl ^int (& (>>> l2 30) 0x3f)))
(aset rt 4 (tbl ^int (& (>>> l2 36) 0x3f)))
(aset rt 3 (tbl ^int (& (>>> l2 42) 0x3f)))
(aset rt 2 (tbl ^int (& (>>> l2 48) 0x3f)))
(aset rt 1 (tbl ^int (& (>>> l2 54) 0x3f)))
(aset rt 0 (tbl ^int (& (>>> l2 60) 0x3f)))
(String. rt))))
According to JLS 15.25, typing the conditional operator never fails unless it includes an invocation of a void method. However, the current implementation throws VerifyError
when the second and third operands differs in type:
user=> (defclass C ^String (defm m [^int x] (str (if (== x 0) "foo" 1))))
Syntax error (VerifyError) compiling at (REPL:1:1).
Bad type on operand stack
Exception Details:
Location:
user/C.m(I)Ljava/lang/String; @17: invokevirtual
Reason:
Type top (current frame, stack[1]) is not assignable to 'java/lang/String'
Current Frame:
bci: @17
flags: { }
locals: { 'user/C', integer }
stack: { 'java/lang/StringBuilder', top }
Bytecode:
0000000: bb00 0e59 b700 0f1b 9a00 0812 11a7 0004
0000010: 04b6 0015 b600 19b0
Stackmap Table:
same_locals_1_stack_item_frame(@16,Object[#14])
full_frame(@17,{Object[#2],Integer},{Object[#14],Top})
user=>
It'd be great to have direct lambda support instead of using the clojure.lang.IFn interface.
Is that on the roadmap and how difficult would it be to get working?
Why does it use def, square brackets, and other vestigal clojure syntax? I can't give this to my Java friends, they'd laugh. There is a JiSE out there waiting to be discovered that they wouldn't laugh it.
I'm really curious about the typical speeds for the algorithms you implemented (like AOBench).
I ran it, it feels really fast but I'm not sure what a comparison might be.
Do you have any comparisons that you might have ran yourself?
Original java:
ThreadLocalRandom tlr = ThreadLocalRandom.current();
long l1 = tlr.nextLong(), l2 = tlr.nextLong();
char[] rt = new char[22];
rt[21] = tbl[(int)l1 & 0x3f]; l1 = l1 >>> 6;
rt[20] = tbl[(int)l1 & 0x3f]; l1 = l1 >>> 6;
rt[19] = tbl[(int)l1 & 0x3f]; l1 = l1 >>> 6;
Corresponding JiSE:
(let [^ThreadLocalRandom tlr (ThreadLocalRandom/current)
^long l1 (.nextLong tlr)
^long l2 (.nextLong tlr)
^chars rt (new [char] 22)]
(aset rt 21 (tbl ^int (& l1 0x3f)))(set! l1 (>>> l1 6))
(aset rt 20 (tbl ^int (& l1 0x3f)))(set! l1 (>>> l1 6))
(aset rt 19 (tbl ^int (& l1 0x3f)))(set! l1 (>>> l1 6))
...
)
Inspected with clj-decompiler, using (decompile ...), gives:
final char[] array = new char[22];
final ThreadLocalRandom current = ThreadLocalRandom.current();
final long nextLong = current.nextLong();
final long nextLong2 = current.nextLong();
array[21] = RandM.tbl[(int)(nextLong & 0x3FL)];
final long n = nextLong >>> 6;
array[20] = RandM.tbl[(int)(n & 0x3FL)];
final long n2 = n >>> 6;
array[19] = RandM.tbl[(int)(n2 & 0x3FL)];
...
long variable in let
is set to final. Is there a way to allow it to mutate?
Curious how much additional effort would be required for annotations. I am helping work through porting an example from optaplanner which is "heavily" class-based and requires lots of annotations to communicate with the framework. Most of clojure's deftype (with annotation support) worked here, however we end up with problems since the field types are "always" Object, regardless of typehint. So optaplanner will complain that the field does not return a constrained type (List or array). Looking at custom bytecode generation with insn, but I figured I would see if JiSE could be closer...
user=> (require '[jise.utils :as jise])
nil
user=> (jise/do (let [^java.io.Serializable s "foo"] (.toString s)))
Syntax error macroexpanding jise.core/class at (form-init7183457418990174559.clj:64:4).
Error: cannot find symbol
symbol: method toString(no arguments)
location: class java.io.Serializable (/private/var/folders/mr/bf82sldd78g9822yxqgzd12h0000gn/T/form-init7183457418990174559.clj:1:47)
user=>
Whereas:
user=> (jise/do (let [^String s "foo"] (.toString s)))
"foo"
user=>
This is essentially due to the fact that the current implementation of t/get-methods
does not consider the Object
class as a supertype of any interface type:
user=> (t/get-methods nil nil (t/tag->type 'java.io.Serializable) "toString")
nil
user=> (t/get-methods nil nil (t/tag->type 'String) "toString")
({:class #object[clojure.asm.Type 0x3d7eb9c1 "Ljava/lang/String;"],
:interface? false,
:param-types [],
:return-type #object[clojure.asm.Type 0xbc97527 "Ljava/lang/String;"],
:access #{:public}})
user=>
@athos: I'm looking to get jnr-ffi working with jise and am porting the Gettimeofday example here:
I'm having problems compiling the defclass
form. Would you please take a look and let me know what I'm doing wrong.
https://gist.github.com/zcaudate/f05001f6cc38a8a02f9b0892bab02a82
I'm getting this error here, which I'm not sure is defclass
or jnr
related.
Error: constructor jnr.ffi.Struct$time_t in class
jnr.ffi.Struct$time_t cannot be applied to given types
(/Users/chris/Development/caudata/statstrade/statstrade-server/src/statstrade/lib/curl.clj:55:26)
{:column 26,
:line 55,
:alternatives
({:param-types
[#object[clojure.asm.Type 0x29c9e0cb "Ljnr/ffi/Struct;"]],
:access #{:public}}
{:param-types
[#object[clojure.asm.Type 0x23d3c400 "Ljnr/ffi/Struct;"]
#object[clojure.asm.Type 0x7093025d "Ljnr/ffi/Struct$Offset;"]],
:access #{:public}})}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.