Comments (6)
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.
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.
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.
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.
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.
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)
- Clojurescript version of topological-sort incorrectly (and randomly) reports a graph cycle error HOT 2
- Metadata Reader Macros and fnks HOT 4
- fnk binding form can't combine optional parameters with destructuring HOT 4
- Feature suggestion: defs HOT 6
- Compile Time Schema Checks HOT 3
- Outputing maps from graphs HOT 4
- defnk-defined functions don't document their args HOT 1
- Schema for Graph HOT 3
- Support for namespaced keys, part II HOT 9
- Annotate defnk/fnk meta with their :file HOT 1
- Functional versions of ?> and ?>> HOT 4
- (map/flatten {:foo false}) -> '() HOT 1
- lazymap's repository has been deleted, please migrate away from it HOT 6
- `eager-compile` throws an error with large graphs HOT 6
- `plumbing.core/keywordize-map` causes shadow-cljs warnings even it is not used in the project HOT 1
- cjlx has been deprecated
- Fix API documentation
- Please consider making a new release HOT 8
- Malformed \uxxxx encoding error via clojars artifact HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from plumbing.