Fork me on GitHub
#malli
<
2023-07-05
>
ikitommi17:07:29

on vacation, but now back with the computer - will check all the PRs this week. Unrelated: would like to add a shortcut syntax to lite syntax to support optional keys: if a keyword key starts with ?, it’s optional. Similar to what TypeScript has:

interface User {
    name: string;
    age?: number;
    occupation?: string;
}
=>
(def User
  (l/schema
   {:name :string
    :?age :int
    :occupation :string}))

User
;[:map
; [:name :string]
; [:age {:optional true} :int]
; [:occupation :string]]
What do you think?

ikitommi17:07:48

using ? as a special marker as last char would clash with the idiom of boolean function.

ikitommi17:07:22

, but, one could always force a key with ? in it:

(l/schema
 {:name :string
  (l/raw :?age) :int
  :occupation :string})
;[:map
; [:name :string]
; [:?age :int]
; [:occupation :string]]

ikitommi17:07:00

also, could do a lite->malli converter.

ikitommi17:07:01

why? 1. 👍 optional keys in reitit parameters are common => simplifies these a lot 2. 🙇 want to pull some of the good parts of TS to malli 3. 💪 just in lite, e.g. no sugar or design compromises into the malli core lib

teodorlu17:07:44

The :? keyword might be an interesting edge case, predicate or optional?? 😅

ikitommi17:07:14

Good point, it should be just a keyword as the stripped value ( : ) is invalid kw.

isak18:07:26

:?caliente?

isak18:07:06

That is an example where it would look a little goofy. (The problem is ? is an idiomatic suffix in clojure for booleans.)

isak18:07:47

What about putting appending the ? to the type instead, e.g.:

(def User
  (l/schema
   {:name :string
    :age :int?
    :occupation :string}))

Ben Sless20:07:05

If anything it belongs on the key. The key itself is optional, not the value. The prefix syntax is fine but I'd put its interpretation behind an option (default off) to avoid collisions by default.

didibus21:07:28

Options on lite syntax would start to make it feel heavy for me. I think having it as a prefix + the raw wrapper in case you actually have a keyword that starts with ? is fine. Sure, it's a bit weird to see: :?registered? but not that weird. Alternatively, could you have a ? wrapper instead:

(l/schema
 {:name :string
  (l/? :age) :int
  :occupation :string})

❤️ 2
pithyless21:07:46

I'm wary of using special suffixes or prefixes in the name to signify semantic changes (even for the lite syntax). Considering the lite map syntax only supports keywords as valid [:map] keys, perhaps we can take advantage of this? eg. tuples to unambiguously identify and pass optional data?

(l/schema
 {:name :string
  [:? :age] :int
  :occupation :string})
It's not much more typing than :?age but shows that there is something special about the key itself.

hifumi12300:07:47

Agreed on putting ? on the key, not value. When I see :int?, my mind wants to interpret [:maybe :int] instead of optional key

isak02:07:27

To me the possibility of already having a ? suffix in the key already is a fatal flaw to the idea of having it as a prefix. Having it on both sides would just be completely nuts. But I can see why having it in the type name is no good either. What about having a delimiter in the key name (such as . ) that is not commonly used in key names, so it is :age.? :int ? Hiccup uses that idea to add classes and ids to html elements, maybe malli could use it.

ikitommi06:07:12

• there is already l/optional wrapper for value on lite syntax • there could be wrappers for keys l/req and l/opt instead • mostly agree that any interpretation of keyword key names should be optional and not enabled by default • I think lite syntax is not restricted to keywords, any key can be used (did not verify this) -> [:? :age] can also clash • this boils to simple vs easy :thinking_face:

👍 1
pithyless06:07:42

> • there could be wrappers for keys l/req and l/opt instead 👍 This would be consistent with existing lite syntax usage.

👍 2
pithyless06:07:19

My concern with bringing in more different kinds of code interpretation is that we are increasing the surface area needed to comprehend what the code is doing. The argument of "let's hide it behind an optional flag" is not convincing to me, because it means in practice there will be codebases that use it and others that don't. (1) if you walk up to the codebase that chose to use malli, you are forced to understand and learn it. Malli is already a lot to take in at once; malli-lite adds even more cognitive load (since it is different enough from regular malli schemas); I really would rather not have to force someone to also discover that keywords are magically interpreted. (2) since it's optional, not every malli codebase will have it. So it is even less likely it will be familiar to people walking up to codebases (even if they think they understand malli) :)

💯 2
didibus07:07:46

Does the lite syntax already has combination of options like that? I feel options that alter the syntax of the lite syntax means it's no longer just one syntax, but a combinatronic explosion of possible syntaxes based on the current options. That's neither simple nor easy anymore. I'd vote for l/req and l/opt, they reduce the amount of typing and visually how much space they take as compared to l/optional, will work for all type of keys, not just keywords, have no conflict with the value of the key, are probably faster to parse, and are pretty self explanatory when you see them. I think a question mark in front or somewhere in the keyword actually isn't "easy" either, nor is it simple. It's more what we call "convenient" but only for people that know about it and are used to it. Otherwise it also seems to create some inconveniences, like if it clashes with the actual value, like how it can't be used on all types, etc.

☝️ 2
ikitommi13:07:51

Based on my experiences, 90% times any added sugar bites back. explicit > implicit, ambiguity issues with syntax are usually really bad. That said, don’t know why I’m tempted with this. Sugar addiction?

😝 1
ikitommi13:07:12

;; 1) this is the way
(l/schema
 {:name :string
  (l/opt :age) :int
  :occupation :string})
;[:map
; [:name :string]
; [:age {:optional true} :int]
; [:occupation :string]]

;; 2) no surprises
(l/schema
 {:name :string
  :?age :int
  :occupation :string})
;[:map
; [:name :string]
; [:?age :int]
; [:occupation :string]]

;; 3) 🥧🥤
(l/schema
 {:name :string
  :?age :int
  :occupation :string}
 {::l/optional-key-syntax true})
;[:map
; [:name :string]
; [:age {:optional true} :int]
; [:occupation :string]]

;; 4) should this be deprecated?
(l/schema
 {:name :string
  :age (l/optional :int)
  :occupation :string})
;[:map
; [:name :string]
; [:age {:optional true} :int]
; [:occupation :string]]

Ben Sless13:07:18

1 makes sense, but since the theme is lite syntax, how about just calling the operator ??

ikitommi13:07:49

you mean:

(l/schema
 {:name :string
  (l/? :age) :int
  :occupation :string})

👍 1