Fork me on GitHub
#clojure
<
2023-09-06
>
λ14:09:39

Total beginner here. I want to create an AWS Lambda function with Clojure. I am getting the following error and need help figuring out how to proceed.

{
  "errorMessage": "class java.util.LinkedHashMap cannot be cast to class com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification is in unnamed module of loader com.amazonaws.services.lambda.runtime.api.client.CustomerClassLoader @2e817b38)",
  "errorType": "java.lang.ClassCastException",
  "stackTrace": [
    "example.core$_handleRequest.invokeStatic(core.clj:12)",
    "example.core$_handleRequest.invoke(core.clj:12)",
    "example.core.handleRequest(Unknown Source)",
    "java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)",
    "java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)",
    "java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)",
    "java.base/java.lang.reflect.Method.invoke(Unknown Source)"
  ]
}
What am I doing wrong in the code?
(ns example.core
  (:gen-class :name example.core
              :main false
              :implements [com.amazonaws.services.lambda.runtime.RequestHandler])
  (:import com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification$S3EventNotificationRecord
           [com.amazonaws.services.lambda.runtime.events S3Event]
           [com.amazonaws.services.lambda.runtime Context RequestHandler])
  (:require [clojure.pprint :as pp]))



(defn -handleRequest ^String
  [^RequestHandler _this ^S3Event event ^Context _context]
  (.getRecords event))

p-himik14:09:44

A more appropriate place is #C053AK3F9. Also, impossible to answer such questions when there's no code.

λ14:09:10

Sorry, I sent the message to channel accidentally while editing it

Alexander Bird14:09:29

Pardon me if this is an ignorant question here, but what is “line” where the community feels like a question belongs in #C053AK3F9? And feel free to point me to existing notices where I might have missed that definition. I am now wondering if there is such a thing as “too basic” of a question to belong in this #C03S1KBA2 channel, and so the clarification will help me in the future I’m sure, since I’m also a beginner. 😅

p-himik14:09:47

> what is “line” where the community feels like a question belongs in #C053AK3F9? Whenever a person is a total beginner. :) Some questions by beginners would of course be appropriate for #C03S1KBA2 or #C03S1L9DN or some other channels. But most of the time beginners can't judge that themselves, whereas kind people in #C053AK3F9 are always happy to point them in the right direction.

2
2
👍 2
Ed14:09:33

The api docs for the interface you're trying to implement (https://javadoc.io/static/com.amazonaws/aws-lambda-java-core/1.2.1/com/amazonaws/services/lambda/runtime/RequestHandler.html ???) suggest that you're supposed to return a specific event type, but you're returning the result of (.getRecords event) which is probably a LinkedHashMap?

λ14:09:30

I don’t know much Java, but my assumption is that you inferred that from RequestHandler<I,O>

λ14:09:23

Which, from my understanding, is a Generic, would the corrective step then be to implement this RequestHandler in Clojure?

Ed14:09:12

O handleRequest(I input, Context context) in the method has 2 generics in it. I which is the input type, and O which is the output type. In the error message you posted, it says it's failing to convert a java.util.LinkedHashMap into a com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification (which probably means that your lambda is being triggered by an S3 notification?) so I guessed ... it's also possible that you've got your input types wrong, and there's LinkedHashMap in your input that can't be cast. I'd probably remove all the type hints, and prn your inputs to find out what they are, remove the return value, and check the logs to see what you actually get.

Ed14:09:23

In java Generics only exist at compile time. By the time you're running code, all the generics have been erased. Since clojure doesn`t care about generics, you don't need to worry too much about them when implementing -handleRequest

p-himik14:09:45

S3Event inherits S3EventNotification along with its .getRecords method. You're telling Clojure that event is of type S3Event and then calling the .getRecords method that comes from S3EventNotification. The value of the event that you actually receive is, I think, either a Java map or a list. In your case it's a linked hash map.

p-himik14:09:11

So that ^S3Event part is wrong. As well as the (.getRecords event) part.

λ14:09:00

I am triggering the Lambda function using an S3 Put event, here is the exact event:

