Skip to content

as-jvm failed for a returned list #269

Open

Description

@kenhuang-io

Hi,

I experienced an issue while I was using libpython-clj to encode the returned list as json via cheshire, it threw an exception with this snippet:

  (println "Just something interesting from Python:"
           (-> (py/py. simple a_list)
               py/as-list
               json/generate-string))

The exception:

Execution error (ClassCastException) at cheshire.generate/generate$fn (generate.clj:135).
class java.lang.String cannot be cast to class java.util.Map$Entry (java.lang.String and java.util.Map$Entry are in module java.base of loader 'bootstrap')

And it worked fine for a map.

I've created a demo repo for this: https://github.com/whatacold/libpython-clj-as-jvm-issue, hopefully I've put all necessary info there.

Was there something I was missing? Thanks.

Activity

  1. changed the title [-]as-jvm for a returned list failed[/-] [+]as-jvm failed for a returned list[/+] on Feb 18, 2025
  2. cnuernber commented on Feb 18, 2025

    @cnuernber
    Collaborator

    I think what you are missing is that as-jvm creates bridge objects that implement a subset of the interfaces in java.util -- ->jvm creates copies of the data. Passing a bridge object into cheshire isn't a use case we support as the resulting pathway is going to call into the python interpreter in a fine grained fashion and is thus very likely to perform quite badly.

    Python has json libraries - using their libraries and then only marshalling the string itself across language boundaries is likely to be faster and more correct than as-jvm -> cheshire.

    That all being said - this is interesting to me in that it is something that should work -- albeit there are better ways -- and this may represent an area where we could have better support for the jvm interfaces. ham-fisted library interface defaults could be used here.

  3. kenhuang-io commented on Feb 18, 2025

    @kenhuang-io
    Author

    I think what you are missing is that as-jvm creates bridge objects that implement a subset of the interfaces in java.util -- ->jvm creates copies of the data. Passing a bridge object into cheshire isn't a use case we support as the resulting pathway is going to call into the python interpreter in a fine grained fashion and is thus very likely to perform quite badly.

    Thanks for the explanations, I had a feeling that maybe it was wrong to feed it into cheshire directly.

    Python has json libraries - using their libraries and then only marshalling the string itself across language boundaries is likely to be faster and more correct than as-jvm -> cheshire.

    Yes, that was what I did, by using json.dumps to encode it to a string for clojure. It's even faster by doing this way? I didn't expect that.

    That all being said - this is interesting to me in that it is something that should work -- albeit there are better ways -- and this may represent an area where we could have better support for the jvm interfaces. ham-fisted library interface defaults could be used here.

    I'm wondering, is it rare to return a list/map/set, etc. from python? What do you usually use libpython-clj for? For me, I was rewriting a webapp that was in python, so I had some logic using python regex to do the trick, hence I needed to feed a python function a map and then get back a list.

  4. cnuernber commented on Feb 18, 2025

    @cnuernber
    Collaborator

    The libpython-clj default is to use ->jvm via copy which I think is usually faster than converting to json. Bridging is used for object that have behavior on them and ->jvm is used for datastructures.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions