Fork me on GitHub
#malli
<
2019-11-25
>
roklenarcic14:11:43

so what happens when you use mt/transformer to combine two existing transformers that have an encoder/decoder for same schema name?

roklenarcic14:11:31

seems to me that the last encoder/decoder function wins

roklenarcic14:11:28

so if you have a modifying transformer like strip-extra-keys-transformer and someone else defines a transformer for :map then one of them doesn’t work, if I am not mistaken

ikitommi14:11:41

should put into chain (after interceptors)

roklenarcic14:11:38

is this some new branch?

roklenarcic14:11:44

should I try to tamper with -transformer function to achieve a modifying effect

rschmukler16:11:17

It'd be reasonably easy to move the ->interceptor function in to have it compose if there's already existing transformers

rschmukler16:11:08

@ikitommi it might be worth having it compose with both :enter and :leave steps

roklenarcic16:11:13

you have a comment block at the top there

rschmukler16:11:29

I just noticed that! Thanks!

rschmukler16:11:39

So basically on the transformer call where it calls ->interceptor - you could move that reduce internally and then later transformers in & options could just compose

roklenarcic16:11:13

maybe schema seems to be reporting wrong name in error message

ikitommi16:11:52

.. about composing the transformers. What should happen when there are multiple transformers for same key? 1. last one wins (current) 2. all transformers with different name get chained 3. all get chained

ikitommi16:11:48

(mt/transformer mt/json-transformer mt/json-transformer)
1. normal json 2. normal json 3. json + json

ikitommi16:11:19

(mt/transformer {:decoders {:map keywordize-keys}} mt/strip-extra-keys-transformer)
1. strip-keys wins 2. both 3. both

rschmukler16:11:28

@ikitommi I wouldn't do unique based off of name - I think for people unfamiliar with the implementation, you might not think that name matters much. Someone might write their own :json that they also compose with the built in json

rschmukler16:11:36

We could do all unique functions though

ikitommi16:11:46

(mt/transformer {:decoders {:map keywordize-keys}} {:decoders {:map upper-case-keys})
1. upper-case wins 2. upper-case wins 3. both

rschmukler16:11:02

I think both would be most useful

rschmukler16:11:49

then you can write things like (mt/transformer keywords-as-strings capitalize-keywords)

rschmukler16:11:48

(I could even see utility libraries existing with tons of tiny compositions of common transformer needs)

rschmukler16:11:27

Also, I actually take back my comment on using unique functions

rschmukler16:11:38

I'd say let the user compose things however they want

rschmukler16:11:20

@ikitommi if you'd like I can add that functionality to my interceptor PR

eskos17:11:32

I almost commented on GitHub but not sure where this thought would actually fit, I started pondering that what if the data given to interceptor would be a zipper like navigation cursor instead? This would actually allow the interceptor to walk up/down/left/right the data structure when needed, without "bind to parent to get access" kind of tricks.

rschmukler17:11:36

Personally I prefer the interceptor pattern as a balance of simplicity, power, and because it's common in other libraries in the ecosystem. The cursor is definitely much much much more powerful, but building it will be non-trivial. Specifically, the way schema expansion currently happens is sort of a pre-walk - so a child doesn't even have reference to its parent because when the child is instantiated the parent doesn't even exist yet.

rschmukler17:11:52

The other thing of note is that right now all of the traversal / introspection of the schema happens at compile time (or, at encoder / decoder ) time. I'm not familiar enough with zippers to think through how mapping the functions produced by the zipper could then be composed into a transformer

eskos17:11:33

I'm almost certain it would be runtime only and probably not that incredibly fast :)

eskos18:11:51

But I disagree on that sentiment of simplicity, as I don't see it as simple for any other than the simple use case - this parent awareness being a very good example of a sudden trickery situation, esp. with multi schemas where the parent doesn't necessarily dictate which child there is. It is always possible everyone's gotten things wrong so far... 🙂

rschmukler18:11:31

It absolutely is!

rschmukler18:11:38

I agree with you 100%

rschmukler18:11:55

Because the schema's are data, we at least have the escape hatch of compiling a different schema

rschmukler18:11:20

But that feels "dirty" to me - not sure why... maybe bad habits from spec

eskos18:11:16

I've never used spec beyond tutorials tbh, I disliked its global registry and nested specs too much.

eskos18:11:29

So maybe I'm not tainted/enlightened in that sense? 🙂

rschmukler18:11:36

Lucky you 😉

eskos18:11:23

But anyway, it definitely is a concern that it would probably be really slow (in relation to rest of malli)

rschmukler18:11:33

The tooling story for spec is pretty cool. Definitely something I intend to port over to malli once things stabilize a bit

rschmukler18:11:37

(>defn- wrap-vec
  "Wraps the given target into a vector. If its already in a sequence, it will
  be converted to a vector. If its a vector it will return itself. If its a value
  it will be inserted into a vector"
  [item]
  [any? => (s/coll-of any? :kind vector?)]
  (cond
   (vector? item) item
   (seq? item)    (into [] item)
   :else          [item]))

rschmukler18:11:51

That kind of inline annotation + optional checks is pretty useful

rschmukler18:11:02

optional instrumentation I should say

ikitommi20:11:38

I would prefer the plumatic schema fn syntax:

(m/defn plus :- int? 
  [x :- int?, y :- int?] 
  (+ x y))

ikitommi20:11:16

effectively about the same.

rschmukler22:11:42

@ikitommi interesting, why the preference? You like the type annotations right next to the variable name?

rschmukler22:11:52

I can likely make both valid. I'll probably just have different namespaces that you can import from