{
  "Records": [
    {
      "eventVersion": "2.0",
      "eventSource": "aws:s3",
      "awsRegion": "us-east-1",
      "eventTime": "1970-01-01T00:00:00.000Z",
      "eventName": "ObjectCreated:Put",
      "userIdentity": {
        "principalId": "EXAMPLE"
      },
      "requestParameters": {
        "sourceIPAddress": "127.0.0.1"
      },
      "responseElements": {
        "x-amz-request-id": "EXAMPLE123456789",
        "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
      },
      "s3": {
        "s3SchemaVersion": "1.0",
        "configurationId": "testConfigRule",
        "bucket": {
          "name": "example-bucket",
          "ownerIdentity": {
            "principalId": "EXAMPLE"
          },
          "arn": "arn:aws:s3:::example-bucket"
        },
        "object": {
          "key": "test%2Fkey",
          "size": 1024,
          "eTag": "0123456789abcdef0123456789abcdef",
          "sequencer": "0A1B2C3D4E5F678901"
        }
      }
    }
  ]
}

p-himik14:09:33

And you'll get a linked hash map that has that data.

λ14:09:41

So what is the value of having S3Event and the methods that it supports?

Ed14:09:48

sure ... that's a textual representation of some json. But by the time your function is called, it's been deserialised into a java data structure. Read the docs that @U2FRKM4TW posted above. And I'd suggest just printing your inputs to see what's in them.

Ed14:09:25

> So what is the value of having S3Event and the methods that it supports? for people writing java code to have code completion in their ide's? ;)

p-himik14:09:34

Yeah, seems like that. You can deserialize that JSON data into an instance of S3Event and then access everything via interop. But I'd just use that JSON data as represented by the map.

λ15:09:43

Can you recommend a library for working with JSON?

igrishaev15:09:56

For JSON, you can use cheshire. For AWS Lambda, you can use my library: https://github.com/igrishaev/lambda

p-himik15:09:25

See the "JSON Parsers" section here: https://www.clojure-toolbox.com/

igrishaev15:09:34

it provides Clojure handlers for both naive and HTTP requests.

p-himik15:09:56

You also don't need to parse that particular JSON because it's already parsed for you - that's why you get a linked hash map.

λ15:09:43

@U1WAUKQ3E I don’t understand how it works

igrishaev15:09:08

@U05MPHVTGPK you write a core module that uses the handler from the library, then compile it with GraalVM and get a single bootstrap binary file. Then you upload it to AWS Lambda and it works.

λ15:09:35

What do you mean by run AWS Lambdas compiled with native image

λ15:09:07

Is it an AWS Lambda runtime? Does it allow me to run AWS Lambda functions locally? Is it a competitor to AWS?

igrishaev15:09:44

A lambda might be of a various runtime. In your example, you use Java runtime. But you can make a binary file which is free from any kind of environment

λ15:09:57

Which is what your library does?

igrishaev15:09:39

yeah, it provides handlers that that do most of work for you.

λ15:09:11

I am not yet proficient enough with Clojure as it comes out of the box, so adding the complexity of this other thing is a daunting task.

λ15:09:11

I wouldn’t be able to justify on my own why using your library is better in my use case, and how it compares to doing things the way I am doing them now

igrishaev15:09:13

Well, since your code completely relies on AWS SDK, why not writing it in pure Java?

igrishaev15:09:55

It would have been easier rather than porting Java code to Clojure

λ15:09:19

I began learning Clojure to do a programming exercise for a company. That company is unable to hire me because of where I am. I have some free time now and want to do the exercise. Most examples I encountered were implementing the Java interface, so I stuck with that.

igrishaev15:09:29

Also, Java runtime takes up to 7 seconds for cold start, whereas a binary file takes 50 msec

igrishaev15:09:55

I'm not pushing my library exactly, just wanted to note that there are other good wrappers, e.g. FieryCod/holy-lambda or babashka + scripts

λ15:09:32

When I looked into holy-lambda, it didn’t seem applicable to my use case: I need to read data from a file in an S3 bucket Parse data and write it to a file in the S3 bucket

λ15:09:18

Holy Lambda mentions an event loop. I don’t need a loop, I need the lambda function to exit when done doing the above.

igrishaev15:09:05

Lambdas always do loop, always

igrishaev15:09:46

They work like a message queue, and you provide a handler

igrishaev15:09:26

In your code, the loop is handled by the java sdk

λ15:09:22

Here’s what I get when I print event

#object[java.util.LinkedHashMap 0x489115ef {Records=[{eventVersion=2.0, eventSource=aws:s3, awsRegion=us-east-1, eventTime=1970-01-01T00:00:00.000Z, eventName=ObjectCreated:Put, userIdentity={principalId=EXAMPLE}, requestParameters={sourceIPAddress=127.0.0.1}, responseElements={x-amz-request-id=EXAMPLE123456789, x-amz-id-2=EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH}, s3={s3SchemaVersion=1.0, configurationId=testConfigRule, bucket={name=example-bucket, ownerIdentity={principalId=EXAMPLE}, arn=arn:aws:s3:::example-bucket}, object={key=test%2Fkey, size=1024, eTag=0123456789abcdef0123456789abcdef, sequencer=0A1B2C3D4E5F678901}}}]}]
How do I work with this #object[] data structure? This is my first time seeing something in Clojure resembling this.

