Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Binding Forms Incompatible with defclass #13

Open
superstructor opened this issue May 10, 2021 · 1 comment
Open

Binding Forms Incompatible with defclass #13

superstructor opened this issue May 10, 2021 · 1 comment
Labels
enhancement New feature or request

Comments

@superstructor
Copy link

Binding forms such as let are incompatible with defclass as such forms only return the value of the last form.

E.g.

(defclass example
   []
   (let [a true]
      {:background (if a :blue :grey)}
      [:h4
        {:color (if a :black :white)}]
      [:&:hover
        {:border [[(px 1) :solid :grey]]}]))

;; will only output
;; [:&:hover
;;        {:border [[(px 1) :solid :grey]]
;; as the first 2 forms are ignored due to the let

The root cause of this is defclass macro return semantics being different to defn / do in that it returns all top level forms, instead of the value of the last form. Its understandable once analyzed that the above let example does what it does in that context, but it is initially surprising behavior for a Clojure(Script) programmer. It certainly caught me out because I was trying to bind a common value with let and it took me awhile to realise why all the styles were not coming through.

I'm not sure how to fix this. Maybe a mitigation such as allowing a single form return style for defclass could work ? E.g.

(defclass example
  []
  [(let ... ])
@dhleong
Copy link
Owner

dhleong commented May 15, 2021

Hmm.... I can see now why you would expect that a let form would have the same mechanics as the top-level defclass, but I hadn't considered it before. I suppose when support would also be nice to have here. It may be doable, but my gut is that it will be tricky.

In the meantime, perhaps something like this will work:

(defclass example []
  (let [a true]
    [:& {:background (if a :blue :grey)}
      [:h4 {:color (if a :black :white)}]
      [:&:hover ; etc.
        ]]))

@dhleong dhleong added the enhancement New feature or request label May 15, 2021
dhleong added a commit that referenced this issue Nov 25, 2021
See #13

This is problematic when used in nested forms. We could perhaps add a
special case so only top-level forms are supported, but that might be
more confusing than it's worth. Another alternative could be some
special syntax that triggers us to unpack binding forms (IE: explicitly
opt-in to multi-return) but that might be a bit too arcane, eg:

```clojure
(defclass stylish []
  [:* (let [opacity 0.2] ... )])
```

We could also add special binding form replacements to similarly opt-in,
eg:

```clojure
(defclass stylish []
  ; the & mimics [:&]
  (&let [opacity 0.2] ... ))
```

This is all sugar though, so maybe the real solution is just
documentation?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants