This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-02-13
Channels
- # announcements (12)
- # babashka (88)
- # beginners (60)
- # biff (10)
- # calva (56)
- # clerk (9)
- # clj-kondo (5)
- # clojure (70)
- # clojure-austin (3)
- # clojure-conj (2)
- # clojure-dev (69)
- # clojure-europe (53)
- # clojure-nl (1)
- # clojure-norway (28)
- # clojure-uk (1)
- # clojurescript (27)
- # copenhagen-clojurians (3)
- # cursive (10)
- # datascript (1)
- # datomic (10)
- # fulcro (3)
- # funcool (1)
- # garden (7)
- # helix (5)
- # holy-lambda (5)
- # hyperfiddle (39)
- # introduce-yourself (6)
- # jobs-discuss (15)
- # lsp (3)
- # malli (5)
- # membrane (19)
- # missionary (1)
- # nrepl (6)
- # off-topic (44)
- # pathom (17)
- # pomegranate (3)
- # react (7)
- # releases (1)
- # shadow-cljs (39)
- # tools-deps (16)
- # xtdb (28)
ClojureDart has a feature to destructure fields in keys destructuring using {:flds [a b c]}
. In squint-cljs I've supported this as ^:js {:keys [a b c]}
as to not have to make changes to clj-kondo. I guess Cursive would also have to make a change to support :flds
- am I right @cfleming?
I wonder if there's support for adopting this more broadly (in CLJS: @dnolen, in CLJ: @alexmiller). Field destructuring doesn't sound unique to ClojureDart and it would be nice not to have to make bespoke (albeit small) changes to static analyzers for Clojure dialects.
cc @cgrand @baptiste-from-paris ❤️
for CLJS it would make sense to have a :js/keys
and :js/props
to be able to easily access thing.x
and thing["x"]
, since it makes a difference for the closure compiler which style you use
would be nice to have a unified way of doing this across CLJ dialect, which is kind of the point of the original post: not having to support dialect-specific stuff too much :)
But any sort of analysis will need to know what the fields are coming from though, right? e.g. Java object, JS object, Dart object. Even if the surface syntax is the same.
> Field destructuring doesn’t sound unique
It’s more important in Dart because, fields have getter/setters. On the JVM it wouldn’t make sense as public fields are rare. Except if you are ready for :flds [foo]
to expand to .getFoo
.
"host object" is the common theme here so I think the (static) analysis should (roughly?) be the same for all?
> Except if you are ready for :flds [foo]
to expand to .getFoo
.
Having used Kotlin, I would actually like this, as well as (.foo x)
(or perhaps (.-foo x)
)
Note that (.foo x)
will actually first try the method foo and then the field foo, if the method doesn't exist, in Clojure
More generally what about static analyzer positing that {:unknown-kw [names ...]} in destrucring is going to bind the provided names.
Yeah, but the .- might make it clearer that you’re expecting to access it like a property.
> Having used Kotlin, I would actually like this, as well as (.foo x) (or perhaps (.-foo x))
But a class may have both a method named foo
and one named .getFoo
— unlikely but I’m sure there are specimens out there. How does kotlin deal with the ambiguity?
> Yeah, but the .- might make it clearer that you’re expecting
Didn't understand this. The expansion isn't visible to the user so it doesn't matter what you expand to, as long as it works for both fields and methods, which JVM Clojure already supports (if you don't automatically prepend get
, just use the raw field/method name)
While we are on sugarized form: we also have (.-prop! x v)
as a shorthand for (set! (.-prop x) v)
because 1/ setting fields is common beacuse of setters 2/ it works better with doto
> How does kotlin deal with the ambiguity?
I’m not sure, those classes are sufficiently rare that I’ve not seen one. But note that the method would be invoked as x.foo()
whereas the property would be either a = x.foo
or x.foo = b
(desugaring to .getFoo()
and .setFoo()
respectively), so even for offending classes perhaps the syntax usually disambiguates - I’m not sure of all the details.
without that what you can do on the JVM with (doto (Obj.) (.setFoo x) (.setBar y))
becomes (doto (Obj.) (-> .-foo (set! x)) (-> .-bar (set! y))
. That’s why Cljd has (doto (Obj) (.-foo! x) (.-bar! y))
@cfleming ah yes missing parens help disambiguating it, so it would be a dash, still room for conflict but more unlikely (public field vs setField)
It’s not something I had thought about a lot, just the sort of thing that occurred to me in the shower.
I think in CLJS this is valid:
(set! x -prop v)
I don't have a strong preference, but again I would have liked it if ClojureDart would have adopted that (maybe it does?) since tooling already supports this and -prop!
looks like a regular field access, now you have to analyze the ending of the name for an exclamation mark, etc(set! x -prop v)
:thinking_face: I though we had implemented something similar, but it was apprently ditched 😞 We can support it too.
As for .xyz
if you want to do anything useful with it you need to have dialect specific member resolution anyway.
if you do some kind of type inference, yes, but clj-kondo currently does't choke on it. it doesn't even check that it's not valid to have the last "arguments" here (.-foo x 1 2 3)
, but one day it might :)
Well we have a couple of other stuff like dotless constructors, method names which are invalid symbols etc.
First page of the cheatsheet gives a good summaryhttps://github.com/Tensegritics/ClojureDart/blob/main/doc/ClojureDart%20Cheatsheet.pdf
Great, thank you - I have been meaning to sit down and make a proper effort at properly supporting ClojureDart, this will help.
still about :flds
:
Java 19 has a "record", that is a immutable class.
https://docs.oracle.com/en/java/javase/19/language/records.html
Its getters are not getField, but just field
I think that :flds [foo] => .getFoo
is not future-proof.
also many Java classes have .get methods with side effects - seems like that would be bad with destructuring
In Java :flds
doesn't seem to be make much sense, maybe I should have started this conversation in #C07UQ678E
field destructuring seems potentially interesting, but I'm not sure how much this would be needed in Java interop, probably more likely in cljs?
also, why not :fields
? I know the others are xyzs but they had useful first syllables/prefixes
@cgrand was really attached to a 4 letters word...
we use the more generic term "member" a lot too, did you consider :mems
?
no, I don't recall considering :mems
Iirc the CLR has getters/setters too so @U45FQSBF1 might be interested in supporting something like that
well as above, getters seem problematic (vs fields)
JavaScript fields can also cause side effects (there are getters and setters, and you can implement your own trickery with Proxy
)
but if you wanted to call those fields/methods anyway, what's the problem in destructuring vs manually calling them?
btw I'm not advocating for this feature, but just wanted to clear up what problem you see in this :)
it may force some semantic ordering of actions that is not currently specified in merely accessing data
Isn’t this tied to what’s idiomatic in a given ecosystem/community? In Java there are side-effecting getters in the “core” classes.
Dart/Flutter seem more well behaved towards what getters do.
In Clojure a deviant ILookup impl can break havoc. Well bean
as mentioned above.
these are just things to think about