Ed16:09:44

That's a Java LinkedHashMap you can convert it to a Clojure map with something like (into {} m)

Ed16:09:42

Clojure maps are printed in EDN, but Java objects generally are not, which is why it prints with the #object style notation, but they are still maps, so you can still do (get "Records" m) to look up keys from the map.

λ16:09:59

hm that returned nil

Ed16:09:36

Sorry ... typing on my phone ... that should have been (get m "Records")

λ16:09:00

@U2FRKM4TW, I am confused, how is it parsed, if there are = signs in the map?

p-himik16:09:37

That's how the map is printed. It's not a string overall, so it's parsed. Don't rely on printed representation. I don't know what AWS Lambda offers in terms of the ability to connect to a running instance, but it's much, much easier and developer-friendly to develop with a REPL at hand. A somewhat relevant comment - since you're a total beginner with Clojure and not a Java developer as well, starting with AWS Lambda is not a good move IMO. It's like a novice car mechanic starting working on a total revamp of a W8 engine. If your goal is to learn Clojure, you would be much better off writing some backend.

p-himik16:09:52

To demonstrate the = printing:

$ jshell
|  Welcome to JShell -- Version 19.0.2
|  For an introduction type: /help intro

jshell> new HashMap<String, Integer>() {{ put("a", 1); put("b", 2); put("c", 3); }}
$1 ==> {a=1, b=2, c=3}

jshell>
Note the line starting with $1.

λ17:09:14

Here’s the output of (get event "Records") https://clojurians.slack.com/files/U05MPHVTGPK/F05QT912763/untitled However, I get nil when trying (get-in event "Records" "awsRegion")

p-himik17:09:08

Check out the docs for get-in.

λ17:09:24

(type (get event "Records") returns java.util.ArrayList

p-himik17:09:30

Ah, then you can't use get-in since array lists are not associative. But you can combine get with nth.

λ17:09:47

as in (nth 0 (get event "Records"))

p-himik17:09:00

No. Please read the docs of the CLJ functions that you're using. In this case, the docs of nth. The https://clojuredocs.org/ website even offers examples.

p-himik17:09:52

The -> threading macro would also be helpful here. Since it seems that your initial question is resolved, I would suggest asking follow-up questions as separate messages, outside this thread. And preferably in the #C053AK3F9 channel since people there have explicitly elected to help out beginners with any sorts of questions or problems they might have.

Ingy döt Net15:09:18

Is a clj-ffi library or did co-pilot make that up? Looking for the best modern way to FFI call a C shared lib from Clojure code.

p-himik15:09:14

Not sure about clj-ffi but FWIW there's https://github.com/IGJoshua/coffi.

4
Ingy döt Net15:09:18

I saw Coffi but need it to work on a LTS JDK

Ingy döt Net15:09:08

ie 17 (I think. Pretty new to this)

Ingy döt Net15:09:56

A bird said a new LTS comes out any day now though

Ingy döt Net15:09:28

Any other modern FFI libs to look at?

Ingy döt Net15:09:15

I'll ask about JDK specifics in #C02EEAUHSJJ in the mean time

p-himik15:09:56

The README in that repo mentions alternatives: https://github.com/IGJoshua/coffi#alternatives

🙌 2
p-himik15:09:34

And I think you can use earlier versions of coffi that do support JDK17. Probably from this branch: https://github.com/IGJoshua/coffi/tree/jdk17-lts

👀 2
Joshua Suskalo15:09:09

new lts comes out this month and coffi will be updated to it.

Ingy döt Net15:09:33

Nice! Does Coffi's latest release support 17? (what I'm using now)

Joshua Suskalo15:09:58

The latest release is for jdk 19, the latest release for jdk 17 is 0.4.341 on maven

Joshua Suskalo15:09:07

The internal api changes between jdk versions because it's in preview, so i don't support multiple jdks per coffi release

Ingy döt Net15:09:23

okie doke. thanks!

Ingy döt Net15:09:00

my needs are simple so shouldn't be much change to switch to the new upcoming LTS

Ingy döt Net15:09:16

fwiw, this is rather funny: > ingydotnet: use coffi to have clojure call libfyaml with a yaml stream and return the parser events. > > GitHub Copilot: I apologize, but it seems that there is no coffi library in Clojure. Did you mean clj-ffi instead?

Joshua Suskalo15:09:10

This is a pretty good expression of why I don't find copilot particularly useful, especially in Clojure projects. These generative text AI often have a lot in common in the output they produce to StyleGAN and other style transfer AI. They will take some way they've seen frequently to solve a problem described (and that frequently then biases towards more mainstream languages like JS and C++ and Java), and then they will apply Clojure as a "set dressing" for that.

Ingy döt Net15:09:12

to be fair... ingydotnet: The Clojure coffi library is here https://clojars.org/search?q=coffi and here https://github.com/IGJoshua/coffi GitHub Copilot: Thank you for the information. I apologize for the confusion earlier. I am not familiar with the coffi library, but it appears to be a Clojure library for calling C functions using a more concise syntax than clj-ffi. Here's an example of how you can use coffi to call libfyaml and parse a YAML stream:

(ns my-app.core
  (:require [coffi.core :refer [defcfun]]
            [coffi.types :refer [string int bool pointer]]))

(defcfun "fyaml_parser_initialize" [] pointer)
(defcfun "fyaml_parser_set_input_string" [pointer string int] bool)
(defcfun "fyaml_parser_parse" [pointer] int)
(defcfun "fyaml_parser_cleanup" [pointer] bool)
(defcfun "fyaml_parser_get_event_type" [pointer] int)
(defcfun "fyaml_parser_get_anchor" [pointer] string)
(defcfun "fyaml_parser_get_tag" [pointer] string)
(defcfun "fyaml_parser_get_scalar_value" [pointer] string)
(defcfun "fyaml_parser_get_scalar_length" [pointer] int)
(defcfun "fyaml_parser_get_plain_scalar" [pointer] bool)
(defcfun "fyaml_parser_get_sequence_start_implicit" [pointer] bool)
(defcfun "fyaml_parser_get_mapping_start_implicit" [pointer] bool)

(defn parse-yaml [yaml-string]
  (let [parser (fyaml_parser_initialize)
        result (fyaml_parser_set_input_string parser yaml-string (count yaml-string))
        events (loop [events []]
                 (let [event-type (fyaml_parser_get_event_type parser)]
                   (cond
                     (= event-type 0) events
                     (= event-type 1) (conj events (parse-scalar-event parser))
                     (= event-type 2) (conj events (parse-sequence-start-event parser))
                     (= event-type 3) (conj events (parse-sequence-end-event parser))
                     (= event-type 4) (conj events (parse-mapping-start-event parser))
                     (= event-type 5) (conj events (parse-mapping-end-event parser))
                     :else (throw (Exception. (str "Unknown event type: " event-type))))))]
    (fyaml_parser_cleanup parser)
    events))

(defn parse-scalar-event [parser]
  {:type :scalar
   :anchor (fyaml_parser_get_anchor parser)
   :tag (fyaml_parser_get_tag parser)
   :value (fyaml_parser_get_scalar_value parser)
   :length (fyaml_parser_get_scalar_length parser)
   :plain-scalar (fyaml_parser_get_plain_scalar parser)})

(defn parse-sequence-start-event [parser]
  {:type :sequence-start
   :anchor (fyaml_parser_get_anchor parser)
   :tag (fyaml_parser_get_tag parser)
   :implicit (fyaml_parser_get_sequence_start_implicit parser)})

(defn parse-sequence-end-event [parser]
  {:type :sequence-end
   :anchor (fyaml_parser_get_anchor parser)})

(defn parse-mapping-start-event [parser]
  {:type :mapping-start
   :anchor (fyaml_parser_get_anchor parser)
   :tag (fyaml_parser_get_tag parser)
   :implicit (fyaml_parser_get_mapping_start_implicit parser)})

(defn parse-mapping-end-event [parser]
  {:type :mapping-end
   :anchor (fyaml_parser_get_anchor parser)})
