Fork me on GitHub
#babashka
<
2020-05-20
>
seancorfield03:05:25

I'm having my first real interaction with sci this evening, via the new extension machinery in Chlorine, that lets you write editor extensions in Clojure, that are executed via sci... and I have a question: how do you try/catch exceptions?

seancorfield03:05:32

I tried (try ... (catch Throwable t ...)) but I get errors that Throwable is unknown (as has every class name I've tried).

seancorfield03:05:13

Hmm, (catch Error e ...) seems acceptable...

didibus04:05:49

Chlorine is probably using the ClojureScript version of Sci @seancorfield. So all interop-ish code should be with the expectations of JavaScript.

seancorfield04:05:05

@didibus Thanks. That makes sense. I hadn't thought about the Clojure/Script dialect issue. I stumbled across catch Error pretty much by accident.

seancorfield04:05:48

Chlorine is using a variant that has special semantics for let so it does automatic await on promises, to improve interop with the editor primitives.

seancorfield04:05:55

It's very cool 🙂

nate05:05:13

Wow. Very cool indeed.

mbjarland10:05:06

I'm digging into getting the oracle jdbc driver working with babashka (potentially a pod-to-be, right now just trying to get the basics working) and running into this:

clojure.lang.ExceptionInfo: Can't call public method of non-public class: public synchronized void oracle.jdbc.driver.PhysicalConnection.close() throws java.sql.SQLException [at /home/mbjarland/projects/clojure/babashka/matias/jdbc-test.clj, line 26, column 3]
when trying to close a connection using next-jdbc and with-open. The connection class is actually a T4CConnection which inherits from PhysicalConnection and neither of those classes are public (i.e. they are package private). I have run a fairly large number of permutations on the reflection settings (i.e. allDeclaredClasses, allDeclaredMethods, etc), recompiling babashka etc including setting all the reflection settings I could find to true for these classes. If anybody knows of a way to fix the above in graalvm it would be much appreciated.

mbjarland10:05:50

should be noted that the query works, just the closing of the connection that fails

borkdude10:05:52

Can you try casting the connection to a public class before calling close on it?

mbjarland10:05:18

nope since I'm neither creating it nor closing it

mbjarland10:05:28

this is created behind the scenes by next-jdbc

mbjarland10:05:51

I could naturally try to instantiate the class myself etc, but that would not match a normal use case I think

mbjarland10:05:01

the relevant close method signature:

public synchronized void close() throws SQLException {

mbjarland10:05:29

well, correction, since I'm using with-open I am closing it

mbjarland10:05:42

but the connection class gets created by the databasource based on the jdbc url

mbjarland10:05:58

i.e. something like this:

(let [ds (jdbc/get-datasource {:jdbcUrl url :user "core" :password "core"})]
  (with-open [c (jdbc/get-connection ds)]
    (prn :connection c)
    (println "result:" (jdbc/execute! c ["select 1 from dual"]))))

borkdude10:05:08

can you try (with-open [^java.sql.Connection c ..])

mbjarland10:05:17

give me a sec

borkdude10:05:47

are you running this code in babashka itself?

mbjarland10:05:02

yes running it in babashka from command line

mbjarland10:05:08

custom compiled bb but still

borkdude10:05:12

but if you are going to make this into a pod, you should not have to run the code through sci/babashka.

borkdude10:05:20

it's just going to be graal compiled directly

mbjarland10:05:26

umm Unable to resolve classname: java.sql.Connection

borkdude10:05:05

have you added that to the reflection config

mbjarland10:05:14

right, I'm with your there, I just did a branch with oracle as a feature and completed it to 90% and wanted to see it working before embarking on the next thing

mbjarland10:05:22

nope, will do

borkdude10:05:10

so if the type hint doesn't work (which I think won't since the usage of type hints in sci is not so good yet), then take a look at this: https://clojurians.slack.com/archives/CLX41ASCS/p1589970216129000?thread_ts=1589969930.126200&amp;cid=CLX41ASCS

mbjarland10:05:11

need a few mins for a recompile

borkdude10:05:32

it tries to cast private classes to public ones

borkdude10:05:49

and then does the reflection on that

mbjarland10:05:20

ah, so I could have something saying if it implements java.sql.Connection cast it to one

mbjarland10:05:29

ok, will try both

mbjarland10:05:50

I assume an oracle feature is no longer relevant with the introduction of pods?

mbjarland10:05:23

type hint worked

borkdude10:05:30

yeah, think so. I think it's better to extend the hsqldb pod code to accommodate more drivers.

mbjarland10:05:33

it does force the user to make a cast

borkdude10:05:53

yeah, the private handling code I mentioned does take care of that

mbjarland10:05:36

well that is certainly useful for my personal use of bb : )

borkdude10:05:10

so instead of compiling one binary pod.babashka.hsqldb the same code can compile both binaries pod.babashka.oracle, using feature flags similar to bb

mbjarland10:05:17

also oracle is somewhat of a pain with the reflection stuff and also requires things like this:

"--allow-incomplete-classpath"                                                                                         
        "--initialize-at-run-time=oracle.jdbc.driver.OracleTimeoutThreadPerVM"                                                 
        "--initialize-at-run-time=oracle.sql.LnxLibServer"                                                                     
        "--initialize-at-run-time=oracle.sql.LoadCorejava"   

borkdude10:05:37

yeah, we can let the pods deal with this pain instead of babashka 🙂

mbjarland10:05:15

but you are in-line with essentially creating one 'jdbc-pod' based on the hsqldb one which would then compile multiple binaries, one per driver?

borkdude10:05:00

PRs to babashka.pod.hsqldb are welcome. we can change the name of the repo eventually

mbjarland10:05:03

ok, we'll see, I occasionally have to spend time on my day job, but I'll start digging

borkdude10:05:34

but if you want, a feature flag to bb for oracle is also welcome. both are possible

mbjarland10:05:45

I'll save the oracle insanity away on a branch for reference. Ok thanks for the input, was stuck on that one for a while

borkdude10:05:11

my hope is that pods will overtake the need for feature flags

borkdude10:05:30

but there might be some limitations to pods, so we'll see how far it gets

mbjarland10:05:58

I'm wondering about the performance aspects of shuffling large amounts of data over bencode and stdin etc

mbjarland10:05:17

as sql could definitely result in large amounts of data

borkdude10:05:56

well, it's all still in memory so should be relatively fast

borkdude11:05:51

Made one change to the async way of working with pods: the :done callback should be independent from the :success callback since the :done message may be sent after the last value has already been sent. https://github.com/babashka/babashka.pods#async Last chance for feedback until I release this. Core.async has been removed from pods. cc @retrogradeorbit

retrogradeorbit12:05:46

I havent had a chance to actually work with the async yet. But the docs look good. I like the simplicity. done being separate from success is good. reminds me of the step/completion seperation in transducers. And of nrepl proto.

borkdude12:05:27

One thing I'm still bike-shedding about: should on-success receive the value directly, or a map with :value so we can add more to it later (prevent breaking)

retrogradeorbit13:05:01

backwards compatability could be preserved later without a hashmap in the callback by changing the invoke call itself

borkdude13:05:00

right, we can add :success2 later

retrogradeorbit13:05:26

like invoke calls back on-success with just the answer. Then later its realised something more must be added. invoke2 calls back with sheep and wood. or :opts :v2. ot :success2 yeah

retrogradeorbit13:05:01

which preserving the old methods

borkdude13:05:56

so you have :error which does receive a map with :ex-message, etc. :success which receives the "naked" return vals and :done which receives one map with undefined vals currently?

retrogradeorbit13:05:12

the implementer can also bolt their own values on by passing a partial

retrogradeorbit13:05:07

done could be 0-arity too

borkdude13:05:02

I'm not worried about the implementer not being able to bolt values on. I'm worried about us not being able to bolt new values on. all callbacks currently receive maps which is uniform

retrogradeorbit13:05:03

yep. but that can all be handled by a different pod/invoke interface

retrogradeorbit13:05:43

just thinking about other event callbacks in other systems, and the success callback is just directly handed the value

borkdude13:05:24

that's because they weren't thinking of breaking changes maybe? 😉

borkdude13:05:55

we could also have one giant callback which receives all the data possible... just the bencode message basically...

retrogradeorbit13:05:08

you can also implement invoke as a call to invoke-v2 later with :success (fn [{:keys [value foo]}] (success-v1 value))

retrogradeorbit13:05:53

on the flipside, its not that big a deal having hashmaps to all. It's not like you are writing a tonne of these.

retrogradeorbit13:05:34

I vote for passing the value plainly

retrogradeorbit13:05:57

but then again...

retrogradeorbit13:05:27

#(put! c %) vs #(put! c (:value %))

borkdude13:05:12

note that the pod itself won't expose :value to the caller. it will just provide a wrapper function that does this on behalf of the user and passes the value on to the user's callback (or async channel, if it wishes to work with core async)

borkdude13:05:31

so what the user of that pod sees is:

[path cb opts]
where cb directly gets the value

borkdude13:05:42

but we can make it easier for pod implementers too. just provide the convenience callbacks and one :raw callback with basically all the data

retrogradeorbit13:05:53

ah ok. so an internal implementation question?

retrogradeorbit13:05:12

yeah give the pod implementer options

retrogradeorbit13:05:32

hashmap with one value is fine. :raw option is good.

borkdude13:05:20

You mean in addition to :success or instead of :success etc?

borkdude13:05:32

It will be very common to receive values which probably deserves its own callback, like error and done. Then raw can contain all of these things and more, basically a representation of the bencode response

samedhi16:05:15

I am looking to use clojure.zip from within babashka. I see https://github.com/borkdude/babashka#babashkaclasspath but am unclear exactly how I would bring in clojure.zip with it?

borkdude16:05:50

@kolhar730 clojure.zip is part of the latest babashka

samedhi16:05:49

So I should be able to just do (require '[clojure.zip :as zip]) with latest?

samedhi16:05:01

Thank you, that worked.

samedhi16:05:07

Also, I have a bunch of bb scripts sitting at https://github.com/samedhi/ctci for "Cracking the Coding Interview" that I have done using bb. I like the instant feedback loop of using bb + entr and just running my test in the ns in which I do the problem. Much appreciated.

borkdude17:05:26

All done using bb? Cool!

borkdude14:05:54

Might make sense to mention how to run them in the README, like with babashka and entr

samedhi17:05:26

Thank you, I have done so.

borkdude20:05:13

babashka v0.0.97: https://github.com/borkdude/babashka/releases/tag/v0.0.97 Notable change: asynchronous pod functions may now take callbacks instead of being coupled to core.async. See https://github.com/babashka/babashka.pods#async. One example of a pod taking a callback is the filewatcher pod: https://github.com/babashka/pod-babashka-filewatcher