Fork me on GitHub
#clojure
<
2021-08-24
>
Crispin04:08:57

what happens to unclaimed future results? If I spawn a future and abandon it (say the future stores its result somewhere), and the future creator never derefs the future, what happens to the result? Does it just consume memory in the JVM forever more? Is it gabage collected somehow when the creator returns without the future?

phronmophobic04:08:01

It will be available for garbage collection:

> (future
    (reify
      Object
      (finalize [_]
        (println "goodbye"))))
#<[email protected]: 
  #object[$eva...66"]>
> (System/gc)
goodbye

Crispin04:08:08

Thankyou. Great little bit of example code.

Crispin05:08:15

does this actually garbage collect though?

Crispin05:08:30

user=> (def fut
  #_=> (future
  #_=>     (reify
  #_=>       Object
  #_=>       (finalize [_]
  #_=>         (println "goodbye")))))
#'user/fut
user=> fut
#object[clojure.core$future_call$reify__8439 0x68d96261 {:status :ready, :val #object[user$fn$reify__2006 0x35c59975 "[email protected]"]}]
user=> (System/gc)
goodbye
nil
user=> fut
#object[clojure.core$future_call$reify__8439 0x68d96261 {:status :ready, :val #object[user$fn$reify__2006 0x35c59975 "[email protected]"]}]
user=> @fut
#object[user$fn$reify__2006 0x35c59975 "[email protected]"]

Crispin05:08:58

or will it gc when fut is gced?

Crispin05:08:05

will fut be gced when finished?

phronmophobic05:08:27

It will be available for garbage collection when there aren't any references pointing towards it

Crispin05:08:31

yep great thanks

bnstvn05:08:01

but printing “goodbye” means something have been gc’d right when fut was live? i see an other “goodbye” after

(def fut nil)
(System/gc)

bnstvn05:08:01

(def fut
  (future
    (reify
      Object
      (finalize [this]
        (println (.hashCode this))))))
=> #'finaliz/fut
(System/gc)
1723828443
=> nil
(.hashCode @fut)
=> 822250702
(def fut nil)
=> #'finaliz/fut
(System/gc)
822250702
=> nil

Crispin06:08:01

interesting

Nom Nom Mousse06:08:20

To keep two maps in sync I guess the easiest thing to do is to create an atom with two fields that contain the maps like :state->jobids and :jobid->state, right? And then ensure that all operations keep them in sync

Nom Nom Mousse06:08:32

Let's say I have an atom like above with

{:jobid->state {:jobid1 :ready :jobid2 :in-progress ...}
 :state->jobids {:ready #sorted-set{:jobid3 ...}}
                 :in-progress #sorted-set{:jobid4...}
                 :done #sorted-set{:jobid5 ...}}
Is there any advantage in making it a defrecord? Or is that only advantageous if I want polymorphism? I do Scala at work so there I'd make it an object. But I guess there is no advantage to it here. I could just have it in a namespace with the getter/setter/lookup-functions.

eskos07:08:18

I don’t really see any benefit in turning this into a record. You already have it properly structured with nice names and all that and Clojure’s APIs work best with this kind of data 🙂 If you need Java interop then maybe, but as is, nah.

Nom Nom Mousse08:08:27

That is what I thought. Thanks! 🙏

Marco Schneider08:08:39

Hey everyone. I’ve got a seemingly very basic question: I want to attach a Thread$UncaughtExceptionHandler to the current thread (my main thread). I do this via

(ns exception-test.core)

(defn -main
  [& args]
  (Thread/setDefaultUncaughtExceptionHandler
   (reify Thread$UncaughtExceptionHandler
               (^void uncaughtException
                [^Thread$UncaughtExceptionHandler this ^Thread t ^Throwable e] ; -> void
                (println "caught:" (.getMessage e)))))
  (throw (Exception. "this is the ex"))
  (println "after ex"))

Marco Schneider08:08:06

My expectation would be that the "this is the ex" expection is caught, but it isn’t. Maybe someone can help me out here?

delaguardo08:08:45

are you testing your main function in REPL?

Marco Schneider08:08:31

No, I’m calling it from the shell via clojure -M -m exception-test.core

delaguardo09:08:03

ok, that isn’t working because of https://github.com/clojure/clojure/blob/master/src/clj/clojure/main.clj#L650-L672 exception thrown by your code will be catched by clojure’s main function

Marco Schneider09:08:41

Thanks a lot. I just figured out the same thing.

Tomato08:08:08

Hi, Clojurians. I’m Younghwan Nam. I’d love to ask about AWS lambda layer where I am stuck in. in deps.edn , I’d like to know how to add sth like scope : provided . I’m considering Lambda Layer to separate dependencies. after making layer, I was trying to make uberjar to deploy lambda. but because of aot: true dependencies are necessary. I have no idea how to deal with it. Thanks a lot.

Tomato08:08:09

Here is my dep.edn for application.

{:paths ["src" "resources"]
 :deps {org.clojure/clojure {:mvn/version "1.10.3"}
        com.amazonaws/aws-lambda-java-core   {:mvn/version "1.0.0"}
        com.amazonaws/aws-lambda-java-events {:mvn/version "1.0.0"}}
 :aliases
 {:dev  {:extra-deps {clojure.java-time/clojure.java-time {:mvn/version "0.3.2"}}}
  :uberjar {:replace-deps {com.github.seancorfield/depstar {:mvn/version "2.0.211"}}
            :exec-fn hf.depstar/uberjar
            :exec-args {:aot true
                        :jar "lambda-demo.jar"
                        :main-class "yhnam.lambda-demo"
                        :sync-pom true}}}}

Tomato08:08:42

Test for separate java-time dependency

vemv14:08:43

I'd say that scope provided is something for libs to use, not applications If you need to make a dependency optional, you can simply isolate it via the :aliases mechanism e.g. it can be present under the :dev alias but otherwise absent by default. Anyway I'd recommend taking a step back and describing your problem more precisely, before considering any specific solution

emccue15:08:01

So basically you want to compile your AOT code with some dependency on the classpath and then make an uberjar with that dependency not on the classpath

emccue15:08:27

or otherwise not included in the uberjar

seancorfield15:08:16

depstar supports different sets of aliases for compilation and for JAR-building, which was added specifically for this use case.

seancorfield15:08:06

:aliases and :compile-aliases are the exec arguments you need but you'll need to ensure that what you need for compilation is added via an alias, so that you can tell depstar "compile it with these dependencies" and then "build it with these different dependencies".

❤️ 4
kwladyka19:08:31

https://github.com/kwladyka/consistency-clj/blob/master/deps.edn here is example of real code for compile to uberjar and publish to clojars consider just use https://clojure.org/guides/tools_build#_parameterized_build . I didn’t have a chance to try, but looks like it can be new standard.

seancorfield19:08:35

@U0WL6FA77 That is not a useful example: it does not involve :aliases or :compile-aliases for depstar which is what the OP needs.

kwladyka19:08:30

ok sorry, I didn’t quite understand the question.

Tomato05:08:27

Thanks a lot! it’s really helpful.

kwladyka11:08:40

confirmed, it was the issue

kwladyka11:08:19

it is worth to look on number of threads in the process. if it is growing in time it can means something not close properly.

p-himik20:08:14

It is impossible to defrecord with the same name as a class in java.lang, right? E.g. (defrecord Enum []) fails with Enum already refers to: class java.lang.Enum.

phronmophobic21:08:26

This seems to work:

(ns-unmap *ns* 'Enum)
(defrecord Enum [])

4
phronmophobic21:08:47

not sure if there's a cleaner way

Alex Miller (Clojure team)22:08:29

Seems like the best idea I can think of