scala clojure interop issue upgrading from 3.0.1 to 3.4.3

64 views
Skip to first unread message

ari gold

unread,
Sep 10, 2021, 9:17:51 PM9/10/21
to Lift
Hello hello,

I fully admit and recognize that this is a shot in the dark. Maybe I'm hoping a little rubberducking (i.e. learning while talking about something) could help us. Worst case, I trust I didn't waste too much of y'alls time :)

We're currently upgrading Lift from 3.0.1 to 3.4.3 and are running into quite a doozy. It's in our Clojure code so there's the whole Java<->Clojure<->Scala routine.

I tested this with our Scala version bumped to 2.12.12 so that it matched the version in release 3.4.3 and we don't hit the error. We only hit the error when we bump Lift to 3.4.3.

Here's the code which, again, is Clojure code accessing Scala through Java bytecode (I think):

(let [full-thing (new net.liftweb.common.Full "foo")] (.openOrThrowException full-thing "opened"))

The error we get is

ClassCastException java.lang.String cannot be cast to scala.Function0  user/eval10221 (NO_SOURCE_FILE:1)

If we do a similar bit to test Empty, we get a different error which seems to point a change in the way things are represented in bytecode or a difference in how Clojure accesses objects in the bytecode -- Empty is a case object:

user=> (let [empty-thing net.liftweb.common.Empty$/MODULE$] (.openOrThrowException empty-thing "CANT OPEN"))

IllegalArgumentException No matching method found: openOrThrowException for class net.liftweb.common.Empty$  clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:80)

I tried all sorts of iterations on Empty and Empty$ and MODULE$ but nothing did the trick. Along the lines of MODULE$, I noticed that this SO answer talks about using MODULE$ as per the Clojure docs on Java Interop but that SO answer is old and the page no longer references MODULE$. That's what got me thinking about a potential change in how the object is accessed in the bytecode.

Does anything there ring a bell?

I poked around Box.scala and noticed this commit which seems like it might be related because that whole java.lang.String cannot be cast to scala.Function0 bit smells like something implicit-y but that theory could mosdef be wrong.

Anyhoo, I know that the Scala<->Clojure interop ain't really a Lift things but I figured I'd post juuuuust in case. It's been a while :D

Thanks so much,

Ari

Andreas Sacher

unread,
Sep 12, 2021, 8:23:07 AM9/12/21
to lif...@googlegroups.com
Hello,

i think you missed a part about the `openOrThrowException` definition:

```
def openOrThrowException(justification: => String): A
```

`justification` is not a String but a Function0[String]. This would
explain your first error.

For the Empty problem: The "Member access" paragraph on the page linked
in the SO answer you linked to uses `Classname/staticField` to access
static fields of a class. Since the page is about java interop (not
scala) i doubt there will be any reference to MODULE$ there. I
understand your error message more like "look i found your object but
not the method you want to call". Since the only method called
`openOrThrowException` on the Empty object doesn't take a String, but a
Function0[String] as first argument you seem to have the same problem here.

For the record: i never used clojure and can't really test my
assumtions. It just seemed to me that you missed the "=>" anyd i hope
this can bring you back on the right track again.

Regards Andreas

Am 11.09.21 um 03:17 schrieb ari gold:
> Hello hello,
>
> I fully admit and recognize that this is a shot in the dark. Maybe I'm
> hoping a little rubberducking (i.e. learning while talking about
> something) could help us. Worst case, I trust I didn't waste too much of
> y'alls time :)
>
> We're currently upgrading Lift from 3.0.1 to 3.4.3 and are running into
> quite a doozy. It's in our Clojure code so there's the whole
> Java<->Clojure<->Scala routine.
>
> I tested this with our Scala version bumped to 2.12.12 so that it
> matched the version in release 3.4.3 and we don't hit the error. We only
> hit the error when we bump /Lift/ to 3.4.3.
>
> Here's the code which, again, is Clojure code accessing Scala through
> Java bytecode (I think):
>
> (let [full-thing (new net.liftweb.common.Full "foo")]
> (.openOrThrowException full-thing "opened"))
>
> The error we get is
>
> ClassCastException java.lang.String cannot be cast to scala.Function0 
> user/eval10221 (NO_SOURCE_FILE:1)
>
> If we do a similar bit to test Empty, we get a different error which
> seems to point a change in the way things are represented in bytecode
> /or/ a difference in how Clojure accesses objects in the bytecode --
> Empty is a case object
> <https://github.com/lift/framework/blob/master/core/common/src/main/scala/net/liftweb/common/Box.scala#L899>:
>
> user=> (let [empty-thing net.liftweb.common.Empty$/MODULE$]
> (.openOrThrowException empty-thing "CANT OPEN"))
>
> IllegalArgumentException No matching method found: openOrThrowException
> for class net.liftweb.common.Empty$ 
> clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:80)
>
> I tried all sorts of iterations on Empty and Empty$ and MODULE$ but
> nothing did the trick. Along the lines of MODULE$, I noticed that this
> SO answer <https://stackoverflow.com/a/21328196/1116825> talks about
> using MODULE$ as per the Clojure docs on Java Interop but that SO answer
> is old and the page no longer references MODULE$. That's what got me
> thinking about a potential change in how the object is accessed in the
> bytecode.
>
> Does anything there ring a bell?
>
> I poked around Box.scala
> <https://github.com/lift/framework/blame/master/core/common/src/main/scala/net/liftweb/common/Box.scala>
> and noticed this commit
> <https://github.com/lift/framework/commit/255713907ed814cb4eecfb2f2807c715e8dad964> which
> seems like it might be related because that whole java.lang.String
> cannot be cast to scala.Function0 bit smells like something implicit-y
> but that theory could mosdef be wrong.
>
> Anyhoo, I know that the Scala<->Clojure interop ain't really a Lift
> things but I figured I'd post juuuuust in case. It's been a while :D
>
> Thanks so much,
>
> Ari
>
> --
> You received this message because you are subscribed to the Google
> Groups "Lift" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to liftweb+u...@googlegroups.com
> <mailto:liftweb+u...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/liftweb/3f772489-56c3-410f-85ae-a0070d01ae21n%40googlegroups.com
> <https://groups.google.com/d/msgid/liftweb/3f772489-56c3-410f-85ae-a0070d01ae21n%40googlegroups.com?utm_medium=email&utm_source=footer>.

ari gold

unread,
Mar 3, 2022, 7:20:57 PM3/3/22
to Lift
I know this is way late Andreas but I wanted to wait until everything was merged and deployed and then a few more months to check for regressions :)

In short, you were spot on. Lil bit of cognitive overload - I missed the "=>" just like you said. That took care of everything.

Thanks again!

Ari

Reply all
Reply to author
Forward
0 new messages