This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-06-24
Channels
- # admin-announcements (2)
- # beginners (46)
- # boot (8)
- # cider (29)
- # cljs-dev (45)
- # cljsjs (10)
- # cljsrn (13)
- # clojure (60)
- # clojure-dev (5)
- # clojure-greece (1)
- # clojure-ireland (4)
- # clojure-mexico (6)
- # clojure-poland (3)
- # clojure-quebec (3)
- # clojure-russia (8)
- # clojure-spec (89)
- # clojure-uk (70)
- # clojurescript (84)
- # cursive (4)
- # datomic (7)
- # devcards (1)
- # dirac (2)
- # emacs (11)
- # hispano (10)
- # jobs (13)
- # keechma (34)
- # lein-figwheel (4)
- # luminus (19)
- # off-topic (2)
- # om (78)
- # onyx (6)
- # parinfer (1)
- # planck (82)
- # proton (2)
- # re-frame (10)
- # reagent (23)
- # ring-swagger (5)
- # spacemacs (2)
- # specter (24)
- # spirituality-ethics (122)
- # untangled (13)
can a function support more than one spec? we could have an alias for sh
with a spec supporting :cb and let the existing sh
barf if you provide :cb with the default spec
i.e., the alias could put sh
into the cb-accepting mode; i.e., select the :cb-accepting spec rather than the regular one
this way i wouldn't have to duplicate the CLJS -> JS -> C plumbing but consumers would still see two different functions
1 - rename current sh
to sh-private
and mark private so consumers can't touch it.
2 - relax spec on sh-private
to accept :cb. propagate :cb all the way through to C if provided.
3 - create new sh
that calls sh-private
appropriately with original spec disallowing :cb.
4 - create new sh-async
that calls sh-private
appropriate and has spec accepting :cb.
@johanatan: sure, give a combined API a try and see how it feels. We can see if a more complicated spec works out. From a spec perspective it seems that the :fn
part would let us express the relation that the return is nil
if :cb
is present. Return values no longer appear to be checked anyway.
@mfikes: what do you think of the above steps 1-4? seems like best of both worlds to me [shared plumbing but different external functions/specs]
and if you ever wanted to go with combined, it would be as easy as removing sh
and sh-async
and renaming sh-private
to sh
@johanatan: It may make sense to somehow make the new API fail at runtime indicating that it is not supported if called under 1.x
@johanatan: I'm curious if the value of js/PLANCK_VERSION
can be used to wrap the (defn sh-async ... )
so it only exists in Planck 2.0
@johanatan: Yes. It is worth trying. I’m wondering if the initialization sequence has js/PLANCK_VERSION
setup early enough.
@mfikes: any idea how to test if something is a function in CLJS? clojure.test/function? doesn't exist
and the output from this isn't very useful without a string compare hack:
cljs.user=> (type (fn [] 9))
#object[Function "function Function() {
[native code]
}"]
but it's complaining about clojure.test.check.generators now:
cljs.user=> (s/exercise :planck.shell/sh-args)
Var clojure.test.check.generators/simple-type-printable does not exist, clojure.test.check.generators never required
cljs.core/-deref [cljs.core/IDeref] (cljs/spec/impl/gen.cljs:15:3)
You need a copy of test.check
with TCHECK-105 applied. There is a copy of that JAR in this gist: https://gist.github.com/mfikes/4b41b7c406c57228489b5edfb6ffe6a7
It will be normal for it to fail when encountering the need to generate values conforming to #(instance? File %)
.
i.e., if i pass in a CLJS function from the CS side, how do I unpack it from the JSObjectRef on the C side
@johanatan: Interestingly, it looks like that whole question was side-stepped with the implementation of setTimeout
@johanatan: If there is no clear way to do it from C, then perhaps you can write some ClojureScript to retain the callback somewhere, and then when the results are available, execute a “script” that says “take this value and apply the callback to it"
(Funky stuff like that was done for function values in Planck’s eval
implementation. See the bottom of http://blog.fikesfarm.com/posts/2016-01-22-clojurescript-eval.html )
@johanatan: Fixed
There are probably many ways to skin that cat. Just pointing out that if it is difficult to deal with functions as values, they can be bijectively mapped to numbers so that you deal with numbers on the C side.
Can you point to an example of the "execute a "script" that says "take this value and apply the callback to it"" part of this?
I think the best way to handle it will be to assign a unique ID to each cb on the way in, stash it in a datastructure on the CLJS side, pass the ID into C and then let C callback to the CLJS with that ID and the return value (it's the last leg of that which I need help with).
@johanatan: See https://github.com/mfikes/planck/blob/master/planck/PLKClojureScriptEngine.m#L168
Who knows if all of that is really just a hack. But it has some germ of an idea on how to cobble together something.
It is probably cleaner with most of it on on the ClojureScript side, and the C just calling something on that side with the function ID and the results.
this should work. one risk i have here though: is the JSContext a relatively global concept? i.e., would it change between successive calls to (sh ...) ?
for the async part, i'm going to have to put a 'wait' on a bkg thread. but when that completes, i still only have the original JSContext (the parent thread/process having returned already)
You may not even need to translate from a the function object to and ID and back again. Perhaps you can opaquely pass it into C and then back out again.
this is the translation on the way into C:
(def ^:private sh-async-cbs "sh-async-cbs")
(aset js/window sh-async-cbs (clj->js {}))
(def ^:private cb-idx (atom 0))
(defn assoc-cb [cb]
(let [idx (swap! cb-idx inc)]
(aset js/window sh-async-cbs idx cb)
idx))
so, C will just generate some js like so: function() { window.sh-async-cbs["{ID}"]( res ); }
I like the opaque idea though. Could look something like:
JSEvaluateScript(ctx, "function() { window.do_callback(res); }();", (JSValueRef)opaque_ref, NULL, 0, NULL);
better yet: pack both the func to call and the result into an object and specify it for the 'this'
[would eliminate having to encode the res
as a string (and the existing impl already encodes it as a JSObject anyway)]
there is the complication of not knowing how/when the JSValueRef[] passed into my C function gets cleaned up though.
passing an int from the main thread to the background thread sidesteps that concern/risk
[i.e., it's possible that the JSValueRef which the background thread has been passed from the main thread will not be valid when the result comes back]
@johanatan: I'd try an experiment to see if it works out
kind of a costly experiment though especially since i'm already down the int road quite a ways
given C's manual memory management, i'm almost certain that the JSValueRef's are being explicitly freed after the function returns to its caller