Fork me on GitHub
#clojure
<
2019-09-18
>
Nazral09:09:44

why is (s/replace "1-1" #"-" "\\-") outputting 1-1 instead of 1\-1 ?

Nazral09:09:42

ah, "\\\\-" was the correct way

Daniel Stephens09:09:09

This seems like a bug since (s/replace "1-1" "-" "\\-") works fine. I think I'm going a little crazy but (.toString ^CharSequence "\\") throws an exception for me, whereas

(let [a "\\"]
  (.toString ^CharSequence a))
is fine?!

jumar10:09:17

Why do you need the type hint in the first place? Passing string is just fine. If you have a little function wrapping this then you would add type hint on the argument. Otherwise you need type hint in the let block - type hints can't be applied everywhere.

Daniel Stephens11:09:58

This is code copied from clojure.string/replace (sort of), I'm aware that it could be done other ways but that doesn't mean it's less of a bug

Daniel Stephens11:09:37

I was trying to work out why Nazral's example: (s/replace "1-1" #"-" "\\-") outputs 1-1 but (s/replace "1-1" "-" "\\-") doesn't

andy.fingerhut14:09:25

There are different cases in the implementation and explained in the doc string for s/replace, depending on whether the second arg is a string or a regex. They do not work the same.

andy.fingerhut14:09:30

If second arg is a string or a character, then the 3rd arg is a literal replacement string with no special interpretation, except the usual one for all Clojure strings in double quotes, where a single backslash is an escape for the next character.

andy.fingerhut14:09:28

If second arg is a regex, then the 3rd arg is not just a literal replacement, but can contain things like $1 or $5 that are replaced by the corresponding parenthesized groups in the regex match.

andy.fingerhut14:09:44

It should all be explained in the doc string for clojure.string/replace, but ask if it doesn't make sense after reading it.

Daniel Stephens14:09:37

👍 My bad, RTFM seems to apply! That said I'm still confused why (.toString ^CharSequence "\\") wouldn't compile, is that by choice or just isn't ever needed so shouldn't matter

andy.fingerhut14:09:48

I am not certain, but the type of "\\" is java.lang.String, not CharSequence, so it seems a little odd to try to type hint "\\" as something it isn't.

Daniel Stephens14:09:30

(.toString ^String "\\") fails as well fwiw

andy.fingerhut14:09:02

Do you get an error message of any kind?

Daniel Stephens14:09:21

Syntax error reading source at (REPL:1:24).
Metadata can only be applied to IMetas
Syntax error reading source at (REPL:1:25).
Unmatched delimiter: )

andy.fingerhut14:09:53

I see one "Metadata can only be applied to IMetas". In Clojure, metadata can be applied to collections and symbols, but very few, if any, other things. Strings are not on the list of things that metadata can be applied to.

andy.fingerhut14:09:42

Also on the list of things that metadata cannot be applied to: literal expressions of type string, number, char, boolean, keyword

andy.fingerhut14:09:28

If you have a name bound in a let or loop, or a parameter of a function, that can have metadata annotating it.

👍 4
Daniel Stephens14:09:44

ahh of course, so in the let example it's a symbol so can have meta attached, looks like I need to spend some more time reading

Daniel Stephens14:09:24

Thanks for your help 🙂

Michael11:09:30

could someone help me understand what's the use of :state under gen-class ? i have the following class:

(ns test.core
    (:gen-class
     :name Testing
     :extends javax.swing.JFrame
     :init init
     :constructors {[String] [String]})
    (:import (javax.swing JFrame)))
(defn -init [x]
  [[x] (ref {})])
i can create a JFrame object and set its title without problems:
test.core> (def f (Testing. "a"))
#'test.core/f
test.core> (.getTitle f)
"a"
test.core> (.setTitle f "b")
nil
test.core> (.getTitle f)
"b"
when/why should i bother with :state ?

cddr11:09:24

Is there any public examples of the use of the com.cognitect.aws/athena lib to run a query against athena?

cddr11:09:55

