Fork me on GitHub
#clojure
<
2019-01-25
>
didibus00:01:50

QUESTION: How do you compile only gen-classes ? Like I don't even want to compile the namespace which has the :gen-class in it, but I only want the Java .classes defined by gen-class to be compiled? Using pure Clojure, not with lein.

didibus00:01:58

I see, so gen-class are kinda infectious then

didibus00:01:09

You quickly devolve into basically full AOT

didibus00:01:14

since compile is transitive

hiredman00:01:21

there are things you can do

hiredman00:01:56

have your namespace with the gen-class require other code at runtime instead of when it is loaded

didibus00:01:44

Like by putting a call to require inside a function?

didibus00:01:52

instead of using ns ?

hiredman00:01:05

then you will have to manually resolve any vars you want to use

hiredman00:01:30

I mean, you still use ns, you just leave out calls to require

didibus00:01:14

Ya, that's a bit annoying

didibus00:01:28

But thanks for the answer

noisesmith00:01:26

example of a java app that uses this a related approach (written so I could use the jsvc app launcher without using gen-class) https://github.com/noisesmith/clj-jsvc-adapter/blob/master/src/java/org/noisesmith/Cljsvc.java

didibus00:01:48

That seems different, you're just avoiding gen-class altogether here, and creating your own Java wrapper no?

noisesmith00:01:18

right, but it's doing the same thing: require at runtime, then calling functions that should be made available by the required code

noisesmith00:01:52

you can do the same thing from an ns that uses gen-class (I started out with that, but with that level of java interop writing a java file was cleaner)

didibus01:01:00

It seems more complicated from Clojure, because then you need to have a flag which on compile does not cause things to be required, but does so otherwise

didibus01:01:19

Where as in Java it is done from static initialization when the class is used

didibus01:01:48

Though I guess the gen-class init could do it

didibus01:01:01

And then it would be similar to what you're doing I guess

hiredman01:01:36

the thing is, clojure is live, so compiling the code has the same effects as loading it (because compiling subsequent code made depend on those effects)

hiredman01:01:38

another thing you can do is just generate the bytecode for the class you want without dealing with the clojure compiler at all

noisesmith01:01:58

@didibus the clojure version of that code looked like:

(ns foo.bar)

