Fork me on GitHub
#clojure
<
2019-10-07
>
Chad Cassady00:10:07

Can you just up-arrow/ctrl-r/m-p through your history?

Alex Miller (Clojure team)01:10:56

@kulminaator source is implemented to look up the source file containing the code and extract it. it's not designed to find repl created fns

Arto Kalishian06:10:08

I have made this simple desktop wallpaper. Helps me keep focused on studying clojure. Enjoy!

aw_yeah 8
👍 16
pez06:10:41

I have a cljc file where I do #?(:cljs (:import goog.string.StringBuffer)) and then later use that as a replacement for StringBuilder. However, I have a type hint in the arguments box of a function where I send an instance of this. Like so:

(defn- foo [ast ^StringBuilder string-builder] ...
Things work, but it feels like I could be tripping up the ClojureScript compiler this way… Any ideas what I could do about it?

dominicm09:10:17

#?(:clj ^StringBuilder) should work I believe.

miikka09:10:28

No, it won't, you can't use reader tags for metadata like that – you'll get a parse error about how the tag does not apply to anything (or something like that). You'd need to something like #?(:clj ^StringBuilder string-builder :cljs string-builder)

Ivan Fedorov10:10:23

Howdy! Anyone ever built a duo out of a rust binary and a clojure uberjar? I’m interested how would one ship that into [canary] production [without Docker if possible].

dominicm10:10:31

You might wanna take a look at the embedded java postgres builds on top of. It's a java library for running binaries. I forget what it's called.

Ivan Fedorov10:10:41

@U1SPRM8LE cool, thanks for a lead!

Ivan Fedorov11:10:20

yeah, thanks mate! They all seem to be a provisioning wrapper around a bundled binary. Which is a way to go.

markus06:10:32

Which is the main program, the Rust binary or the Clojure jar? If the Rust binary is the main program you can just use JNI from Rust to load the JVM shared library, provide an interop interface between the languages and start your Clojure code. JNI works the other way around too if the Rust binary is a shared library. https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html

dominicm06:10:20

Graalvm&llvm is probably an option too

markus06:10:01

If you are concerned about packaging: 1. If the Rust binary is a library it can be packaged in the Clojure jar as a resource, unpacked at runtime and loaded with System.load. 2. If the Rust binary is the main program... I don't know. I have very little Rust knowledge. But theoretically you can always bundle resources inside any executable file so it should be possible to have a single file distribution for that too.

markus06:10:29

@dominicm You mean by using the language interop features? Or did you think about native image? I don't think native image supports actually having compiled LLVM code as a guest language so even if you can compile the Clojure jar to an executable the Rust code might run slow when called in that scenario.

dominicm06:10:43

Interop features, not thinking about native image.

markus06:10:48

But if you are running on the GraalVM and not native image SubstrateVM then it might be plenty fast and probably an easier option than my suggestions.

dominicm06:10:28

The hard part is that it isn't packaged anywhere yet!

markus06:10:12

Yeah. That is why I mentioned packaging a library as a resource and native image. The deployment is usually the issue and native binaries or at least having a single jar makes that much easier. I would love to be able to deploy a single executable with many languages in it. Hoping for an improvement in native image for that.

dominicm07:10:10

I meant graalvm itself :)

Ivan Fedorov15:10:56

@U89UL6P9P the jar is the main one. Rust bin is a slave server. They talk via websocket. So I think the about packing the bin into a jar as a resource yes, as a start. Thanks!

pez10:10:34

@miikka, @dominicm: The first thing I tried was to just conditional the hint. That didn’t work and I ran out of ideas. 😃 The latter suggestion works great. Thanks!

dominicm10:10:12

Huh, I didn't realize that the metadata reader worked as a group not as an individual thing.

miikka11:10:02

Yeah... It makes sense to me in the code-is-just-data sense but it's super annoying when you have to conditionally tag a lot of forms.

dominicm13:10:41

That's a good way to think about it. There's no partial forms in the reader.

David Pham12:10:44

Which mechanism of polymorphism do you use most in UI? I tend to prefer multi methods, because they feel more natural, but maybe I get it wrong? I try to avoid giving functions as parameter in the rendering function, but am I mistaking?

awb9913:10:50

(print-table [ {:a {:b 1 :c 2} :d 3} {:a {:b 4 :c 5} :d 6} ] [ [:a :c] :d] ) Result would be :a :c + :d +++++++++++++++ 2 + 3 5 + 6

awb9913:10:00

is there any library that would do print-table with nested maps?

awb9913:10:18

The original clojure.pprint/print-table does not like nested properties

andy.fingerhut13:10:51

I don't know the answer to your question. You may have already considered this, but you could write a function that creates a new map from your existing one, and then call print-table on that?

awb9913:10:25

@andy.fingerhut Yes I am considering that.

awb9913:10:35

In fact I am thinking of doing a pre-formatter

awb9913:10:40

that adds nested properties

awb9913:10:50

say I have :a {:b}

awb9913:10:02

then I want to add a column :a-b

awb9913:10:13

so the normal clojure print-table could be used,

awb9913:10:24

and I only have to call (denest table) first.

andy.fingerhut13:10:58

The normal Clojure print-table might also work with a key of the form [:a :c] -- worth a test, anyway if the output from that meets your needs.

andy.fingerhut13:10:42

For example, the current print-table implementation can already do this:

user=> (pp/print-table [[:a :c] :d] [ {[:a :c] 2 :d 3}  {[:a :c] 5 :d 6}])

| [:a :c] | :d |
|---------+----|
|       2 |  3 |
|       5 |  6 |

awb9913:10:04

It seems [:a :c] is a key that is a vector.

awb9913:10:10

I am looking to do nested maps.

awb9913:10:17

But very interesting that this works.

andy.fingerhut13:10:52

Keys in maps can be arbitrary Clojure collections.

andy.fingerhut13:10:52

As far as other 3rd party libs for printing tabular data, I am aware of these two, but not whether they already do what you want. You might want to scan the examples in their docs to check: https://github.com/cldwalker/table https://github.com/joegallo/doric

awb9913:10:02

(clojure.pprint/print-table [:a [:c :d]]
    [ {:a 1 :b 2 :c {:d 3}}
      {:a 4 :b 5 :c {:d 6}} ]
           ) 

awb9913:10:43

| :a | [:d :c] |
|----+---------|
|  1 |         |
|  4 |         | 

andy.fingerhut13:10:31

Right, that doesn't already do what you want, but if the map were manipulated via some other code to produce one that had keys [:c :d] with the values you wanted to see in the table, then calling print-table on that modified map would print what you want.

awb9913:10:47

GOOD POINT!

awb9913:10:06

VERY GOOD POINT!!

awb9913:10:35

😘😘😘

awb9913:10:31

Also thanks for the 2 library links!

awb9913:10:30

This are so basic print requirements,

awb9913:10:37

funny that there is not more demand for them.

awb9913:10:22

Inspecting lists of complex data should not be too uncommon task.

awb9913:10:53

I wrote a little print-table that can filter rows easily before printing

awb9914:10:15

I got it running 🙂

andy.fingerhut15:10:58

cool. Check out the small set of functions in namespace clojure.set for some that may be useful for what you are doing. They are pretty basic.

denik16:10:23

Wrote a lib recently to leverage spec for a looser form of multimethods. It's part idea-sketch, part pun, part maybe useful? See code examples in tests. https://github.com/den1k/defmostly

sgerguri16:10:00

When using multimethods is it always required that an implementation namespace is required at some stage? I have a few multimethods which spread their defmethod implementations over several namespaces and I am finding (rather annoyingly) that these need to be required before use otherwise the dispatch clause simply will not be found. I haven't tried this in a running jar yet, only in testing/REPL but I am finding this to rather limit the openness/extensibility in that I need to be aware of the callpoints of the multimethod to make sure that the clause has been actually added to the system. Does the same happen when one compiles this down to an uberjar or is it enough then to simply require the namespace that holds the defmulti declaration?

hiredman16:10:14

you have to load the code to use the code

4
sgerguri16:10:03

Thought as much. I wonder if given this it is better to simply place all the dispatch clauses in the same namespace as the multimethod declaration - that way, it's just one import away. How do folk usually do it here - single or multiple implementation namespaces for multimethods?

hiredman16:10:15

I don't use multimethods a ton, but in the past my conclusion was the way to structure things is as a diamond shape: namespace spi contains the defmulti, namespaces impl1 and impl2 require spi and contain defmethods, namespace interface requires impl1 and impl2 and defn's a wrapper around the defmulti

hiredman16:10:03

the diamond shape gives you a place to require all the implementations and also avoids circular dependency issues people stumble into with multimethods

Alex Miller (Clojure team)16:10:06

depends on the use case. if you are using multimethods primarily to create a fixed set of polymorphic behaviors, then putting them all in the same place is easiest. if it's designed to be an open system, then it might make more sense to rely on some higher level of control to know how to declare the method and say which namespaces to load.

Alex Miller (Clojure team)16:10:58

and agreed on the @hiredman's structure

dominicm16:10:31

What kind of higher level of control do you mean @alexmiller?

Alex Miller (Clojure team)17:10:58

someone that is deciding what to load

Alex Miller (Clojure team)17:10:51

either a fixed set of ns'es or possibly even an open set defined in config

hiredman17:10:29

I've done that with multimethods too, defining basically an interface as a group of multimethods and having some kind of config file that says which implementation of that interface to use and which namespace to load to get it

dominicm17:10:27

So either application specific (config.edn), or deriving implementation from keyword namespace (like integrant)?

dominicm17:10:03

