This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-06-09
Channels
- # announcements (3)
- # aws (2)
- # aws-lambda (15)
- # beginners (38)
- # calva (15)
- # cider (17)
- # cljs-dev (2)
- # clojure (44)
- # clojure-dev (17)
- # clojure-spec (4)
- # clojure-sweden (1)
- # clojure-uk (8)
- # clojurescript (122)
- # cursive (19)
- # fulcro (25)
- # jobs-discuss (12)
- # nyc (3)
- # off-topic (20)
- # reagent (1)
- # rewrite-clj (4)
- # shadow-cljs (11)
- # spacemacs (65)
- # tools-deps (1)
- # vim (3)
Is it possible to extend a whole type to a new IPrintWriter, but only in the scope of particular print action?
Like, say I want to print a whole collection, but I want to do something funny with the strings or functions or objects, but only during this printing, not globally at all times.
I want to tell the writer, "for each node in this collection, if you get to this type, write it this way instead"
And if I had to walk it, is it even possible to get js type info during a macro time walk? Does the analyzer have that info?
I don’t think this is a use case anticipated / supported by Clojure, typically. I guess it’s all about how much we can get at the protocol impl
in CLJS we happen to know that protocol implementations end up like
Bar.prototype.cljs$core$IPrintWithWriter$_pr_writer$arity$3 = function (this$ writer$ opts$) { ... }
so you could save the current value of the -pr-writer impl, extend the type, then when you’re done swap it back 😛
I’ve been circling around a similar problem with printing hiccup. I’d like to take a React element and print it to something like #hiccup/react [:div "foo"]
, but React elements are just bare objects 😕 hard to handle
I'm essentially trying to experiment with strategies to pickle certain kind of objects and functions over the .postMessage
wire in a webworker environment
it’s been awhile since I used IPrintWithWriter. doesn’t it require you to call it recursively?
so couldn’t you make that a recursive call to your own printer that handles these objects specially?
So, for any given cljs collection, printing it will pickle certain types into a tag with an id, add the object as another parameter to the message, send the message, read-string the edn, then the tag-reader will grab the object for that id and the collection is restored on the other side.
My other option, instead of printing collections to edn, would be to clj->js
the coll and extend IEncodeJS for the types I care about
But the edn path already has more fidelity for clojure datastructures... I'd have to add a lot of IEncodeJS writers and readers
maybe it’s better to implement your own protocol, IPickle, and create your own printing function
I think it can be done by walking the whole collection and specify!
ing a special printer that hands off the object and drops in a tagged id for fn?
args
What's interesting is that certain functions print out in a self contained way, such that if all of your workers (or js environments) have the same compiled artifacts, the strings act as byte code that can be shuffled between them.
@yogthos presented a video where they’re serializing functions to a DB and then reading them into a CLJS app
Actually, the functions get read in clj in my case because all the business logic runs server-side to ensure updates being transactional across clients.
I had a chance to chat with Mike Fikes, and he suggested that one option would be to add a namespace with exports for all the core functions you're using. Then you'd be able to call those if you compile cljs to js on the fly and hot load it on the client.
the whole function impl was in the serialization though, so it sounds like you’re getting like a reference to a function and then passing that over the wire?
not really sure what you mean “as bytecode”. I think they were just passing EDN back and forth from the DB to the app
I'm doing this (((read-string (pr-str (fn->special-fn (fn [] inc))))) 1)
where special fn reifies a special print writer and a tagged reader calls js/eval
on it.
But (fn [] inc)
evals to:
#object[ret__6694__auto__ "function (){
return cljs.core.inc;
}"]
It's definitely a little wild. Not a supported use case... But the utility of it is pretty surprising. Especially when you use it mostly as an rpc mechanism for already statically compiled code, even though it feels kinda like your talking between threads like back in clojure-land
yeah. starts to tickle at some things I’ve run into while developing a REBL clone for CLJS
Yeah, you're not getting the same object on both sides of the wire here, in an equality sense, necessarily
I do have a cool SAB backed atom thing though that can be shared between workers, and that is the same object on both sides of the wire. And a cool on
macro that knows how to transfer them, so you can do like (let [sa (shared-atom 1)] (-> wkr1 (on #(swap! %1 + %2) sa 1)) (println (wait sa)))
or just ... (-> wkr1 (on swap! sa + 1)) ...
as all arguments to the right of the function passed to on
will be applied to it.
on
also sends a sab to the worker for the return value of the function you pass, so that you can dereference the return value of the on
to get the result, or wait
on the result, like (-> wkr1 (on swap! sa + 1) wait (->> (println :result)))
or (-> wkr1 (on fib large-number) wait (->> (println :result)))
would probably be more likely, if you're just using the return value sab to get the result.
I've already got the on
macro doing the function wrapping jazz and it seems to work for common functions you might pass to a swap. Just building out the ability to transfer clojure collections now, but not sure whether to go through the trouble of trying to build out all this machinery to convert all functions in an arbitrary clojure datastructure
if anyone’s interested, I whipped up an example of using reader tags for hiccup parsing: https://github.com/Lokeh/hiccup-tag/blob/master/src/hiccup_tag/examples.cljs#L17
It'd be interesting to make a static site/blog edn format where all behaviors are in an approved set of tagged readers, where all the logic is guaranteed to run deterministically and terminate.
And then possibly page snippets could be shared between untrusted users. Essentially, sandbox the logic but allow for new complex components that are built in clojure but are guaranteed to be safe at runtime
I’m thinking of ripping out the hiccup interpreter in hx
and using tagged literals instead
I haven’t really run into a use-case yet where I wanted the dynamicity of runtime interpretation. it’s been more a concession because the ergonomics of macros are bad
#h/r [:div (for [n [1 2 3]]
#h/r [:div {:key n} n])]
;; vs
(h/r [:div (for [n [1 2 3]]
(h/r [:div {:key n} n])])
One interesting thing about tagged literals - because they run before macro expansion, you can write things in macros that transform prior to macro expansion
an upside to the reader literal is being able to use it with cljs.reader
to receive stuff over the wire, though that’s not something I’m actively using it for
Though you can dip into that using register-tag-reader!
without having to have a reader file, if you're just converting stuff from io
actually the change that I think makes either macros or reader tags tenable is the thing I’m doing with props
I haven’t implemented it completely yet, but I’m testing a new syntax for dynamic props:
(let [stuff {:style {:color "green"}}]
#h/r [:div {& stuff} "foo"])
@lilactown if the intent is to know that stuff
is a map, another possibility would be to tag it directly, eg [:div #hx/map stuff "foo"]
i personally find writing lots of nested tagged literals not-so-pleasant. even the simple case of #js
gets tedious with nested structures
IMO the props disambiguation makes doing the parsing at read time or macro time much more manageable
Because you don't have to fall back to runtime checks for whether it's props or not. And you don't have to pay the cost of allocating a map and then turning it into a js object in many cases
I've though about metadata for disambiguating the props as well, but feels mor verbose than I like
Yeah writing tagged readers can be a little mind-bending too though. If you pull it off, I'm sure it'll be very interesting.
Hello, is there a way to require clojure libaries into clojurescript? I am getting this error:
Unexpected error (ExceptionInfo) compiling at (<cljs repl>:1:1).
No such namespace: clojure-csv.core, could not locate clojure_csv/core.cljs, clojure_csv/core.cljc, or JavaScript source providing "clojure-csv.core" (Please check that namespaces with dashes use underscores in the ClojureScript file name) at line 1 <cljs repl>
@lilactown Understood. Thanks!