(defn -main [& args]
 (require 'baz.quux)
 ((resolve 'baz.quux/-main) args))

noisesmith01:01:41

you can add gen-class to that, and it won't load baz.quux while compiling, this is directly analogous to what the java code is doing (just much less idiomatic)

didibus02:01:06

Still could be problematic, if that namespace is also used from Clojure though

didibus02:01:19

Which is why I was thinking something more like:

(ns foo.bar)

(when-not *hypothetical-compiling-flag*
  (require '[baz.quux]))

dpsutton05:01:57

wow i've never seen with-precision before from core

borkdude08:01:47

what’s a good name or an option for a map transformation that’s not recursive? no-recurse? We already had a version that did recursion by default.

kirill.salykin08:01:32

what about linear?

lmergen09:01:24

i would stick with recurse? without the no- because it's not necessary

lmergen09:01:31

other than that, it seems like an appropriate name

borkdude09:01:13

well, we have a convention that options should take nil or false as the default, so I have to invent a name for non-recursive. I’ll probably go with that

lmergen09:01:36

in that case, just stick with no-recurse?

borkdude09:01:38

leaving out the option is the same as passing the option with false or nil

Marko09:01:48

Hi guys, is there any way to format code in .clj files with pprint?

roklenarcic10:01:19

Is there a string length function I can use both in clj and cljs? I can use count, but count is slow and generates ton of garbage

lukas.rychtecky12:01:20

Why do you think that count is slow? And what garbage?

jumpnbrownweasel12:01:58

@roklenarcic, you may be thinking of the implementation of count for sequences.

roklenarcic12:01:18

I've improved performance a lot in some of my libraries by replacing count with explicit .length calls

roklenarcic12:01:12

Looking at the newest 1.10 code of count, directly invoking .length saves about 4 if sentences

lukas.rychtecky12:01:40

I’d say that this only makes sense when you have a real bottle neck.

borkdude10:01:30

@roklenarcic this seems to work:

(defn str-length [s] #?(:clj (.length ^String s) :cljs (.-length s)))

roklenarcic11:01:06

well obviously I can write my own 😄

roklenarcic11:01:26

I was hoping for an official solution and I'm shocked that clojure.string namespace doesn't have one

roklenarcic11:01:42

hell even substring exists in clojure.core

henryw37412:01:27

Hi everyone, I'd like to get compiler warnings when a variable masks another one So, for example in this case:

(let [[name] ["yay"]]
  name)
=> warning: name already refers to clojure.core/name anyone know if there is a way to turn that on, or if there is an open issue for this? If there is I haven't found via googling. thanks

borkdude12:01:57

not that I know. joker (a linter) also doesn’t warn about this, but I think it could be a useful feature for it

roklenarcic12:01:47

@mark540 As explained, count isn't appropriate because it's slow and generates garbage

henryw37412:01:44

@borkdude thanks, linters are probably the place to start investigating if it's not in the compiler

dominicm12:01:35

I actually quite like being able to shadow

borkdude12:01:54

that’s why linters have config 🙂

jumpnbrownweasel12:01:35

What would be useful to me is an option to only warn about shadowing clojure.core symbols, as in the example.

Jan K13:01:48

This linter warns about (some cases of) shadowing: https://github.com/jonase/eastwood

👍 10
m_m_m13:01:15

Hi. I have an error with my simple module: https://pastebin.com/bBy8htnT error: Exception in thread "async-dispatch-88" java.lang.NullPointerException can anyone tell me why? I've spend on this some time and I really don't know why.

Jan K14:01:56

You should check the full stack trace using (clojure.repl/pst), but I can see a couple things wrong with that code. When you're using blocking <!! you shouldn't wrap those in go blocks. Also by putting the "store" in a global def you're defeating the purpose of mount/defstate.

Chris15:01:46

Am I right in thinking libraries shouldn't include org.clojure/clojure as a dependency? Since it's just going to be provided by the application anyway?

borkdude15:01:44

a lot of libraries do it, it can be overriden by the consuming project

borkdude15:01:18

unless you’re making a cljs only lib or a Java-facing AOT-compiled lib, it doesn’t matter I guess

borkdude16:01:29

or maybe it does when your lib forces a newer version of clojure than the lib consumer wants to user? hmm. not sure how that is resolved

taylor16:01:49

I've also wondered how this works when multiple dependencies declare dependencies on diff versions of Clojure

devn17:01:54

In the past, I've usually set the default uncaught exception handler at the top of a -main entrypoint for an application. I am ring uberjar'ing. Will setting the default uncaught exception handler at the top of, say, server.clj (the location of the ring handler) accomplish same?

devn17:01:37

(ns server)
(Thread/setDefaultUncaughtExceptionHandler
 (reify Thread$UncaughtExceptionHandler
   (uncaughtException [_ thread e]
     (log/error e "Uncaught exception on" (.getName thread)))))
(def handler ...)

noisesmith17:01:53

it's a mutable slot on an object, you can set it in any place at any time

noisesmith17:01:23

top level side effects are run when the ns is loaded (even when using aot)

pserrano17:01:37

Can I define a mutation over an ident, instead of declaring all the way walking through the tree?

noisesmith17:01:54

by ident do you mean symbol or keyword? that's what clojure.core/ident? checks for, but if that's what you mean your question confuses me

noisesmith17:01:16

do you mean a nested update as in update-in or assoc-in as opposed to a programmatic operation like clojure.walk/post-walk ?

pserrano17:01:26

I mean, if I have a normalized table :people/people-list and inside it :person/by-id Can I use a mutation directly for [:person/by-id 1] or do I have to go into [:people/people-list :my-list :person/by-id 1]

lilactown17:01:31

@patrickcms your use of the word “mutation” is confusing. If you are asking how to use update-in / assoc-in with a map, then yes you’ll have to put the full path

lilactown17:01:57

you could come up with your own function that uses clojure.walk to do what you mean, though. Again, assuming you’re using a map

pserrano17:01:14

Oh, I messed up, I thought I was in the fulcro's slack. I'm sorry

kenny17:01:38

In 1.10, is there a way to extend a map to be Closeable via metadata?

lilactown17:01:23

is that java.io.Closeable? I think that’s an interface, not a protocol

kenny18:01:09

Yes. And I suppose a better question would've been: can you extend via metadata with an interface.

kenny18:01:20

Sounds like no 🙂

noisesmith18:01:19

metadata is a clojure thing - you can check metadata via java by using the clojure IMeta api (or using the Clojure api to call clojure.core/meta) but this isn't something you should expect normal java code to be doing, ever

noisesmith18:01:33

and it's definitely not something that exists on the level of the Closable interface

noisesmith18:01:48

you can use defrecord to make a hash-map that is also Closable

kenny18:01:13

I ended up doing that.

lilactown18:01:27

I think there was a proposal to implement Closeable as a protocol

kenny18:01:44

That would be convenient. It's nice to be able to with-open things.

noisesmith18:01:23

that's a change to with-open so it can use things that aren't directly java.io.Closable, it doesn't change or extend Closable itself

noisesmith18:01:29

what's the motivation for not using java.io.Closable - wanting to extend some class from outside the implementation?

kenny18:01:00

I have an API that returns a map and I wanted to use with-open in my tests to ensure that parts in that map are closed when the test finishes.

noisesmith18:01:04

but then you'd be extending closable to map?

lilactown18:01:18

I think that’s why he wanted to do it via metadata

noisesmith18:01:45

you can implement protocols just via metadata?

kenny18:01:59

Right. Wrapping in a record is fine. Just seemed cleaner if it was possible to do it via metadata.

noisesmith18:01:11

ahh, a new 1.10 feature

lilactown18:01:23

yep! it’s super cool

✔️ 10
andy.fingerhut18:01:30

Probably part of the way JIRA works, either by default, or perhaps by custom configuration of this instance, but I don't know which.

andy.fingerhut18:01:03

Given the conversation on that issue, I would not hold high hopes that it would be implemented in core even if it got a thousand votes.

andy.fingerhut18:01:37

Votes get attention to an issue sooner, they don't necessarily change the decision made once it has been considered.

andy.fingerhut18:01:46

My suggestion would be making your own variant of the function that works as you wish, and use that. Given the interest in it by some others, I wouldn't be surprised if Specter can do it, or medley, or one of handful of other utility libraries.

👍 5
souenzzo18:01:28

I published a patch on Twitter then everyone can fix your codebase. 😅

😕 5
andy.fingerhut21:01:49

Anyone can patch their own copies of Clojure all they wish, of course. Not nearly as convenient as having it in a place where it can be used without a patch.

mseddon22:01:48

@U2J4FRT2T Just refer your update-in and exclude clojure's version. The current behaviour has been useful to me tracking down bugs that would otherwise subtlely succeed but mysteriously trash everything :) (consider, returning a dynamically generated path vs or nil for the second argument)

mseddon22:01:03

Your semantics are equally valid of course, but clojure is extremely amenable to hacking, and guardrails are nice in general imo. Particularly in a dynamic language like a lisp.

didibus22:01:35

I think you can still comment though?

jumpnbrownweasel23:01:05

This is perhaps a different issue, but get-in does seem inconsistent and I wonder if the fact that it returns the entire map when [] is passed is intentional or it just happens to do that. There is no way to tell from the doc, since it just says "ks is a sequence of keys" and doesn't say whether it can be an empty sequence.

👍 5
jumpnbrownweasel23:01:37

Oops, I meant get-in not get, fixed.

jumpnbrownweasel23:01:22

My guess is that the behavior with an empty sequence is accidental and the doc should probably say "ks is a non-empty sequence of keys".

👍 5
mseddon23:01:55

'Fixing' that asymmetry might break a lot of existing code. 😀

mseddon23:01:45

That's not to say clojure 2 might not fix this sort of thing, but pretty much everything in 1.x is backwards compatible for practical reasons.

mseddon23:01:21

The docstring change would be really helpful though.

mseddon23:01:12

https://www.conj.io/store/v1/org.clojure/clojure/1.9.0/clj/clojure.core/update-in grimoire reports the correct signature though. Not a computer atm, but wonder if that is how it is defn'd

noisesmith18:01:41

so you could make a new IClosable and a new with-open

noisesmith18:01:59

or you could pass the relevant vals to the current with-open (it allows N closables)

kenny18:01:05

I suppose. This works for now - not critical. Was just trying to use a new 1.10 feature really 🙂

noisesmith18:01:27

yeah, extending via metadata is opt-in on a per-protocol basis, interesting

lilactown18:01:02

I think that was for performance reasons