malli

https://github.com/metosin/malli :malli:
rmcv 2021-07-02T07:18:45.263100Z

How do I provide sci options in malli decode? Trying to use java class with no luck.

(m/decode [:int {:decode/string '(fn [_] (.toEpochMilli (java.time.Instant/now)))}]

          "whatever"

          {:classes {'java.time.Instant java.time.Instant}}

          mt/string-transformer)

ikitommi 2021-07-02T09:21:00.264400Z

looking at the code, it’s :malli.core/sci-options key in options, see https://github.com/metosin/malli/blob/master/src/malli/core.cljc#L1792-L1813

ikitommi 2021-07-02T09:41:41.265700Z

@ben.sless merged the loop unrolling perf PR, great for common cases and as it’s just clj, doesn’t make the cljs bundle size any bigger, big thanks!

;; 164ns -> 36ns
(let [valid? (m/validator [:and [:> 0] [:> 1] [:> 2] [:> 3] [:> 4]])]
  (cc/quick-bench (valid? 5)))

πŸ‘ 2
πŸŽ‰ 3
ikitommi 2021-07-02T10:45:55.266600Z

merged the other perf PR too:

;; 150ns -> 39ns
(let [valid? (m/validator [:map [:a :any] [:b :any] [:c :any] [:d :any] [:e :any]])
      value {:a 1, :b 2, :c 3, :d 4, :e 5}]
  (cc/with-progress-reporting
    (cc/quick-bench (valid? value))))

1
πŸŽ‰ 3
Richard Hundt 2021-07-05T09:47:04.309300Z

@ikitommi I've created https://github.com/metosin/malli/issues/472 with a test case which demonstrates the issue.

Ben Sless 2021-07-05T11:01:07.309700Z

@richard.hundt I profiled you example, it looks like CPU mostly goes towards parsing the schema. If you wrap every def-ed schema with a schema constructor it seems to be way more efficient, would you mind trying?

Richard Hundt 2021-07-05T11:02:26.310100Z

D'you mean just wrapping it in a function which returns the structure? (I'm not sure what you mean by "schema constructor")

Ben Sless 2021-07-05T11:06:25.310400Z

like so;

(def A1
  (m/schema
   [:map
    {:encode/test {:leave encode} :decode/test decode}
    [:type [:= "A1"]]
    [:value float?]
    ]))

Richard Hundt 2021-07-05T11:06:44.310600Z

thanks, I'll try

Ben Sless 2021-07-05T11:06:44.310700Z

m/schema parses the children once

Ben Sless 2021-07-05T11:06:57.311Z

your implementation has no way to cache these results

Ben Sless 2021-07-05T11:07:31.311200Z

It's a bother to do from scratch, you can take this

Ben Sless 2021-07-05T11:07:56.311600Z

Ben Sless 2021-07-05T11:08:06.312Z

thanks slack, very helpful

Richard Hundt 2021-07-05T11:08:38.312200Z

thank you

Ben Sless 2021-07-05T11:09:02.312600Z

there, more convenient

Richard Hundt 2021-07-05T11:09:38.312800Z

yeah, that's pretty much instant now, I'll try it on our production code

Ben Sless 2021-07-05T11:19:52.313Z

πŸ‘

Richard Hundt 2021-07-05T11:36:05.313200Z

Perfect. Thanks Ben! What shall I do with the github issue? Do I close it, or are you planning on making changes to parsing?

ikitommi 2021-07-05T12:43:28.316900Z

I closed the issue, no plans on making the parser faster or caching at the moment. Thanks for @ben.sless for digging into this πŸ™‡

Ben Sless 2021-07-05T12:46:06.317600Z

I think it is worth to leave a comment on the issue and perhaps a note in the readme regarding references to uncompiled schemas

Ben Sless 2021-07-05T12:46:50.317800Z

And you're welcome πŸ™‚ Turns out I was completely wrong regarding the transformers and satisfies?

Ben Sless 2021-07-05T12:47:57.318Z

I see you left a comment with a link to the gist, so that would leave only the readme

ikitommi 2021-07-05T13:14:13.320700Z

if you have idea what and where to write this, please do πŸ™‚

πŸ‘ 1
ikitommi 2021-07-02T10:50:05.269700Z

@ben.sless, great work. Saw the thread on Clojureverse about compiler optimizations. Would be great if things got automatically or magically faster. While waiting, writing performant code inside the libraries (on the hot perf path) is just being smart.

1
πŸ™ 1
ikitommi 2021-07-02T10:54:51.269900Z

Ben Sless 2021-07-02T11:21:35.270700Z

Thank you, I appreciate it. Blame it all on the talk you gave on ClojureTRE 2019

Ben Sless 2021-07-02T11:22:22.271Z

Nice 😁

rmcv 2021-07-02T14:53:11.272Z

tried this

(m/decode [:int {:decode/string '(fn [_] (.toEpochMilli (java.time.Instant/now)))}]
          "whatever"
          (merge
           (m/-default-sci-options)
           {:malli.core/sci-options {:classes {'java.time.Instant java.time.Instant}}})
          mt/string-transformer)