On Wed, Jan 30, 2019 at 11:07 PM Brian Craft <craft.br...@gmail.com> wrote:
> With much experimentation, I ended up with this: > > (let [a 1 > b (.longValue ^Long (:foo {:foo 3})) > c (if (< a b) a b)]) > > which seems to avoid the longCast call: > > Object o; > if (_thunk__0__ == (o = _thunk__0__.get(const__3))) { > o = (__thunk__0__ = __site__0__.fault(const__3)).get(const__3); > } > final long b = (long)o; > final long c = (a < b) ? a : b; > > I don't know if this is advisable. Does anyone do this? > No, I wouldn't do this. `long` can inline so it's going to be better (it's also more likely to jit well as it's used other places and is likely hotter in the jit). Going back to the original... (let [a 1 b (:foo {:foo 3}) c (if (< a b) a b)]) let will track primitives if possible. - a is going to be a primitive long. - (:foo {:foo 3}) is going to (always) return an Object and it's best to recognize that and make an explicit cast to a primitive long. - if a and b are both primitives, then < is able to inline a long-primitive comparison (via Numbers.lt()) - the if is going to return an Object though, so again you'll probably want to type hint or cast c, but it's hard to know for sure without seeing more code Without other info, I would probably start with (let [a 1 b (long (:foo {:foo 3})) c (if (< a b) a b)]) Or alternately, it might be better to just type hint b in the comparison to avoid reboxing b, but hard to know without more context: (let [a 1 b (:foo {:foo 3}) c (if (< a ^long b) a b)]) Comparing the bytecode for these (skipping everything up through the keyword lookup, which is same for all): Original: Option 1: Option 2: 45: astore_2 45: invokestatic #41 45: astore_2 46: lload_0 48: lstore_2 46: lload_0 47: aload_2 49: lload_0 47: aload_2 48: invokestatic #41 50: lload_2 48: checkcast #37 51: ifeq 62 51: lcmp 51: invokestatic #43 54: lload_0 52: ifge 60 54: lcmp 55: invokestatic #45 55: lload_0 55: ifge 66 58: goto 65 56: goto 61 58: lload_0 61: pop 59: pop 59: invokestatic #49 62: aload_2 60: lload_2 62: goto 69 63: aconst_null 61: lstore 4 65: pop 64: astore_2 63: lload 4 66: aload_2 65: astore_3 65: invokestatic #47 67: aconst_null 66: aload_3 68: astore_2 67: aconst_null 69: astore_3 68: astore_3 70: aload_3 71: aconst_null 72: astore_3 Option 1 does an lstore/lload (long) instead of an astore/lstore (object). Both options use lcmp which is likely the fastest path to compare longs. I've omitted some info here to make these fit, but Original line 48 will invoke Numbers.lt:(JLjava/lang/Object;)Z which is the Numbers.lt(long, Object) - lcmp is definitely going to be preferable to this. Also of importance is that in Option 1, both a and b are stored as longs and loaded as longs so if there is subsequent stuff to do on them, they can avoid boxing (this is also betrayed by the shorter length from fewer casts). Your longValue one is like Option 1, but starts: 45: checkcast #37 // class java/lang/Long 48: invokevirtual #41 // Method java/lang/Long.longValue:()J I guess I don't know whether that's faster than an invokestatic call to clojure/lang/RT.longCast:(Ljava/lang/Object;)J, hard to tell without testing in a real context. I'd certainly use the (long ...) one though unless I proved it mattered. -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.