This code defines a Clojure namespace my-app.core that uses the coffi library to call the libfyaml library and parse a YAML stream. The defcfun macro is used to define functions that correspond to the C functions in the libfyaml library. The parse-yaml function takes a YAML string as input and returns a sequence of parser events. The parse-scalar-event, parse-sequence-start-event, parse-sequence-end-event, parse-mapping-start-event, and parse-mapping-end-event functions parse specific types of events from the parser and return them as maps. You can call the parse-yaml function to parse a YAML stream like this:
(parse-yaml "foo: bar\nbaz: qux\n")
This will return a sequence of parser events that correspond to the YAML stream. Each event is represented as a map with a :type key that indicates the type of the event (e.g. :scalar, :sequence-start, :sequence-end, :mapping-start, or :mapping-end) and additional keys that provide information about the event (e.g. :anchor, :tag, :value, :length, or :implicit).

Ingy döt Net15:09:52

I'm sure I'll have to debug it. I never use its code. Just ask it sometimes when I'm blocked to get new ideas, or when trying something totally foreign (npi).

Joshua Suskalo15:09:59

That's fair. There's a couple parts of that which are almost right. It kinda seems like it might be pulling on some CL ffi stuff there, but I'm not certain. The readme for coffi should hopefully be enough to help out a lot with knowing what to do, and if you want to see a sample library wrapped, I have https://github.com/IGJoshua/glfw-clj

Joshua Suskalo15:09:25

This uses a slightly older version of coffi, you can check the changes for that here: https://github.com/IGJoshua/coffi/blob/jdk17-lts/CHANGELOG.md

Joshua Suskalo15:09:29

glfw-clj uses 0.2.259, so the changes since then are relevant.

Ingy döt Net16:09:07

There's no lein usage in the docs I noticed.

Ingy döt Net16:09:14

But I'll figure it out.

Joshua Suskalo16:09:56

[org.suskalo/coffi "0.4.341"]

Ingy döt Net16:09:03

thanks. I know it's dumb. I'll get there...

👍 2
chrisn16:09:30

Dtype-next also has ffi bindings that work today on several lts releases

👍 2
chrisn16:09:46

It’s used for libpython-clj

chrisn16:09:32

Examples would be avclj, libpython-clj and tmducken

chrisn16:09:53

With avclj being the most approachable

chrisn16:09:10

Jdk-8 and forward

chrisn16:09:51

And graal native bindings if that is your jam

Ingy döt Net16:09:24

ok thanks. I'll look. I looked at the dtype-next docs but they felt complicated for what I needed... 1 call. I'll look at avclj.

Ingy döt Net16:09:03

I'm writing clojure thst compiles to a graalvm shared lib actually.

Ingy döt Net16:09:12

for binding to other langs

Ingy döt Net16:09:19

that part is all done

Ingy döt Net16:09:39

I just want to replace the java yaml parser with a better C one

Joshua Suskalo16:09:51

That's important actually, you can't use coffi and compile to a graal native image. coffi uses runtime bytecode generation in order to handle high performance boxing and unboxing for higher order functions.

Joshua Suskalo16:09:17

That doesn't work on graal, so dtype-next is your best bet, unless you want to use the graal native stuff directly.

Ingy döt Net16:09:20

well that saves me time likely

Ingy döt Net16:09:54

my test binding (python ctypes) makes a single high level call to the graal-compiled shared lib

Ingy döt Net16:09:14

thanks for the tip @U5NCUG8NR!!!

Joshua Suskalo16:09:43

Yeah, no problem! Normally I'd also question why a project is using graal, but compiling to a shared object to allow using from python is a pretty good usecase 😅

Ingy döt Net16:09:09

well and many many other langs

Joshua Suskalo16:09:13

Just as a heads up, you may also want to keep an eye on https://jank-lang.org/ , which is a WIP clojure dialect that compiles to native code and offers direct FFI

Ingy döt Net17:09:12

The high level abstract is: > a libyamlscript binding for YFL (your favorite language) that lets you write YAML files with functional transformations (in a nice highly stylized YAML DSL syntax). YAMLScript is an alternate syntax reader for Clojure. SCI is bundled into libyamlscript to evaluate the translated Clojure code. The result is returned as JSON and parsed/loaded/evaled by FYL giving you the expected data value. > > Literally: >

(->> ys-file
>   slurp
>   ys/ys-to-clj
>   sci/eval-string
>   json/write-str)
From Python:
import yamlscript
data = yamlscript.load_file("config.yaml")

Ingy döt Net17:09:30

I'm aware of Jank but unaware of what it could do for me here...

Ingy döt Net17:09:37

SCI seems to fit very well, and I already have all the compilation working.

Ingy döt Net17:09:33

In fact everything works. Replacing the java snakeyaml with the C libfyaml is pretty much an optimization at this point.

Ingy döt Net17:09:18

But I also work closely with the libfyaml author and it will play a much bigger role later on

