GithubHelp home page GithubHelp logo

Comments (6)

w01fe avatar w01fe commented on September 18, 2024

I don't remember if these are supported currently, I'm not sure if I thought of these combinations (I mostly thought of "renaming" as a way to bind an entire map).

I think schema + renaming would be easy to support if we don't already.

For renaming + fallback, what would you expect the behavior to be? Would the fallback also be used for the other bindings?

i.e. does (letk [[:x a :as {b {:a 1}}] {}] a) crash or return 1?

from plumbing.

lyderichti59 avatar lyderichti59 commented on September 18, 2024

Regarding renaming + fallback having sibling bindings as fallback, I'd reproduce the same behaviour as let (clojure.core).
i.e., we can use bindings however we like provided they have already been bound.

Example 1 : this works because b reuses a but a was already bound

(let [a 1, b (inc a)] b)
=> 2

Example 2 : this doesn't work because b is not bound yet when we use it to bind a

(let [a (inc b), b 2] b)
=> Syntax error compiling. Unable to resolve symbol `b` in this context

I'm not sure to understand your syntax proposal though.
I'm happy to see alternatives, but using an :or keyword might help.
Random example :

(letk [ [[:bar :or 777 :as baz]] {:foo 42}] baz) 
=> 777

Using :or & :as might be convenient with other combination as well.
schema + renaming would give :

(letk [[foo :- schema.core/Number :as bar] {:foo 42}] bar)
=> 42

schema + renaming + fallback

(letk [[:bar :- schema.core/Number :or 777 :as baz] {:foo 42}] baz)
=> 777

Please note I'm just brainstorming and I'm happy to see alternatives / what you have in mind.

But IMHO, deprecating the {binding fallback} and {binding :- schema fallback} patterns & relying only on vectors would avoid the cons of maps : being constrained to have pairs of symbols (which may force you to use nested structures (maps or vectors) for keys or values, just for the sake of having pairs)

With plain vectors, since you don't have any constraints on the vector's size (and can have an odd number of items in the vector) you could fairly easily pick any optional :- schema, :or fallback :as renaming pairs, with any combination of pairs you want
at the expense of a small verbosity (having :- :or and :as would be less concise than not having them), but with a great legibility improvement (probably subjective ?)

Examples for all combinations :
:foo => vanilla
[:foo :as bar] => renaming only
[:foo :- s/Number] => schema only
[:foo :or 3] => fallback only
[:foo :or 3 :as bar] => fallback + renaming
[:foo :- s/Number :as bar] => schema + renaming
[:foo :- s/Number :or 3] => schema + fallback
[:foo :- s/Number :or 3 :as bar] => schema + fallback + renaming

from plumbing.

w01fe avatar w01fe commented on September 18, 2024

Thanks for the detailed response. I'll need to think about these suggestions a bit.

Off the top of my head, the first thing I notice is that in [:foo :or 3] nothing is bound. The original intent behind the nested vector syntax was that you'd use it primarily to further bind things out of a sub-map, and the ability to use that for aliasing was somewhat incidental. Of course, there's no reason we have to stick to that, but I think we'd need to write [:foo :as foo :or 3] which is a bit of a mouthful compared to {foo 3} IMO.

from plumbing.

lyderichti59 avatar lyderichti59 commented on September 18, 2024

Good shout. I understand (and had not properly appreciated, I admit) that the nested vector syntax was first designed for sub-maps. It's great, and my suggestions above are somehow equivalent to extending these features (initially for sub-maps) to the top level maps too, in order to enable new use cases.

Regarding :foo (keyword) or foo (symbol), my thinking was to have the macro bind [:foo :or 3] to the foo symbol by default when there is no :as renaming. It's a rather opinionated solution that has the benefit of being "universal" (aka, in the examples above, you don't have to think about the syntax ("keyword or symbol?") depending on the context ("is there a renaming?"), you just always use a keyword as a first item). It also would have the benefit of being compatible with namespace keywords (the classic : (let [{:keys [:ns/foo :bar]} {:ns/foo 42, :bar 777}] [foo bar]) returns [42 777] because keywords (namespaced or not) are bound to symbols by default.

Alternatively, the syntax could bind a symbol in first position (when there is no renaming) (example : [foo :or 3], no keyword at first position here) and if there's any renaming (example [:foo :or 3 :as bar]). But I prefer the solution above. YMMV

Again, this is just brainstorming

from plumbing.

w01fe avatar w01fe commented on September 18, 2024

Thanks, happy to continue brainstorming.

I personally think it's a smell to ever bind anything that isn't a symbol in the binding map (e.g., binding to the symbol form of a keyword). The potential for confusion when accidentally shadowing an existing binding or something is just too high.

I also think the asymmetry between (defnk [foo ...] ...) and (defnk [... [foo ...] ...] ...) (the first binds a key in the current map, whereas the second binds a symbol in the outer map) is very confusing.

from plumbing.

w01fe avatar w01fe commented on September 18, 2024

On further reflection, I think the best route might be:

(letk [ [[:foo :as {bar 25}]] {}] bar) for combining a default with a rename. And for optional + schema, I guess metadata is always an option. Unfortunately the :- syntax just doesn't work well with the map-based default syntax (which predates the introduction of :- and schemas). We could consider switching away from maps, but that's a significant enough breaking change that I'd be pretty reluctant to do it, especially since you're the first person to bring up this gap.

from plumbing.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.