Fork me on GitHub
#babashka
<
2023-09-25
>
joost-diepenmaat11:09:08

I’m trying to count unicode code points. Not sure why the following works in Java but not in bb:

(.count (.codePoints "woof🐕"))


java=> 5
bb=> java.lang.NoSuchFieldException: count [at <repl>:13:1]

joost-diepenmaat11:09:20

in bb v1.3.184, clojure 1.11.1 Java 20.0.2

lispyclouds11:09:58

bb is based on JDK 19, does this method exist at that version?

borkdude11:09:44

this is just a matter of adding the right class to the class configuration in babashka, it's just not included yet

2
borkdude11:09:56

feel free to post an issue

joost-diepenmaat11:09:14

Not sure when this was added, the Java APIdocs mention it in Java SE8: https://docs.oracle.com/javase/8/docs/api/java/util/stream/IntStream.html#count--

joost-diepenmaat11:09:19

Though that documentation looks suspicious;; pretty sure `

return mapToLong(e -> 1L).sum();
 
is not valid java 8

borkdude11:09:06

bb isn't based on java 8 for a long time, don't see how that point is relevant

borkdude11:09:22

it's just a config issue with bb

joost-diepenmaat11:09:47

It’s relevant if count was added in jdk20. but I’ll add an issue later today

borkdude11:09:10

ah so it's 19 vs 20 issue, that actually makes sense

borkdude11:09:12

then why does count show up in the java 8 docs

joost-diepenmaat11:09:39

I don’t understand the java8 documentation 🙂 so I don’t know. I’ll do some experiments first to see when that was added.

borkdude11:09:04

This works on Java 19 for me:

(.count (.codePoints "woof🐕"))

borkdude11:09:12

so it should also work on bb which is based on 19 right now

lispyclouds11:09:46

yeah looks like its added on java8

joost-diepenmaat11:09:44

Ok i’ll add an issue later today. Thanks!

borkdude11:09:02

actually the Stream class also has a count method, so I'd expect this to already work somehow...

borkdude11:09:19

somehow this doesn't work:

(let [^java.util.stream.Stream x (.codePoints "woof")] (.count x))

borkdude11:09:26

is IntStream not a subclass of Stream?

borkdude11:09:48

a fun jungle of classes...

lispyclouds11:09:17

Stream seems to be a sibling of IntStream

borkdude11:09:25

adding the class + a cast from a private object to that class seems to work:

$ ./bb -e '(.count (.codePoints "woof🐕"))'
5

borkdude11:09:42

Adds 126 kb to bb though :/

borkdude11:09:36

how do you pull up that hierarchy?

borkdude12:09:11

IntStream is a BaseStream

borkdude12:09:09

but BaseStream doesn't have .count, this is why it doesn't work in bb currently

borkdude12:09:06

@U09N5N31T This currently works in bb as a workaround: (count (iterator-seq (.iterator (.codePoints "woof")))) => 4

borkdude12:09:48

ok, we'll just add IntStream then, seems fundamental enough for 100kb

borkdude12:09:35

guess we can wait for LongStream and DoubleStream until someone runs into it

borkdude12:09:45

fixed here: https://github.com/babashka/babashka/pull/1625 use the recommend workaround meanwhile

borkdude13:09:43

lol, this test succeeded in the PR but on master:

lein test :only babashka.interop-test/IntStream-test
FAIL in (IntStream-test) (interop_test.clj:46)
expected: (= 5 (bb nil "(.count (.codePoints \"woof?\"))"))
  actual: (not (= 5 6))
Apparently there is something weird with codepoints on Windows. I'll just change the test to pos?

joost-diepenmaat14:09:41

Maybe something is off in the source file encoding?

borkdude14:09:56

yeah, I'll just let windows deal with windows

borkdude14:09:54

just use this for now as a workaround: (count (iterator-seq (.iterator (.codePoints "woof")))) - your original code will work only from the next release on

danm13:09:32

Is anyone who's used (preferably dug into the code of) awyeah-api for using Cognitect-style calls within babashka about? I'm trying to execute a request against the AWS API, which works in the actual Cognitect libs. I'm already executing various other requests (including against SecurityHub), which work with awyeah-api. My bb.edn contains:

:deps {com.cognitect.aws/endpoints {:mvn/version "1.1.12.504"}
        com.cognitect.aws/securityhub {:mvn/version "848.2.1413.0"}
        com.cognitect.aws/sns {:mvn/version "847.2.1365.0"}
        com.grzm/awyeah-api {:git/url ""
                             :git/sha "9257dc0159640e46803d69210cae838d411f1789"
                             :git/tag "v0.8.41"}
        org.babashka/spec.alpha {:git/url ""
                                 :git/sha "8df0712896f596680da7a32ae44bb000b7e45e68"}}
The request I'm trying to execute is:
(require '[com.grzm.awyeah.client.api :as aws])
(aws/invoke
    (aws/client {:api :securityhub})
    {:op :BatchUpdateFindings,
     :request {:FindingIdentifiers [{:Id "arn:aws:inspector2:eu-west-2:${MY_ACCOUNT_ID}:finding/e7fcfd57f44eac3fcf45419912f99b14",
                                     :ProductArn "arn:aws:securityhub:eu-west-2::product/aws/inspector"}],
               :Note {:Text "Status changed from NEW to NOTIFIED", :UpdatedBy "DanM testing"},
               :Workflow {:Status "NOTIFIED"}}}))
I get back a NullPointerException stacktrace from the awyeah http-client (it's long, so I'll put it in a thread on this message)

danm13:09:15

I'm trying to look at debugging that

danm13:09:00

Oh, of note is that I'm using exactly the same com.cognitect.aws/securityhub version in full Clojure with the real Cognitect lib, where it works

danm13:09:48

And ${MY_ACCOUNT_ID} is replaced with my actual account ID when I execute the code

danm13:09:13

That stacktrace doesn't seem to contain anything from within awyeah-api, it's all just sci and Java proper, from what I can see...

danm14:09:08

Ahha, I get a much more readable stacktrace if I try in full Clojure

borkdude14:09:02

yeah, I was going to suggest, try the same code in a JVM

danm14:09:17

Ahha! Think I've got it

borkdude14:09:22

hopefully you found it using that approach? cool

danm14:09:33

Pretty certain that's a typo

danm14:09:39

That key should be :patch

borkdude14:09:52

aaah makes sense. I bet @U0EHU1800 would accept a PR for that

danm14:09:08

I know my request is a :patch request, so I think we're looking up into there are getting back a nil method

danm14:09:12

I've just forked to test

danm14:09:34

He actually has a PR template that explicitly says he doesn't accept PRs and to raise an issue 😉 But I can do that too no worries once I've proved it

grzm14:09:50

That seems prima facie reasonable. I'll take a look tonight. Thanks for digging in!

danm08:09:46

Awesome, thanks very much @U0EHU1800 😄

borkdude15:09:00

I'm sometimes tempted to make a language front-end to babashka which uses JS or Java-ish syntax so people in those languages can script in babashka, but every time I end up with the conclusion that they should just learn Clojure and nowadays just paste their inputs into ChatGTP to get started ;)

😆 1
👀 1
borkdude15:09:09

Technically it's very doable though

mmer15:09:40

Are you talking about a JS to Clojure(SCI) compiler/interpreter?

elken15:09:40

What's the opposite to squinting? 😛

respatialized15:09:08

https://docs.racket-lang.org/rhombus/index.html You might look into Rhombus, an experimental version of Racket that provides a more "conventional" syntax for Racket s-expressions, though it is more similar to Python (e.g. syntactically significant indentation) than JS in its notation.

borkdude15:09:57

> Are you talking about a JS to Clojure(SCI) compiler/interpreter? I'm talking about a JS/Java-ish to Clojure transpiler which is then being fed into bb. So same APIs, just different syntax

borkdude15:09:41

yeah, same idea as rhombus but a syntax that people already know

borkdude15:09:41

I think Java (or Kotlin) syntax might make most sense as people who already know the JVM might be more tempted to use bb

mmer15:09:11

I have to admit that I find my use of clojure spurned by my colleagues even if I show that I can perform tasks fast with it.

borkdude15:09:16

I wonder how you would express stuff like (-> (foo) :bar :baz) in Java though

borkdude15:09:58

->(foo(), ..., ...)
not even sure how to express keywords, it's gonna be a shit show probably

borkdude15:09:15

maybe foo().:foo().:bar()

mmer15:09:15

Would you be better starting out with something like C, so that you don't have the weight of classes etc.

borkdude15:09:38

yeah, I was planning to just start with a subset of Java, no class stuff

borkdude15:09:45

just C-style syntax is the main point

mmer15:09:46

Just for interest what got you thinking down this path?

borkdude15:09:40

I'm considering doing more reaching out to non-Clojure developers for babashka, but I wonder if there's any real interest in this from non-Clojure people. I could imagine that there's JVM developers that want to build there bash-like scripts in something they could easily read and still also use JVM interop in places

james15:09:28

Groovy support maybe, it's used in Jenkins and you can use it with Spring.

borkdude15:09:20

that also crossed my mind

Bob B21:09:25

re: the threading example, I think the method chaining is a viable translation, of course the question becomes are keywords an acceptable departure from 'familiar' syntax, and maybe will keywords make sense in method position... I could imagine a really verbose translation that could probably be Java being something like foo().get(new Keyword("bar")).get(new Keyword("baz")) , and maybe somewhere in that spectrum is what's comfortable for a "Java audience".

borkdude21:09:59

yeah, the new Keyword thing is what I don't find acceptable compared to Clojure :)

Bob B22:09:13

To be clear, I'm not saying this is a desirable outcome per se', but something like a colon could be a (stretched) version of Kotlin's operator overloading. Just to sort of make the argument that a colon followed by a symbol could be somewhat correlated to a curly-braced dialect, I overrode ! on Strings in Kotlin to produce this code which 'works'™️ :

data class Keyword(val name: String)

operator fun String.not() = Keyword(this)

operator fun <T> Map<T, *>?.get(k: T) = if (this != null) this[k]
else null

val m = mapOf(!"bar" to mapOf(!"baz" to "abc"))

m[!"bar"][!"baz"] // "abc"
m[!"bar"][!"bat"] // null

Bob B22:09:14

it's not perfect (probably not even good), but it could be a step toward saying "`:abc` could be shimmied into a curly-brace language"

jackrusher23:09:13

I’ve been thinking about an alternative infix syntax for Clojure for awhile. For what it’s worth, I think something like rhombus or dylan would be a better starting point than a Java-derived syntax.

👍 1
borkdude09:10:02

you can already see how hard it is to properly expose Clojure to a mainstream dialect

borkdude09:10:37

A bit more palatable by introducing some helper fns:

mmer09:10:20

In the language could you do the resolving through some kind of import header syntax and so remove the need to the resolve and helper functions?

borkdude09:10:06

I guess so, a custom ns form

borkdude10:10:19

@U4C3ZU6KX this works now ;)

borkdude10:10:58

Special template strings for keywords and symbols:

mmer11:10:16

if you are exposing the idea of a keyword in this mini language why not just use : or do you have to expose the idea of keywords? Also is the idea of a keyword as a function really working in that last example, it seems quite subtle to me.

borkdude11:10:13

because : isn't JS syntax, the JS parser I'm using doesn't get that

borkdude11:10:26

yes, it works

mmer11:10:50

OK, now I understand where you are coming from.

mmer11:10:55

I was just thinking the get (response, k'status')

borkdude11:10:13

that works too

borkdude11:10:32

but k and s templates work at compile time

borkdude11:10:44

such that the transpiled code is (:status ...)

borkdude11:10:52

this doesn't work for calling pr-str in Clojure: ((symbol "pr-str" ...)) but

s`pr-str`(...)
translates into
(pr-str ...)
because the conversion is done at compile time

borkdude11:10:27

anyway these are just fun hacks, nothing serious