Joshua Suskalo17:09:21

I don't think it gets you much right now, but in the future it would allow you to have a lighter shared object that doesn't bundle even a minimal JVM

Ingy döt Net17:09:57

ah. ok. well the linux shared lib is 52MB, so that's fair

Ingy döt Net17:09:28

I could certainly have the option to swap sci for jank. once the whole project is further down the road and has tons of tests to validate the jank would work out.

Ingy döt Net17:09:56

thanks for helping me see that... 🙂

Ingy döt Net17:09:09

(have I thanked you enough yet?)

Joshua Suskalo17:09:40

Lol, definitely have. It's really cool to see someone doing clojure stuff in a shared object!

Joshua Suskalo17:09:27

The goal for Jank in this case is to be able to do "everything that both clj and cljs can do", and they are working towards pretty robust tests.

Joshua Suskalo17:09:47

Having a test suite and making sure it all works the same would be great, and if it doesn't then it's a good way to generate bug reports for jank, which I'm sure the author would appreciate

2
Ingy döt Net17:09:17

Ironically I'm here because I am working on a Clojure Platform for Perl (first, then others) called Lingy and gave a talk about https://www.youtube.com/watch?v=9OcFh-HaCyI in July. See me joining the Clojurians slack: https://clojurians.slack.com/archives/C0218CKTVEK/p1689687145013449 My Clojure journey to date gets more amazing by the day. From the things I've learned from folks like yourself, I will be able to make YAML programmable in at least 10 languages by the end of this year. That's insane from my experience in programming. My needs so far with Clojure are a bit reversed from typical: I'm taking Clojure and its concepts and tooling and using them to spread various goodness to all the other langs. That's pretty much been my MO for the past 20 years. Clojure and friends are the giants' shoulders. I'm a little angry I only learned about Clojure in the last year, but also very happy about where it is technically today (AWESOME). Note: YS also considers any existing YAML file to be valid YS, so you can load any YAML (and thus JSON) file with it (using FP calls or not) and it will work the same in everything language (something YAML struggles with today).

Joshua Suskalo17:09:53

Yeah, with the yaml spec being the way that it is and having as many versions as it does, it's very challenging to get a consistent experience with it across different languages.

Ingy döt Net17:09:59

Right. (fyi I am an author of that spec...) My opinion is that the spec (even though it is huge) it does not contain all the information needed to allow people to produce fully compatible implementations across languages. One solution (my current one) is to make a top notch, api compatible reference implementation in every modern language. And now I think I can reasonably do that with help from clojure and friends.

Joshua Suskalo17:09:44

that's really cool!

chrisn19:09:41

First, why is the C parser better than the java parser? And second, if you are transforming the entire datastructure to clojure function by function then I think that will be somewhat slow. It would be more ideal to get pointers to data structures and do the traversal that way as opposed to using granular function calls. Third ham-fisted has optimized datastructures that are somewhat faster to create than the base clojure datastructures -- this was the part of my https://www.youtube.com/watch?v=ralZ4j_ruVg and lastly we could also add yaml parsing to charred. There is an https://github.com/cnuernber/charred/issues/15 about that which would mean you wouldn't need to link to the C library and pay the cost of transforming the datastructures - if you do indeed plan on doing that.

Ingy döt Net19:09:06

1. Nothing to do with C or Java. The C libfyaml is a better library by far on many levels. 2. I'm not. The transform is from a string containing a YS/YAML document to a a string of clojure forms. 3. ok 4. The call to the C lib (`libfyaml`) and the Java lib is to "parse" a single yaml document into a sequence of YAML parse events. That's all. I don't see any advantage to avoiding it, and later I'll need libfyaml for other advanced reasons.

Ingy döt Net20:09:23

The term "parse" in YAML context is only one layer (text to event structs) of a more complex stack called "load" (text to native)

Ingy döt Net20:09:02

parsing YAML is the very hard part that no parser in the world (afaik) can do yet. libfyaml and the reference parser I wrote and eemeli's java parser pass 100% of the test suite, but I know of many cases where they fail taht have not yet made it into the test suite. All these implementations were written by YAML core team members (5 of us)

Ingy döt Net20:09:25

We should continue this in #C05HQFMTURF if there is more to go over. 🙂

chrisn20:09:08

Nope - this is all interesting especially the high level design and makes sense. Good luck and if you want help with dtype-next's ffi system I am happy to help.

Ingy döt Net20:09:50

@UDRJMEFSN many thanks, and I'll almost certainly need some help along the way!