Uploaded image for project: 'ClojureScript'
  1. CLJS-2920

Optimize qualified- / simple- ident? / keyword? / symbol?


    • Type: Improvement
    • Status: In Progress
    • Priority: Major
    • Resolution: Unresolved
    • Affects versions: None
    • Fix versions: None
    • Patch:


      There are some optimizations that we can make for the simple-ident?, qualified-ident?, simple-symbol?, qualified-symbol?, simple-keyword?, and qualified-keyword? functions.

      Two separate optimization can be done.

      In places where boolean is used (the qualified- fns), we can instead use some? for a faster implementation:

      (boolean (and (symbol? x) (namespace x) true))

      can be converted to simply

      (and (symbol? x) (some? (namespace x)))

      Focusing on just V8 for now, for

      (simple-benchmark [x 'a/b f #(qualified-symbol? x)] (f) 100000000)

      and subtracting out the baseline cost for

      (simple-benchmark [x 'a/b f (fn [] x)] (f) 100000000)

      this yields a speedup of 1.74.

      Since we know that we are dealing with keywords or symbols when applying namespace, we can furthermore use (.-ns x).

      Alone this gives a speedup of 2.21 and when combined with the previous optimization as

      (and (symbol? x) (some? (.-ns x)))

      we see a combined speedup approaching infinity (the operation effectively becomes free, taking the same time as the baseline).

      Note that we could perhaps use predicate-induced type inference along with a new macro for namespace that emits .-ns instead, but CLJS-2866 Closed currently hinges on looking at the test in an if, while expressions like the above cause optimized js* output with short-circuiting &&.

      These optimizations would be good because these functions are often used in spec-based generative code testing where performance can be an issue.

      We have test coverage for these functions in cljs.predicates-test.

      For reference here is the JavaScript currently emitted for qualified-symbol?

      function cljs$core$qualified_symbol_QMARK_(x) {
        return cljs.core.boolean$(
          (function() {
            var and__8540__auto__ = x instanceof cljs.core.Symbol;
            if (and__8540__auto__) {
              var and__8540__auto____$1 = cljs.core.namespace(x);
              if (cljs.core.truth_(and__8540__auto____$1)) {
                return true;
              } else {
                return and__8540__auto____$1;
            } else {
              return and__8540__auto__;

      and here is what we get with the revisions

      function cljs$user$qualified_symbol_QMARK_(x) {
        return x instanceof cljs.core.Symbol && !(x.ns == null);

      (The compactness of this revised implementation means that it might be further inlinable via Closure for more speedups for whole-program optimization.)




            • Assignee:
              dnolen David Nolen
              mfikes Mike Fikes
            • Votes:
              0 Vote for this issue
              1 Start watching this issue


              • Created: