Fork me on GitHub
#clojure
<
2021-09-18
>
Martynas Maciulevičius10:09:18

Hey. Code reloading+Java interface question. I use ring and it reloads code when I update my sources and refetch the page. I have a defprotocol (I'll call it Interface) which I instantiate using reify or defrecord (the Exception is different in both cases but it says that my object doesn't implement my interface). I also use a type hint to specify the Interface just before I call the method. The exception happens when I call a method on a class after a reload. This is the text of the exception when using reify:

java.lang.ClassCastException: class `ReifiedClass` cannot be cast to class `Interface` (`ReifiedClass` is in unnamed module of loader clojure.lang.DynamicClassLoader @33f19df2; `Interface` is in unnamed module of loader clojure.lang.DynamicClassLoader @3e848201)
	at <my stack trace>
	at compojure.core$wrap_response$fn__3866.invoke(core.clj:158)
	at compojure.core$pre_init$fn__3965.invoke(core.clj:328)
	at compojure.api.coerce$body_coercer_middleware$fn__17205.invoke(coerce.clj:51)
	at compojure.core$pre_init$fn__3967$fn__3970.invoke(core.clj:335)
	at compojure.core$wrap_route_middleware$fn__3850.invoke(core.clj:127)
	at compojure.core$wrap_route_info$fn__3855.invoke(core.clj:137)
	at compojure.core$wrap_route_matches$fn__3859.invoke(core.clj:146)
	at compojure.core$wrap_routes$fn__3977.invoke(core.clj:348)
	at compojure.api.routes.Route.invoke(routes.clj:74)
Any ideas? 😕 I think it worked previously as I had more sources that are written like that in the past. But for some reason current one fails. My java version is openjdk version "16.0.2" 2021-07-20

p-himik10:09:02

It might be that you redefine the protocol after reifying it. A demonstration of a similar thing, although the error is different:

user=> (defprotocol P (f [_]))
P
user=> (def p (reify P (f [_] (println "f"))))
#'user/p
user=> (f p)
f
nil
user=> (defprotocol P (f [_]))
P
user=> (f p)
Execution error (IllegalArgumentException) at user/eval207$fn$G (REPL:1).
No implementation of method: :f of protocol: #'user/P found for class: user$reify__194
user=> 

Martynas Maciulevičius11:09:50

I think it could be the case. I moved the defprotocol into a different namespace and it didn't produce the error after tinkering.

👍 2
Martynas Maciulevičius11:09:44

Probably the reloading mechanism could be smarter. Or it was a recent addition. I also changed my java version to 8 and it resulted in the same exception.

noisesmith18:09:59

ring's wrap-reload is not smart enough to do protocol redefinition correctly

noisesmith18:09:17

your choices are to not use protocols, or use a smarter reloading mechanism

noisesmith18:09:15

(or do a full restart of your jvm every time you edit a file that defines a protocol)

pinkfrog10:09:19

Is there any benefits to separate the test file with the implementation, as in:https://github.com/xtdb/xtdb/blob/224a3dc04b0b9d9d5336c54f0ea9ee0d0aeb003b/crux-test/test/crux/bitemporal_tale_test.clj#L6 ? Or just purely out of personal taste?

p-himik10:09:29

If you don't do that, then your production setup will have to have all dependencies and potentially the same setup that you would need only during testing.

pinkfrog11:09:53

Can’t we compile the uberjar but excluding those with xxx_test.clj files?

p-himik11:09:21

That's exactly what I mean - if the test code is separated from the rest of the code, then it's much easier to exclude that code. And if all test code is in a separate directory, then it becomes trivial - you just don't include that directory in the classpath, along with all test dependencies, when building an uberjar.

Max16:09:38

I asked a similar question in this channel recently: https://clojurians.slack.com/archives/C03S1KBA2/p1631643375454100 The consensus seemed to be “it’s possible but impractical”

pinkfrog14:09:02

Sadly the message there has been hidden by slack. “it’s possible but impractical”. How come it is impractical? And for the wild pattern matching facility mentioned, I remember lein seems have that support, how about deps?

Max16:09:04

You’d have to note each file you wanted to include in the classpath one-by-one. There’s not any support for wildcards currently

p-himik13:09:46

Just started experimenting with a socket REPL running on a remote host. For some reason, the server drops the connection after a short period of inactivity (30-60 seconds):

% telnet localhost 50505                
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
user=> (println "x")
x
nil
user=> 1
1
user=> Connection closed by foreign host.
What could be the reason for that? The port keeps being forwarded - I can reconnect just fine.

kulminaator13:09:31

maybe the network channel itself has an agressive timeout policy ?

kulminaator13:09:38

i stumbled on a similar issue when i was playing around with amazon's loadbalancer in front of my database instance. sql client just lost connections for initially no apparent reason at all (which was annyoing for long running stats queries, obviously)

kulminaator13:09:57

you could probably verify that by running the repl over network "locally" on the remote host ... if it locally doesn't close in the given timeframes the issue isn't in the repl

p-himik13:09:19

I just checked it with nc running on the remote - yeah, seems to be the case, so it's not Clojure-related. Thanks!

Aneil Mallavarapu14:09:41

Here's a curiosity that is just for amusement and maybe understanding Clojure internals better. I found this weird behavior of map - it ignores side-effects of lexically bound atoms (not globally bound ones, though, mind you) when mapping a closure. It's only in that case. I know I'm abusing of map by trying to do side-effects, and that loop or whatever is the right way. I just discovered this while exploring the behavior of closures, and thought some would find this interesting. Maybe map deliberately copies closure bindings before doing its work?

p-himik14:09:48

Try the second block, but in a do:

(do
  (def a (atom []))
  (map #(swap! a conj %) [1 2 3]) 
  @a)
=> []
The root cause has nothing to do with scopes. map produces a lazy collection - if nothing attempts to iterate over it, the mapping function is never called. I assume you're doing it all in a REPL - it will evaluate the lazy collection for you when it's a return value. Since do above hides that value, it's never evaluated.

🙏 2
Ben Sless15:09:52

Side effects in laziness are a constant source of pain and trip-ups

Aneil Mallavarapu18:09:20

AHHH. Laziness. Thank you.

jjttjj15:09:32

I've found that gzipping files in clojure via GZIPOutputStream (for example, like this https://github.com/clojure-cookbook/clojure-cookbook/blob/master/04_local-io/4-21_read-write-gzip.asciidoc) is worse than just using the gzip linux command for large files. It seems to take more memory and is slower. Is there any way to do this more efficiently purely on the jvm or is just shelling out the way to go?

jjttjj15:09:48

Oh yeah definitely, thanks!

neupsh17:09:04

Hello, how do i use clojure.lang classes in my java 11 classes in a clojure/java leiningen polyglot project? I get:

Compiling 16 source files to <myproj>/target/classes
warning: [options] system modules path not set in conjunction with -source 11
<myclass>.java:3: error: package clojure.java.api is not visible
import clojure.java.api.Clojure;
^
(package clojure.java.api is declared in the unnamed module, but module <mymodule> does not read it)
<myclass>:4: error: package clojure.lang is not visible
import clojure.lang.IFn;
I tried to add requires clojure; in the module-info.java file but it does not work either
warning: [options] system modules path not set in conjunction with -source 11
<myprojmodule>/module-info.java:6: error: module not found: clojure
requires clojure;
is there a template that I can use to get started on java/clojure polyglot that works with recent versions of java? Its been a while I had not used clojure 🙂

bbloom22:09:26

at some Clojure Conj or something long ago, somebody had a flow diagram of advanced HTTP routing, including handling content-types, accepts, languages, methods, various status codes, etc. Also, iirc, there was a library/framework associated. Does anyone know what I'm thinking of?