I had considered using a data_readers.clj-like thing in the past too.

hiredman17:10:16

I think, for that kind of plugin thing I was doing then with multimethods, I would prefer a protocol now

dominicm17:10:31

Would be nice to have something in core, for libraries to load their extensions automatically if they're entirely about multi methods. But could be fixed in user space if library authors defining the multi methods could be brought on board.

Alex Miller (Clojure team)17:10:30

Are you talking about a set of methods in a single library or open set? If the former, that seems like a lot of complexity for something with a current simple solution. If the latter, how do you know where the extensions are?

dominicm17:10:16

No, the latter. A "blessed" solution. I think something like data_readers.clj but for indicating multimethod extensions could work, although it would be duplicative of what's there.

Alex Miller (Clojure team)17:10:52

Java actually has a way to do this now via service loaders

Alex Miller (Clojure team)17:10:14

really as a way of finding implementations of an interface

Alex Miller (Clojure team)17:10:19

uses manifest annotations

dominicm17:10:52

Oh cool. Basically what I'm describing.

Alex Miller (Clojure team)17:10:14

yeah, I mean the mechanism and constraints are a bit different, but same idea

tristefigure17:10:28

by the way, Ruby/Rails has this via the Gemfile's require: false option. In clojure, this would correspond to setting a flag on a dependency vector's metadata.

tristefigure17:10:45

And it also has initialization order problems lol

dominicm17:10:14

I don't think clojure would have ordering problems. Why does ruby?

Alex Miller (Clojure team)17:10:15

it doesn't seem like the gemfile require thing is the same thing

Alex Miller (Clojure team)17:10:39

seems like that's at the library/module level and we're talking about the ns level

Alex Miller (Clojure team)17:10:30

there are things like this already (provided or optional scope in maven for example)

dominicm17:10:49

I assumed that the gemfile manifest indicated which modules to load. Maybe I'm wrong.

dominicm17:10:13

Now that protocols can be attached to data, I also quite like the idea of using protocols.

Alex Miller (Clojure team)17:10:05

multimethods and protocols both have the same issue of loading extensions, so I'm not sure it makes a difference

sgerguri17:10:03

Some good tips here. True about protocols having the same issue, but that is typically something that I don't tend to hit as I tend to only have two implementations of any given protocol, but several dispatch clauses for a multimethod.

tristefigure17:10:21

Hi. I'm trying to type hint a HashMap<String, byte[]>. How can I do that ? I'm doing this because Clojure's automatically picks the wrong static method (same method name, also accepts a HashMap, but with keys of a different type).

noisesmith17:10:31

generics are mostly a fiction of javac, they only exist as an annotation in the bytecode, which most code never looks at

noisesmith17:10:10

clojure type hints don't do generics at all

noisesmith17:10:29

(they can hint ^HashMap but not the specialization)

Alex Miller (Clojure team)17:10:55

can Java even do what you're describing? two methods that differ only in the generics?

4
Alex Miller (Clojure team)17:10:25

can you point to public javadoc or anything?

tristefigure17:10:39

yes you're right, my bad, they do differ by name, I guess I rushed and misinterpreted the error I got, sorry.

devth18:10:47

(if-let [{:keys [x y z]} {:not "what ~you~ i expect"}] "yep" "nope")
always bites me. (evals to "yep")

borkdude18:10:25

what do you expect this to do?

devth18:10:41

i mean i sorta get it

devth18:10:44

but i repeatedly make the wrong assumption

borkdude18:10:28

maybe it makes sense if you think like (if-let [[x y] some-vector) vs (if-let [[x y] nil)

👍 4
devth18:10:37

might help looking at macro expanded too:

(let*
  [temp__5718__auto__ {:not "what you expect"}]
  (if temp__5718__auto__
    (let*
      [map__64993
       temp__5718__auto__
       map__64993
       (if (clojure.core/seq? map__64993)
         (. clojure.lang.PersistentHashMap
          create
          (clojure.core/seq map__64993))
         map__64993)
       x
       (clojure.core/get map__64993 :x)
       y
       (clojure.core/get map__64993 :y)
       z
       (clojure.core/get map__64993 :z)]
      "yep")
    "nope"))

kulminaator18:10:53

👼 if i'd find code that looks like that written by me i would just delete it and write it again ... (regarding that if-let from above)

🙂 4
kulminaator18:10:14

too old to puzzle around complicated blocks

devth18:10:47

first 3 lines of the macro expansion say it all

devth18:10:14

anyway i must not be the only one because it was a pattern i found in code contributed to an open source project i maintain. fooled us both 🙂

devth18:10:30

rewritten:

(let [{:keys [x y z]} {:not "what you expect"}]
  (if (and x y z)
    "yep" "nope"))

Eduardo Mata18:10:24

What library would y'all recommend for HTML parsing?

Eduardo Mata18:10:15

Thanks! Works great