Ah scratch that. Seems like it might be easier to just use the jdbc client

roklenarcic12:09:46

So if I when I use deps, do aliases apply to transitive dependency also? I am trying to make a library that has an optional additional dependency that enables more configuration formats.

roklenarcic12:09:54

My guess is no

vlaaad12:09:44

no, but I created an issue to add support for similar functionality 🙂

roklenarcic12:09:44

Yeah... speaking of managed dependencies... in java being able to inherit maven configuration from Spring base and have library versions default to specific values in all projects was a game changer and it's a killer feature in larger organizations

mateus.henrique.brum13:09:51

Hey guys, I have a really naive question: How do I compose a hash like {:a <any function> :f <any function> ...} I have tried something like (merge-with (fn [a f] {a f }) [:a f] (reaptedly *)) But at the end I just have some similar to {:a 1 :f 1} How do I merge a index with a function as value?

vlaaad13:09:08

not sure I understand what you want (what's your input and desired output?), but zipmap comes to mind, is it what you want?

(zipmap [:a :b] (repeat *))
=> {:a * :b *}

mateus.henrique.brum13:09:07

that is exactly what I need, cheers ...

vlaaad13:09:19

@mbrum note that I used repeat, not repeatedly

dpsutton13:09:40

(take 2 (repeatedly *)) #_ =>(1 1)

👍 4
sova-soars-the-sora14:09:58

one of the most satisfying things about clojure is returning to the source code of a project i worked on 4 years ago and can still completely comprehend wth is going on.

henrik14:09:52

This is extremely satisfying, and something I have the pleasure to experience with Clojure, but not my ClojureScript projects. Frontend is horrible.

henrik14:09:52

A ton of irreducible complexity that is not related to the business problem, it’s just there by virtue of the solution sitting in an extremely hostile environment.

mateus.henrique.brum15:09:34

any one know a function like merge-with but that accept 3 or more args at on? like : (merge-with-xxx (fn [a b c] (......)) {:a 1} {:a 2} {:a 3})? or something similar as merge-with-key (merge-with-key (f val-in-result val-in-latter) maps) both kind of function suits me.. cheers...

jjttjj16:09:56

You could just do something like

(defn merge-with-xxx [f & maps]
  (reduce (partial merge-with f) maps))

(merge-with-xxx into {:a [1]} {:b [2]} {:a [3]})

;;{:a [1 3], :b [2]}

mateus.henrique.brum16:09:48

it still require 2 args in function .... I`d like the same behavior of merge-with but instead of accumulate in pairs, it should call a function with all values at once (3 values of 3 different maps with the same key at once ) ...

jjttjj16:09:36

so the merge function arity should always be exactly equal to the (variable) number of args passed after the function?

mateus.henrique.brum16:09:31

instead of 2, it should be and arity ..

jjttjj16:09:37

what happens if not every map has the same keys

jjttjj16:09:46

nils are passed to the function?

jjttjj16:09:37

or do you assume identical keys

mateus.henrique.brum16:09:03

{:a 1} {:a 2 :g 6} {:a 3} , will call once (f [a b c]) with 1,2,3 and ignore any call with g value

jjttjj16:09:25

doesn't seem like the best idea tbh 🙂 but maybe something like this:

(defn merge-with-xxx [f & maps]
  (let [ks (into #{} (mapcat keys maps))]
    (into {}
          (for [k ks
                :let [vs (map k maps)]
                :when (every? some? vs)]
            [k (apply f vs)]))))

(merge-with-xxx (fn [x y z]
                  [z x y])
                {:a 1} {:a 2 :g 6} {:a 3})
;;{:a [3 1 2]}

mateus.henrique.brum09:09:59

yep, this looks to work, I will brush up a bit.... 🙂

jjttjj16:09:07

people that use reloaded style workflows: how do you deal with your work-in-progress code which needs to use the main system? I have a system which I can fully reset but this means I cannot refer to the system at the top level, which is something I usually want to do in a scratch namespace of of stuff I'm working on. Is it as simple as just have your work-in-progress stuff outside of the tools.namespace.repl refresh dirs? Or are there other techniques I'm missing?

hiredman17:09:23

in general, I don't think code should ever use the whole system, it should be passed the parts it needs, same for work in progress code

rgm16:09:56

I’ll usually opt a scratch namespace out of tools namespace with disable-reload! and pluck what bits of the system I need out of the running system map at https://github.com/weavejester/reloaded.repl/blob/master/src/reloaded/repl.clj (integrant.repl has a similar internal value)

jjttjj16:09:49

Awesome, I think that should do

vemv16:09:39

No particular need disable-reload! btw, or to have the WIP ns outside the "refresh-dirs" You always can access the internal atom, right?

stijn17:09:56

@jjttjj if you're using mount, it will only start/stop the parts of the application state in the namespaces you've recompiled in the REPL (it's not the same as a full refresh, but for ongoing work this is rarely necessary I find). I really like that feature and until actually using it had no idea how it improves your workflow.

jumar19:09:13

Does anyone know how to dynamically set logging level with clojure.tools.logging, preferably when using log4j 2? I've tried something like this https://github.com/jumarko/clojure-experiments/blob/master/src/clojure_experiments/logging.clj#L39-L48 but it didn't work (even without slf4j dependencies on the classpath). I got to some "weird" state when it somehow worked but after restarting the REPL it's not reliably working anymore. The log level seems to be stuck at whatever level was set at startup from the config file

ataggart19:09:40

@jumar dynamic configuration will need to go through the underlying logging implementation, e.g., log4j.

ataggart19:09:20

IIRC, log4j can support reloading when the config file changes.

jumar04:09:27

@U5ZNLFCQ7 that's true but I do want to do this from code. Maybe even expose it as a "diagnostic feature" of an application.... Not sure I get this: > dynamic configuration will need to go through the underlying logging implementation, e.g., log4j. Isn't that what I'm doing or do you mean something else?

ataggart14:09:09

I mean that clojure.tools.logging provides a consistent interface to write to some underlying logging implementation (e.g., log4j, slf4j). It does not provide an interface to configure that underlying logging implementation; for that you'll need to code directly against whatever specific logging implementation you are using.

jumar15:09:01

Yeah, that's what I've done, I believe, with the code I shared. But it doesn't work properly for some reason

denik20:09:32

it seems like function metadata in clojure is stored on the var, not the function object

(defn- takes-args? [f]
  (->> f meta :arglists (some (comp pos? count)) boolean))

(defn foo [x])

(takes-args? #'foo)
;; => true

(takes-args? (fn [x]))
;; => false
Is there a way to find out whether a function takes arguments from the function itself?

Alex Miller (Clojure team)20:09:41

usually if you're asking that question, it's a good sign you have gone down the wrong path. what is your actual goal?

denik05:09:45

oh just saw this. I'm emulating a REPL using load-string that uses the last return value as the final value. If it's a thunk, I want to invoke it, otherwise it shall not be invoked since args would be missing.

lodin20:09:32

@denik You can use introspection to get a list of arities. (I don't remember how vararg is handled.)

denik21:09:55

how would I do that?

denik21:09:16

it should work for any function passed to takes-args?

lodin20:09:51

What are you using this for?

denik21:09:52

using it for my project zeal https://github.com/den1k/zeal

noisesmith21:09:54

doesn't this miss arities above the limit where you can only use applyTo?

noisesmith21:09:04

I think there's a limit like that...

noisesmith21:09:37

(cmd)user=> (.invoke + 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20)
210
(cmd)user=> (.invoke + 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21)
Execution error (ClassCastException) at java.lang.Class/cast (Class.java:3369).
Cannot cast java.lang.Long to [Ljava.lang.Object;
(cmd)user=> (.applyTo + '(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21))
231

ataggart00:09:57

user=> (arities +)
[0 1 2 :more]
Maybe I don't understand your point.

noisesmith00:09:14

oh - I'm surprised that invoke with 20 args works when the function arities only specify 0, 1, 2, and N args

noisesmith00:09:00

I was concerned about the mapping from invoke signatures to arity support, but clearly it's more complex than I thought

Alex Miller (Clojure team)02:09:35

Isn’t 20 one example of N?

denik05:09:35

perfect. this works

Alex Miller (Clojure team)21:09:28

just as a general handwavey thing, if you're trying to do something in Clojure and it's hard, you should take that as a sign

💯 12
noisesmith21:09:37

(cmd)user=> (.invoke + 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20)
210
(cmd)user=> (.invoke + 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21)
Execution error (ClassCastException) at java.lang.Class/cast (Class.java:3369).
Cannot cast java.lang.Long to [Ljava.lang.Object;
(cmd)user=> (.applyTo + '(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21))
231

kenny22:09:51

Why does the core.cache README examples use a fifo cache factory with a regular clojure map? That seems misleading given regular clojure maps do not have order guarantees, and a fifo cache is typically only used on data that has order.

hiredman22:09:17

what makes you say that?

hiredman22:09:15

first in first out is relative to the insertion order in the cache, it isn't via some ordering of elements of the cache

kenny22:09:40

Oh, that's how core.cached works?

hiredman22:09:50

that is how fifo caches work

kenny22:09:17

Sure, but I'm talking about the specific library here. From core.cache fifo docstring: > If the associative structure can guarantee ordering, then the said ordering will define the eventual eviction order. Otherwise, there are no guarantees for the eventual eviction ordering.

hiredman22:09:45

the initial map passed in is the "seed" of the cache

hiredman22:09:58

the entries in it need some insertion order

hiredman22:09:31

so the cache just uses the order you get back from calling seq on the seed

kenny22:09:12

If I'm following you correctly, that's exactly my point. Calling seq on a regular Clojure map does not guarantee order.

hiredman22:09:01

correct, and as the doc string suggests, if that doesn't work for you, you can seed the cache with some other associative structure that does have some order

hiredman22:09:41

there are a number of different clojure map implementations that preserve some kind of order, and I expect it also works on java.util.Maps, of which many preserve order as well

kenny22:09:58

Right - I get that but it seems like the example could be improved by using a structure that does preserve order.

dpsutton22:09:18

so the example of a fifo cache from core.cached is not fifo?

hiredman22:09:49

but you may also say "hey, this is the seed of the cache, everything as an arbitrary insertion of now, so just do whatever with them"

dpsutton22:09:12

for some arbitrary notion of first?

hiredman22:09:39

because everything you start with in the seed is tied for first, and it just picks a way to break the tie

dpsutton22:09:23

i'm confused. if you seed with an empty map, add 5 things, when it needs to evict it won't evict the first of the 5 things added after the seed but whichever reports as first when calling seq on the map

kenny22:09:25

Wait so order is preserved when inserting into a seed that does not preserve order?

hiredman22:09:37

the seed is not the cache

dpsutton22:09:56

ah. ok. i was mistaken. i thought it would evict on seq of the current state

kenny22:09:40

Oh I see. So basically if your cache seed does not guarantee order, eviction order is not guaranteed for the seed values. All values after that get evicted in a fifo fashion.

hiredman23:09:31

it's like, imagine there is a clock for the cache, and every operation on the cache advances the clock one tick, so the clock starts and time 0, the first operation becomes 1, etc, etc

hiredman23:09:44

because it is an immutable cache, and you can only add one item at a time, no two items will be added on the same clock tick, and at eviction time you always evict the item added at the lowest clock value

hiredman23:09:34

but, at the very beginning, the base items are all added at the same tick, so the clock value is the same for all of them

hiredman23:09:48

so given a tie when it is time to evict, what do you do?

hiredman23:09:39

so it is still fifo, it is just fifo, but some times things are added at the exact same time so "first" is an arbitrary member of that set of tied items

4
denik05:09:45

oh just saw this. I'm emulating a REPL using load-string that uses the last return value as the final value. If it's a thunk, I want to invoke it, otherwise it shall not be invoked since args would be missing.