Can't `with-open`
Describe the bug
with-open will not compile.
Does your problem persist after clj -M:cljd clean && flutter clean? Yes
To Reproduce Steps to reproduce the behavior:
- Create any ClojureDart project. I reproduced with your first app on sha 303e2621391abaf52a7179efb848bf6d73ebb2e8 but it was also present on 6c1b1538310862dfe3fc3960fb897cf5de5a4b59 in another project
- Modify the source to include any
with-openform. It breaks with anywith-openform but the simplest I could invent was:- add
["dart:io" :as io]to namespace:requires - replace "Let's get coding!" message with
(with-open [client (io/HttpClient)] (str client " foo"))
- add
- See error:
Compiling to Dart... @10:09:59
acme.main
Keep calm and fix bugs! 👑
Error while compiling with-open
⛔️ Unknown symbol: with-open at line: 15, column: 13, file: acme/main.cljd
Faulty subform and/or expansion with-open
While compiling (defn main [] (f/run (m/MaterialApp .title "Welcome to Flutter" .theme (m/ThemeData .primarySwatch m.Colors/pink)) .home (m/Scaffold .appBar (m/AppBar .title (m/Text "Welcome to ClojureDart"))) .body m/Center (m/Text (with-open [client (io/HttpClient)] (str client "--foo")) .style (m/TextStyle .color m.Colors/red .fontSize 32.0))))
Expected behavior
with-open should compile, create its bindings, and then .close the bindings
I ended up "writing" my own with-open, but then I soon realized that half the things I wanted to with-open were actually closed with .cancel and not .close. And then some more had to be .dispose'd...
And creating a closable protocol would require lots of tactical extensions.
I suspect that with-open must stay true to its original spirit of relying on conventions and not interfaces.
Something like?
(with-open [controller (xxx) :close .dispose] ...)
I propose adding with-open to CLJD with the following deviations from CLJ:
1/ allow for keyword options in the bindings vector (options apply to the previous binding)
2/ only supported option is :close whose value is a form into which the resource is threaded (as per ->). Default value is .close. When the close is itself async, the user would have to write :close (-> .terminate await). Is it common enough to mandate an :await-close option? I don't think.
3/ allow destructuring in bindings (useful for example with StreamController where stream and sink fields have to be used). It doesn't make sense in CLJ where there's no :flds destructuring.
However with-open doesn't cover Dart streams. We need something like Dart's await for. There are at least two distinct macros/fns: one to reduce (should we expect the reducing function to return a future? If not should we provide two reduce variants? Should we also consider transduce? Or should we go the areduce way?) and one to perform side-effects (dostream to riff on doseq).
Related #287