planck

Planck ClojureScript REPL
johanatan 2016-06-23T00:45:11.000140Z

@mfikes: i'm getting an kJSTypeObject as the only member of argv in my shellexec handler when invoking the sh function with a string. When I try to invoke it with an integer or an actual object I correctly get the following error:

cljs.user=> (require '[planck.shell])
nil
cljs.user=> (planck.shell/sh (clj->js {:a "b"}))
In: [0] val: #js {:a "b"} fails spec: :planck.shell/sh-args at: [:cmd] predicate: string?
ERROR
cljs.user=> (planck.shell/sh 9)
In: [0] val: 9 fails spec: :planck.shell/sh-args at: [:cmd] predicate: string?
ERROR
cljs.user=> 
any idea why my string arg is being converted into a js object?

johanatan 2016-06-23T00:46:11.000142Z

also any idea how to find out what keys are on that object (which would be my next step for trying to diagnose it myself)?

mfikes 2016-06-23T00:51:07.000143Z

@johanatan: I'm AFK now but I bet the PLANK_REQUEST http get stuff (already implemented in planck-c) has some similarities with sh.

johanatan 2016-06-23T00:51:34.000144Z

the http stuff actually expects an object (and apparently gets one)

johanatan 2016-06-23T00:51:40.000145Z

there are other examples that expect strings though

johanatan 2016-06-23T00:51:53.000146Z

and i didn't see any noticeable difference in the way they're setup and the way mine is

johanatan 2016-06-23T00:53:16.000148Z

function_raw_write_stdout e.g.

johanatan 2016-06-23T00:59:59.000149Z

i've pushed my code if you'd like to take a look when you have a chance: https://github.com/johanatan/planck/tree/shellExecWorkInProgress

mfikes 2016-06-23T01:00:16.000151Z

@johanatan: worth looking at the ClojureScript and Objective-C. Perhaps the first arg is passed through.

mfikes 2016-06-23T01:00:35.000152Z

(Not)

johanatan 2016-06-23T01:00:39.000153Z

oh, hmm. ok, i'll try to track that down

johanatan 2016-06-23T01:01:30.000154Z

but given that you said there weren't any changes required to those for the rest of planck-c i figured they would remain constant for this one function as well

mfikes 2016-06-23T01:02:16.000155Z

Let me look.

johanatan 2016-06-23T01:02:28.000156Z

k

mfikes 2016-06-23T01:04:35.000158Z

@johanatan: I don’t know why clj->js is being applied to cmd here https://github.com/mfikes/planck/blob/master/planck-cljs/src/planck/shell.cljs#L39

johanatan 2016-06-23T01:05:27.000160Z

but that would still produce a string though no?

cljs.user=> (clj->js "blah")
"blah"

mfikes 2016-06-23T01:07:30.000161Z

@johanatan: cmd is an array of strings

johanatan 2016-06-23T01:07:42.000162Z

ahh, right. i was just wondering about that

mfikes 2016-06-23T01:07:59.000163Z

Actually 🙂 via the spec one or more strings: https://github.com/mfikes/planck/blob/master/planck-cljs/src/planck/shell.cljs#L58

johanatan 2016-06-23T01:08:09.000166Z

so, i think this makes sense then

johanatan 2016-06-23T01:08:15.000167Z

aren't arrays also objects in js?

mfikes 2016-06-23T01:08:25.000168Z

If you look at the Objective-C you will see how it is dealt with on that side...

johanatan 2016-06-23T01:08:41.000169Z

ok, cool. thx!

mfikes 2016-06-23T01:09:21.000173Z

@johanatan: ^ fortunately, half of that code is actually C already 🙂

johanatan 2016-06-23T01:10:40.000174Z

ha, right

mfikes 2016-06-23T01:13:20.000175Z

Hah, the use of C to interoperate with JavaScriptCore traces back to a suggestion of David Nolen’s from a little more than a year ago. I guess he knew one day Planck would be ported to straight C. 🙂 http://blog.fikesfarm.com/posts/2015-05-23-ambly-using-javascriptcore-c-api.html

johanatan 2016-06-23T01:15:26.000176Z

nice

johanatan 2016-06-23T01:15:59.000177Z

btw, do you know if there's anything like C++'s std::vector in our C environment here? really not looking forward to a bunch of malloc and free calls to do dynamic allocation

johanatan 2016-06-23T01:17:10.000178Z

i.e., NSMutableArray from the Obj-C example you linked to

johanatan 2016-06-23T01:39:30.000179Z

so, this works: https://github.com/johanatan/planck/commit/62a7fb8484edac14840273c5039626da8c4e5456 [wish it were a little tighter but I guess that's C for ya]

mfikes 2016-06-23T01:40:25.000180Z

Cool. C is for ClojureScript 🙂

johanatan 2016-06-23T01:40:31.000181Z

🙂

mfikes 2016-06-23T01:42:25.000182Z

Yeah, the last time I was doing malloc / free was in 1994, I think. By the way this will help if you want to check for memory corruption: https://github.com/mfikes/planck/blob/master/planck-c/Makefile#L7 (add the sanitize address flag)

johanatan 2016-06-23T01:44:33.000185Z

ahh, cool.

johanatan 2016-06-23T01:45:19.000186Z

i unfortunately have been doing this stuff as recently as 2008-09 lol

johanatan 2016-06-23T01:50:16.000187Z

do you know if C/Linux file handling functions know/understand file:// url syntax?

mfikes 2016-06-23T01:54:33.000188Z

No clue

mfikes 2016-06-23T01:55:11.000189Z

If you don't have access to Linux, I can check the behavior of code for you

johanatan 2016-06-23T01:58:47.000190Z

What would we do about supporting :in (and :in-enc) if it turns out file:// isn't supported on C/Linux?

mfikes 2016-06-23T02:03:14.000193Z

@johanatan: I’m actually not familiar with that particular feature… but I’m guessing we could convert file:// urls to their local path, if it is possible to do so

johanatan 2016-06-23T02:04:26.000194Z

Ya, I think it would be to merely strip that prefix and replace it with '/'

mfikes 2016-06-23T02:07:23.000195Z

In the long run, handling of file:// in general might be possible to cope with via the <http://planck.io/IOFactory|planck.io/IOFactory> machinery. (That’s the way http:// can be handled, etc., in a generic fashion.) But yeah, just stripping file:// probably suffices for now.

johanatan 2016-06-23T03:09:36.000197Z

@mfikes: ok, i think we have a bigger issue with the char encodings. std C doesn't have any notion of these and you'd have to have a bunch of functions like the ones on this page to convert between the encodings (if you wanted to): http://codereview.stackexchange.com/questions/40780/function-to-convert-iso-8859-1-to-utf-8

johanatan 2016-06-23T03:09:50.000199Z

[unless there is a 3rd party library that provides all of this for us]

johanatan 2016-06-23T03:13:12.000200Z

for now, i'm going to ignore :in-enc and :out-enc

mfikes 2016-06-23T03:16:21.000201Z

Yeah… I wouldn’t worry too much about that. I bet most people use UTF-8 if anything and we might be able to take advantage of some stuff that might already exist in JavaScriptCore. For example https://github.com/mfikes/planck/commit/45874f341c02f241f2880b3ae985828f2bbdf99f#diff-b1129fb19d4dc0f5029761d2161e6f22L76

johanatan 2016-06-23T03:44:22.000203Z

Okay

johanatan 2016-06-23T03:44:36.000204Z

One other thing: how do you invoke sh with the optional arguments?

johanatan 2016-06-23T03:45:03.000205Z

I couldn't find any examples in the codebase or tests that did anything but set string varargs for the 'cmd'

johanatan 2016-06-23T03:45:43.000206Z

This was my best attempt in the REPL:

cljs.user=&gt; (planck.shell/sh "0" {:env {"blah" "blah"}})
In: [1] val: ({:env {"blah" "blah"}}) fails spec: :planck.shell/sh-args predicate: (cat :cmd (+ string?) :opts (* :planck.shell/sh-opt)),  Extra input
ERROR

johanatan 2016-06-23T03:47:58.000207Z

@mfikes: ^

mfikes 2016-06-23T03:50:33.000208Z

They are keyword arguments. So

cljs.user=&gt; (planck.shell/sh "env" :env {"foo" "bar"})
{:exit 0, :out "foo=bar\n", :err “"}

mfikes 2016-06-23T03:52:27.000210Z

What’s exciting these days is you can consider using spec to generate example arguments:

cljs.user=&gt; (s/exercise :planck.shell/sh-args)
([("") {:cmd [""]}]
 [("o" "m" :in "9") {:cmd ["o" "m"], :opts [[:in {:key :in, :val "9"}]]}]
 [("" "v0" "Cl" :env {}) {:cmd ["" "v0" "Cl"], :opts [[:env {:key :env, :val {}}]]}]
 [("Gs" "" :in-enc "RFY" :in "G" :out-enc "3dP")
  {:cmd ["Gs" ""], :opts [[:in-enc {:key :in-enc, :val "RFY"}] [:in {:key :in, :val "G"}] [:out-enc {:key :out-enc, :val "3dP"}]]}]
 [("O5" "n7j" "d" "" :out-enc "" :out-enc "K0" :dir "a0a")
  {:cmd ["O5" "n7j" "d" ""],
   :opts [[:out-enc {:key :out-enc, :val ""}] [:out-enc {:key :out-enc, :val "K0"}] [:dir {:key :dir, :val [:string "a0a"]}]]}]
 [("cY2" "6Y0" "I8Da" "F" "" "hDrjK" :in "Pb") {:cmd ["cY2" "6Y0" "I8Da" "F" "" "hDrjK"], :opts [[:in {:key :in, :val "Pb"}]]}]
 [("q4i" :in "7gDvI7") {:cmd ["q4i"], :opts [[:in {:key :in, :val "7gDvI7"}]]}]
 [("G3YDS" "Z2q9" "798rPJT" "8fq" "cN" "u" :env {} :dir "a3oHJ8")
  {:cmd ["G3YDS" "Z2q9" "798rPJT" "8fq" "cN" "u"], :opts [[:env {:key :env, :val {}}] [:dir {:key :dir, :val [:string "a3oHJ8"]}]]}]
 [("e" "3Cibazb0" "F3q" :env {}) {:cmd ["e" "3Cibazb0" "F3q"], :opts [[:env {:key :env, :val {}}]]}]
 [("e44fT" "" "AjhU2X2XC" "8jVEyD3" "SgHp" "R6lKza78P" "TtFDVMdVz" "Se5B53Cdh" "F948Sdg5")
  {:cmd ["e44fT" "" "AjhU2X2XC" "8jVEyD3" "SgHp" "R6lKza78P" "TtFDVMdVz" "Se5B53Cdh" "F948Sdg5"]}])

mfikes 2016-06-23T03:53:10.000211Z

Of course, the spec hasn’t been told that, for example that ”9” is not a legal string encoding 🙂

mfikes 2016-06-23T03:53:36.000212Z

I suppose the spec could also be improved to require non-empty strings, etc.

mfikes 2016-06-23T04:04:51.000213Z

@johanatan: By the way, in case it helps, planck.shell/sh is an imitation of clojure.java.shell/sh https://clojuredocs.org/clojure.java.shell/sh

johanatan 2016-06-23T04:12:16.000214Z

Ahh, nice. I had actually tried a variation of that with :cmd before the first string arg

johanatan 2016-06-23T04:29:41.000215Z

Any idea on this one? Looks like the value I'm specifying for :dir is being sent through as a vector which as-file doesn't have a protocol method define for.

cljs.user=&gt; (planck.shell/sh "0" :env {"zblahbb" "blahzz" "abc" "def"} :dir "/home/jonathan")
No protocol method Coercions.as-file defined for type cljs.core/PersistentVector: [:string "/home/jonathan"]
	cljs.core/missing-protocol (cljs/core.cljs:266:4)
	<http://planck.io/as-file|planck.io/as-file> (planck/io.cljs:259:33)
	planck.shell/sh (planck/shell.cljs:49:60)

johanatan 2016-06-23T04:30:35.000216Z

doh! same error happens when the directory actually exists:

cljs.user=&gt; (planck.shell/sh "0" :env {"zblahbb" "blahzz" "abc" "def"} :dir "/Users/jonathan")
No protocol method Coercions.as-file defined for type cljs.core/PersistentVector: [:string "/Users/jonathan"]
	cljs.core/missing-protocol (cljs/core.cljs:266:4)
	<http://planck.io/as-file|planck.io/as-file> (planck/io.cljs:259:33)
	planck.shell/sh (planck/shell.cljs:49:60)

slipset 2016-06-23T08:35:56.000217Z

@johanatan: there is an error in the spec handling here...

slipset 2016-06-23T08:36:10.000218Z

(s/conform ::sh-args [ "0" :env {"zblahbb" "blahzz" "abc" "def"} :dir "/Users/erik"])
{:cmd ["0"], :opts [[:env {:key :env, :val {"zblahbb" "blahzz", "abc" "def"}}] [:dir {:key :dir, :val [:string "/Users/erik"]}]]}

slipset 2016-06-23T08:45:26.000220Z

https://github.com/mfikes/planck/issues/330

slipset 2016-06-23T08:49:57.000222Z

https://github.com/mfikes/planck/pull/331

slipset 2016-06-23T08:53:22.000224Z

btw, love this one:

slipset 2016-06-23T08:53:42.000225Z

(map (comp (juxt :key :val) second) opts)

slipset 2016-06-23T08:53:54.000226Z

and the fact that I’m able to read what it does 🙂

mfikes 2016-06-23T12:46:52.000227Z

Great catch… merged in the fix 🙂

slipset 2016-06-23T12:54:52.000228Z

My pleasure 🙂

johanatan 2016-06-23T14:15:27.000229Z

@mfikes: after taking your latest commits, I'm seeing the following error:

Jonathans-MacBook-Pro:planck-c jonathan$ ./planck 
Planck 2.0
WARN: no bundled sources, need to run script/bundle-c
ClojureScript (Unknown)
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
    Exit: Control+D or :cljs/quit or exit or quit
 Results: Stored in vars *1, *2, *3, an exception in *e

WARN: no bundled sources, need to run script/bundle-c
The goog base JavaScript text could not be loaded

johanatan 2016-06-23T14:15:39.000230Z

i don't see a script/bundle-c anywhere

mfikes 2016-06-23T14:16:35.000231Z

Do make bundle-and-build in the planck-c at least once to get it bundle things up. The bundle-c script is off in another part of the tree but the makefile knows where to run it

johanatan 2016-06-23T14:17:03.000232Z

ahh, ok

mfikes 2016-06-23T14:17:18.000233Z

After that, you can simply do make to build the native part quickly

mfikes 2016-06-23T14:17:54.000234Z

(You can rapidly iterate on the native part, with bundle.c containing all of the AOT-compiled JavaScript.)

johanatan 2016-06-23T14:18:15.000235Z

yea, that's what i've been doing and so forgot about the initial make bundle-and-build

johanatan 2016-06-23T14:18:36.000236Z

i did check that bundle.h/c were present though and they were-- i suppose they were perhaps stale due to the code changes though

johanatan 2016-06-23T14:28:09.000240Z

oops, sorry. nevermind

mfikes 2016-06-23T14:28:55.000244Z

Yeah, IIRC they start off “empty"

johanatan 2016-06-23T14:29:10.000245Z

ya, :cmd isn't part of the options hash

johanatan 2016-06-23T14:29:23.000246Z

just needs to be flattened list of strings

mfikes 2016-06-23T14:30:20.000247Z

Don’t understand… unless you are saying that the command is just the initial segment of the argument list that is strings, until you hit the first non-string.

johanatan 2016-06-23T14:30:32.000248Z

yes, i think that's right

mfikes 2016-06-23T14:30:36.000249Z

yep

johanatan 2016-06-23T14:30:51.000250Z

the first non-string being a keywd to denote which part of options follows

mfikes 2016-06-23T14:31:28.000251Z

spec’s regular expression machinery (`cat`, et. al.) is awesome for expressing these concepts

johanatan 2016-06-23T14:31:49.000253Z

ya, i saw cat but didn't dig into what it means just yet 🙂

mfikes 2016-06-23T14:33:02.000254Z

The high level idea is that a structure can be a sequence or a map. cat is perhaps the top-level for the first, while keys is the top-level for the other. (probably not 100% accurate), but fits my mental model for now.

johanatan 2016-06-23T14:36:21.000255Z

haha, right

johanatan 2016-06-23T14:37:54.000256Z

one question: should it be safe to take a c-string obtained from value_to_c_string and do an unbounded strlen or other str operation on it? I am imagining so as I can't see how one could get an unbounded string from ClojureScript through the JS machinery and into these native bits

johanatan 2016-06-23T14:39:04.000257Z

i.e., it should be safe to assume that the strings obtained in this manner are null-terminated

johanatan 2016-06-23T16:20:03.000259Z

@mfikes: ^

johanatan 2016-06-23T16:21:34.000260Z

one other thing: can you explain what self.context is/where it comes from and how it is different than ctx (if it is actually different)? I don't think I have anything analogous to that in the native function: https://github.com/mfikes/planck/blob/7b8fb645177a5828de87b51cca9ab883402e9436/planck/PLKClojureScriptEngine.m#L638-L640 would it be ok to just create those return values on the ctx that is passed into the function?

mfikes 2016-06-23T16:26:04.000262Z

@johanatan: It should be safe to assume that C strings obtained from that function are NULL-terminated.

johanatan 2016-06-23T16:26:29.000263Z

and for my second question, i just went ahead and tried it with ctx and it seems to work

mfikes 2016-06-23T16:26:44.000264Z

@johanatan: self.context and ctx would be the same thing

johanatan 2016-06-23T16:26:48.000265Z

ahh, nice

johanatan 2016-06-23T16:26:59.000266Z

so, i have a working example here now. it handles env and dir

johanatan 2016-06-23T16:27:08.000267Z

might be ready for PR/review

mfikes 2016-06-23T16:27:12.000268Z

Very nice!!!

mfikes 2016-06-23T16:27:52.000269Z

(It doesn’t have to be absolutely perfect… the 2.0 branch being under construction.)

johanatan 2016-06-23T16:27:56.000270Z

i still need to make it handle :in if provided

johanatan 2016-06-23T16:27:58.000271Z

ok, cool.

johanatan 2016-06-23T16:28:13.000272Z

in that case, i'd say let's go ahead and get a PR in for this as it would be super useful even without :in support

mfikes 2016-06-23T16:28:21.000273Z

Yes, I agree 🙂

mfikes 2016-06-23T16:28:43.000274Z

It may even get us to the point where we can run the existing test infrastructure which uses sh

johanatan 2016-06-23T17:11:43.000275Z

https://travis-ci.org/mfikes/planck/builds/139812933

johanatan 2016-06-23T17:12:01.000276Z

Line 498 says the binary was placed but line 499 couldn't find it

johanatan 2016-06-23T17:12:08.000277Z

Not sure how it has anything to do with my changes

johanatan 2016-06-23T17:12:37.000278Z

Oops, i see some errors above that

mfikes 2016-06-23T17:13:28.000279Z

Right… dunno where those defines are supposed to come from

johanatan 2016-06-23T17:13:49.000280Z

stdio.h apparently

johanatan 2016-06-23T17:13:51.000281Z

which is included

johanatan 2016-06-23T17:14:18.000283Z

oh, oops. unistd.h

johanatan 2016-06-23T17:14:24.000284Z

i'll try adding an explicit include to that one

mfikes 2016-06-23T17:14:27.000285Z

Yeah

johanatan 2016-06-23T17:19:04.000286Z

Looks like that fixed it

mfikes 2016-06-23T17:32:49.000287Z

@johanatan: Looks like you may have inadvertently left some debug console printing

johanatan 2016-06-23T17:32:58.000288Z

oh, that was intentional.

johanatan 2016-06-23T17:33:13.000289Z

there are some other #ifdef DEBUGs in the project

johanatan 2016-06-23T17:33:27.000290Z

[but i just found a bug in read_child_pipe]

mfikes 2016-06-23T17:33:45.000291Z

OK… that’s likely to cause it to not be usable when running the existing integration tests

mfikes 2016-06-23T17:34:03.000292Z

Will see...

johanatan 2016-06-23T17:34:05.000293Z

oh, i can remove them (or hide them behind a diff flag like SHELLDEBUG)

mfikes 2016-06-23T17:34:52.000294Z

Very cool. It’s working 🙂 !!!

🦜 1
johanatan 2016-06-23T17:38:17.000295Z

Ok, i just pushed the bug fix for read_child_pipe.

johanatan 2016-06-23T17:41:39.000296Z

[and removed DEBUG prints]

mfikes 2016-06-23T17:50:32.000297Z

@johanatan: Cool. Perhaps after that is in, I can make some new Linux binaries and put them on the Planck alpha download page 🙂

mfikes 2016-06-23T17:50:49.000298Z

This is good stuff 🙂

johanatan 2016-06-23T18:20:20.000299Z

Should be good to go now. 🙂

johanatan 2016-06-23T18:20:40.000300Z

Ahh, I see you merged it. 🙂

mfikes 2016-06-23T18:23:12.000301Z

@johanatan: Yeah, I merged prior to your latest push. (Sigh, mutable PRs.)

johanatan 2016-06-23T18:23:35.000302Z

Oooh, do i need to create another one?

mfikes 2016-06-23T18:23:54.000303Z

Yes… your latest stuff is not in Planck master

johanatan 2016-06-23T18:24:28.000304Z

Hmm, not sure how to do that. I don't see any "create PR" button on my fork now

johanatan 2016-06-23T18:25:25.000305Z

Oops, nevermind. Found it

johanatan 2016-06-23T18:28:42.000306Z

[Sorry about the race condition-- i figured i could get the fix in before you merged the PR]

mfikes 2016-06-23T18:30:16.000307Z

No problem. (This is one of the reasons Cognitect only accepts patches, evidently.)

johanatan 2016-06-23T18:35:39.000308Z

Do tests pass with the DEBUG statements removed?

mfikes 2016-06-23T18:48:04.000309Z

Yes https://travis-ci.org/mfikes/planck/builds/139841792

mfikes 2016-06-23T18:48:33.000310Z

But… if you are asking about the full Planck test suite… not yet… there are other things failing stil.

johanatan 2016-06-23T22:16:09.000313Z

Hmm, I don't see any tests in this one-- only the build itself: https://clojurians.slack.com/archives/planck/p1466707684000309

mfikes 2016-06-23T22:18:49.000315Z

Right. Travis CI is currently only being used to assure Planck 2.0 can be built.

johanatan 2016-06-23T22:21:36.000316Z

Right, so when I asked about the tests, I meant the ones that you said might run with the impl of sh with debugging removed.

johanatan 2016-06-23T22:29:44.000317Z

[or were you just referring to the build itself?]

mfikes 2016-06-23T22:34:30.000318Z

@johanatan: I was referring to the stuff exercised by script/test (and script/test-c)

mfikes 2016-06-23T22:35:30.000319Z

script/test-c doesn't fully work yet given the gaps that Planck 2.0 has relative to 1.x

johanatan 2016-06-23T22:38:36.000320Z

ahh, but sh gets us closer to the target I presume?

mfikes 2016-06-23T22:39:55.000321Z

Part of Planck's tests originate from prior to cljs.test being functional under bootstrap, and involve crude comparisons of stdout with what is expected. (So writing debug output would cause those crude tests to fail.)

mfikes 2016-06-23T22:41:21.000322Z

And, yes, parts of the test infrastructure use Planck itself to run scripts. Your changes will help Planck fundamentally be able to execute all of that on Linux.

johanatan 2016-06-23T23:20:31.000323Z

Nice. And I removed the DEBUG prints so should be good to go in that respect.

johanatan 2016-06-23T23:23:35.000324Z

So, next step for me will be to get async version of sh going. Do you have any guidance on how to accomplish? Should I add a dependency on core.async and add a new function: sh-async which returns a channel which the {:out ... :err ... :status ..} payload is sent over when available?

johanatan 2016-06-23T23:23:45.000325Z

@mfikes: ^

mfikes 2016-06-23T23:28:45.000326Z

@johanatan: I wouldn't force people to take on a core.async dep, but instead support a callback. A callback can be converted to core.async by users interested in it. This is also good post in the subject: http://www.lispcast.com/core-async-code-style

johanatan 2016-06-23T23:29:18.000328Z

Ah, yea, I remember that. As long as the callback is the last argument or something, there's an automatic conversion?

johanatan 2016-06-23T23:30:17.000329Z

are you ok with the name sh-async or is there a common naming pattern for that sort of thing?

mfikes 2016-06-23T23:32:19.000330Z

There is no automatic conversion, but it is easy for a client to pass a in lambda that puts a result on a channel.

mfikes 2016-06-23T23:35:01.000331Z

In terms of API, I'd take a look at the http and other APIs in Planck to get a sense. (I suspect a new arity won't work, and http and sh have different ways of passing optional stuff, so maybe -async might feel right in the end.) might be worth experimenting

mfikes 2016-06-23T23:35:58.000332Z

API design is hard :(

mfikes 2016-06-23T23:38:33.000333Z

@johanatan: I'd suggest looking at cljs.js. It went with cb as last argument

mfikes 2016-06-23T23:39:23.000334Z

(Damn, sh has no "last" argument.)

johanatan 2016-06-23T23:41:37.000335Z

@mfikes: pretty sure there is an automatic conversion provided by promesa or one of the libs I used recently

johanatan 2016-06-23T23:42:30.000337Z

i have an example if you'd like me to dig up the code. 🙂

mfikes 2016-06-23T23:42:56.000338Z

Is promesa a Clojure library?

johanatan 2016-06-23T23:44:15.000339Z

Yep

johanatan 2016-06-23T23:44:27.000340Z

https://funcool.github.io/promesa/latest/

mfikes 2016-06-23T23:46:10.000341Z

Ahh. Yeah. Zach Tellman also has a set of async abstractions.

johanatan 2016-06-23T23:46:11.000342Z

oh, no. actually it was &lt;&lt;&lt; from here: http://www.lispcast.com/core-async-code-style

mfikes 2016-06-23T23:46:32.000343Z

Right.

johanatan 2016-06-23T23:46:34.000344Z

which i adapted to my purposes

mfikes 2016-06-23T23:47:26.000345Z

Seems like accepting a cb then allows for any preferred style to be used on top of it.

johanatan 2016-06-23T23:47:31.000346Z

Yep

johanatan 2016-06-23T23:47:50.000347Z

But how to handle the fact that our arg list is variadic?

mfikes 2016-06-23T23:48:02.000348Z

Exactly :)

johanatan 2016-06-23T23:48:26.000349Z

I'm thinking another wrapper that does: (sh-async other-args :cb callback) might work

mfikes 2016-06-23T23:48:36.000350Z

Yep

mfikes 2016-06-23T23:50:18.000351Z

It is tempting to revise sh to return nil if :cb is present. Wonder if that would be natural or a hack

mfikes 2016-06-23T23:51:39.000352Z

Almost any sync API can be revised to return nil for the callback arity or optional cb case. Wonder if that is a common pattern or an anti-pattern

mfikes 2016-06-23T23:57:07.000354Z

Maybe a separate -async fn is cleaner than trying to complect the two