Fork me on GitHub
#clojure
<
2019-09-10
>
nha01:09:18

I am seeing this: https://github.com/puredanger/clojure-from-java A java interface backed by Clojure. Is there an example of a Clojure Protocol backed by Clojure but used from Java? EDIT: I am guessing the protocol will have to have type hints - but will it suffice?

nha01:09:43

Starting even smaller, the following does not seem to work (compilation error):

public boolean isAwesome() {
  IFn isAws = Clojure.var("mylibraryinclojure.myns", "abooleandef"); // in a CLJ library (def ^boolean abooleandef true)
  IFn deref = Clojure.var("clojure.core", "deref");
  System.out.print("isAWS " + deref.invoke(isAws)); // prints true
  return true; // OK
  return deref.invoke(isAws); // KO
  // error: incompatible types: Object cannot be converted to boolean
  //   return deref.invoke(isAws);
  // ^
}

andy.fingerhut01:09:18

Likely the deref.invoke method returns type Object, not boolean.

nha01:09:17

Yes, I was hoping that the type hint in (def ^boolean abooleandef true) would help 😕

Alex Miller (Clojure team)01:09:46

to invoke a protocol from Java, you'll want to call through the same named interface that is generated

Alex Miller (Clojure team)01:09:56

that protocol will always have all Object in method calls and returns

Alex Miller (Clojure team)01:09:17

this is usually a poor interface from a Java user perspective (it will also lack javadoc, etc)

Alex Miller (Clojure team)01:09:43

generally I find if your goal is a high quality Java interface, you should make that interface yourself, in Java

nha01:09:46

ok, noted thanks 🙂

Alex Miller (Clojure team)01:09:50

the repo above is mine btw

nha01:09:14

yes I noticed 😄

Alex Miller (Clojure team)02:09:45

I've used that technique on a couple of real projects with success

🎉 4
nha02:09:44

Is using definterface here acceptable? Or will I hit limitations too?

Alex Miller (Clojure team)02:09:28

it's better - you can at least type things properly

Alex Miller (Clojure team)02:09:38

but still no javadoc

😭 4
ahungry02:09:29

I notice a big problem/trend in software for quite some time, and this problem is not really limited to clojure uniquely in anyway (and for non-library code, I'm often quite guilty of it, but think i'm a little more on base for library code), but that's "completely nonsensical names for different packages" (or, names that have no meaning). I would much rather read something like com.acme.net.web.routing and com.example.net.web.routing than compojure or ataraxy or bidi, a bunch of names that don't give any insight into whats in it. Is clojars the best location to get a list of "clojure package that does 'foo'"? (other than search engines)?

ahungry02:09:49

https://clojars.org/search?q=ring+routing - almost 1000 different results to look through - "html templating" is equally as bad

ahungry02:09:38

this link looks nice, thanks

danielcompton02:09:29

though doesn't cover every library published to Clojars, just a curated set

ahungry02:09:12

I think the java convention has 2 big benefits - its easy to tell whose responsible for a library, and it lends itself to actually hosting documentation at that url

ahungry02:09:48

Does clojars have an API or a page where you can choose sort of results? like, sort by last publish date, or sort by total downloads/popularity?

danielcompton02:09:55

I'm writing a plugin which takes a collection of namespaces to be required dynamically. What would you name the argument to that function? namespaces, nss, libs, libspecs, or something else? In this case it doesn't make sense to provide libspecs as they are required purely for spec registration side effects, not for referring or aliasing into a namespace

danielcompton02:09:34

There is an API which does take some Lucene search query params. Not sure how well it is documented, but I think cljdoc was using it, at least for a while

hiredman02:09:15

Maybe ns-names given it will be a collection of symbols, not namespace objects

8
ahungry02:09:55

Does Clojure have an installer type setup for Windows (similar to pacman -S clojure for Arch Linux)? or is the only Windows option signing up for an oracle account and downloading the jdk by hand, and then getting the clojure jar? After many years away from windows, I tried to set up leiningen on a windows VM - it was a very bad experience

seancorfield02:09:57

@m131 Check out #clj-on-windows and folks will be happy to tell you how they do stuff...

seancorfield02:09:14

Scoop is very popular as a package manager on Windows, I gather.

seancorfield02:09:32

That certainly makes it easy to install any number of different JDK variants.

seancorfield02:09:13

I installed the Zulu JDK 8 + JavaFX bundle that way over the weekend -- to test REBL on Powershell.

seancorfield02:09:41

And there's a Scoop bucket for Clojure (unofficial, but it uses the official Powershell alpha installer).

ahungry02:09:22

very cool, thanks, I'll give that a look - seems a lot better than random cnet links if I want to skirt around the oracle sign up form

seancorfield02:09:53

There are lots of OpenJDKs out there -- no need to deal with Oracle's at all these days on any platform.

seancorfield02:09:09

The Scoop bucket listed there also makes it easy to install Joker, a linter for Clojure (which has a lot of editor integrations).

ahungry02:09:13

if I wanted to write a gui with the widest-reach in clojure, is seesaw, being swing oriented, the best candidate? I really like cljfx, but the openjfx dependency seems very flakey between java versions - bundled in some of them, not present in others, available as a maven dependency here or there

gerred03:09:34

i'm partial to adoptopenjdk, haven't tried zulu

jcburley04:09:35

Is there a good place to find and ask macro wizards questions (or is this it)? I'm struggling with defining a macro that checks whether an argument is passed is a type (in Joker; "Class" in Clojure/JVM) before deciding on the expansion.

hiredman04:09:27

That is the kind of thing that is only going to work in a limited number of cases

hiredman04:09:22

If your macro argument is anything other than a literal object, then you are going to have problems

jcburley04:09:26

My use case might narrow those cases down to only the useful ones: I want to extend the repl's doc function to support e.g. (doc Boolean), i.e. documentation of types.

hiredman04:09:21

Boolean as returned by the reader is a symbol

jcburley04:09:36

Doing things the obvious (to me) way, I can't get (doc Boolean) to work, because for some reason the (type? name) ... test I've inserted before the final (resolve name) in the cond list (which matches Boolean and then tries to (var ...) it) doesn't recognize it as a type.

hiredman04:09:52

Because the reader reads it as a symbol, and it isn't until it is evaluated (compiled and executed) that you get a Class object

jcburley04:09:55

In my Clojure repl I've done (defn type? ^Boolean [x] (= (type x) java.lang.Class)), which works in isolation on the few test cases I've tried. But if I call that in a macro, it doesn't work, and I've tried various things that don't seem to get it to work.

jcburley04:09:06

That's interesting.

hiredman04:09:41

And macros, by their nature get things before they are evaluated

jcburley04:09:00

Yeah, that probably explains why I'm hitting these issues.

hiredman04:09:24

You likely just need to move your logic after the call to resolve

jcburley04:09:37

In what way though?

hiredman04:09:06

Resolve may turn the symbol in to a class object

jcburley04:09:08

One snag I've hit is I can't (try (var ...) ...), because var is kinda special.

hiredman04:09:44

I dunno why you would do that anyway

jcburley04:09:44

Oh, I think I see what you're saying: capture the result of (resolve name) (instead of just testing it) and test that result with (type? ...)?

jcburley04:09:57

Okay, I'll give that a shot.

hiredman04:09:12

But I forget if resolve only resolves vars or also does classes

jcburley04:09:22

Will find out shortly!

jcburley04:09:57

Well, this is promising:

user=> (defmacro mm [n] (let [r (resolve n)] (if (type? r) (println "is a type") (println "not a type"))))
#'user/mm
user=> (mm +)
not a type
nil
user=> (mm Integer)
is a type
nil
user=> (mm Boolean)
is a type
nil
user=> 

jcburley04:09:07

Okay, this seems to work, in that I get a nil Meta map (because I haven't yet added the code to populate that for any of the builtin Joker types) instead of an error when I do (doc Boolean):

(defmacro doc
  "Prints documentation for a var, type, or special form given its name,
  or for a spec if given a keyword"
  {:added "1.0"}
  [name]
  (if-let [special-name ('{& fn catch try finally try} name)]
    `(#'print-doc (#'special-doc '~special-name))
    (cond
      (special-doc-map name) `(#'print-doc (#'special-doc '~name))
      (keyword? name) (println "Keywords (spec) not yet supported")
      (find-ns name) `(#'print-doc (#'namespace-doc (find-ns '~name)))
    
      (resolve name) (let [x# (resolve name)]
                       (if (type? x#)
                         `(#'print-doc (meta ~x#))
                         `(#'print-doc (meta (var ~name))))))))
Thanks!!!

jcburley04:09:24

(It's not the Clojure doc, though -- that's the one currently defined by Joker. I recently PRed the (find-ns name) clause to support printing documentation for namespaces.

jcburley04:09:08

(And yes the code looks kinda ugly to me, because of the duplicate (resolve name) being done in that case. Not sure how best to address that though....)

jcburley04:09:56

(The similar duplications should probably be refactored as well.)

jcburley04:09:07

FWIW, the code is working quite nicely now! Thanks again, @hiredman!

jcburley05:09:51

For anyone curious about what I was trying to do, here's the resulting PR: https://github.com/candid82/joker/pull/262

Empperi05:09:06

It's so nice that these days in almost half of the job ads I see which are located near me (Helsinki, Finland) there's also Clojure listed as a language which they are using

Empperi05:09:35

Don't know about rest of the world but in Finland Clojure is going strong

clj 28
28
8
jsabeaudry13:09:14

(clojure.string/replace "a" #"a" "\\") Why won’t this replace a by \ ?

Alex Miller (Clojure team)13:09:35

per the doc string:

For pattern / string, $1, $2, etc. in the replacement string are
   substituted with the string that matched the corresponding
   parenthesized group in the pattern.  If you wish your replacement
   string r to be used literally, use (re-quote-replacement r) as the
   replacement argument.

Alex Miller (Clojure team)13:09:45

user=> (clojure.string/replace "a" #"a" (clojure.string/re-quote-replacement "\\"))
"\\"

borkdude14:09:11

however in CLJS:

cljs.user=>  (clojure.string/replace "a" #"a" "\\")
"\\"

Alex Miller (Clojure team)14:09:15

regexes are inherently an area where host semantics matter and may differ

borkdude14:09:20

but you can also do:

(clojure.string/replace "ab" #"(a)(b)" (fn [[m group1 group2 :as v]] group2))

borkdude14:09:30

ah, it calls directly to the host more or less, didn't know that

borkdude14:09:48

makes sense

SgtZdog17:09:11

Hey all, I can't find if there is a way to have lein run tell me the return value of my -main function. Is there a way?

SgtZdog17:09:13

Right now I know I can do it by either running in the nREPL or if I use System/exit, but the latter will kill an nREPL solution as well as my function.

Alex Miller (Clojure team)17:09:30

There is no return value

SgtZdog17:09:17

I don't suppose there's a way to detect if I'm running in an nREPL?

Alex Miller (Clojure team)17:09:12

The function literally does not return a value (it’s a Java void return)

Alex Miller (Clojure team)17:09:51

I often have -main call a function that does the work and use that for testing etc

emccue19:09:27

kinda vague question

emccue19:09:10

what are people's preferred ways of validating external input / data

emccue19:09:30

i don't really have a good sense of the idiomatic way to do it in clojure

emccue19:09:58

Ive used the whole Decoder a -> ... -> Result _ a approach in typed languages

emccue19:09:20

but i don't know a satisfactory way of achieving the same result here

lukasz19:09:59

@emccue either https://github.com/plumatic/schema or clojure.spec will work for you (I'm prefer schema, as it's easier to map it to the shape of the external data, but it's a personal thing)

emccue19:09:59

see that makes sense to me kinda within functions, but i don't know how to use those tools to actually manage what happens if it goes wrong

emccue19:09:28

does that make sense?

emccue19:09:46

like, if i validate a schema and its wrong i get an exception

emccue19:09:34

but i don't know how to tell the user "sorry, your name field was > 140 characters" without doing it all manually

emccue19:09:00

not that i am averse to manual code

emccue19:09:10

i just feel lost and confused

lukasz19:09:51

Gotcha. I've seen projects which "humanize" schema (or spec) errors - worth checking them out. This might be a good jumping off point https://github.com/datil/schema-rosetta