Fork me on GitHub
#clojure
<
2020-02-05
>
Eduardo Mata01:02:06

Does .contains works for searching if a string contains a words such as

(.contains "Hello Worlds!" "World")

emccue01:02:34

should, but when in clojure prefer clojure.string/contains?

emccue01:02:11

(:require [clojure.string :as string])

(string/contains? "Hello Worlds!" "World")

Eduardo Mata01:02:32

My repl seems to not recognize that functions

noisesmith01:02:10

when was string/contains? added? I don't see it in 1.10.1

Eduardo Mata01:02:40

Yeah I am using clj 1.10.1

noisesmith01:02:43

maybe you meant clojure.string/includes?

Eduardo Mata01:02:17

includes? can work

noisesmith01:02:44

@contact904 generally javadoc for a type will show you what should work, but clojure often has functions that are more convenient to use

seancorfield01:02:07

Also, clojure.string is supported in ClojureScript too so you can write portable Clojure/Script using clojure.string functions, whereas the Java interop only works in Clojure.

noisesmith01:02:41

that's true, the big issue with interop is losing portability

JAtkins01:02:35

What is the Clojure equivalent for Java's (byte) 255 => -1? (byte 255) returns an error.

noisesmith01:02:40

there's a whole family of those

user=> (apropos "unchecked-")
(clojure.core/*unchecked-math* clojure.core/unchecked-add clojure.core/unchecked-add-int clojure.core/unchecked-byte clojure.core/unchecked-char clojure.core/unchecked-dec clojure.core/unchecked-dec-int clojure.core/unchecked-divide-int clojure.core/unchecked-double clojure.core/unchecked-float clojure.core/unchecked-inc clojure.core/unchecked-inc-int clojure.core/unchecked-int clojure.core/unchecked-long clojure.core/unchecked-multiply clojure.core/unchecked-multiply-int clojure.core/unchecked-negate clojure.core/unchecked-negate-int clojure.core/unchecked-remainder-int clojure.core/unchecked-short clojure.core/unchecked-subtract clojure.core/unchecked-subtract-int)

emccue02:02:11

yeah my bad includes?

emccue04:02:35

(defn reduce-over-sql-statement
  "Reduces over the nodes in a sql statement from left to right.
  Will terminate early if the reducing function returns a
  (reduced ...) just like normal reduce."
  [root-sql-statement acc-zero reducing-fn]
  (loop [acc acc-zero
         statement-stack (list root-sql-statement)]
    (if (empty? statement-stack)
      acc
      (let [statement (first statement-stack)
            next-acc-value (reducing-fn acc statement)]
        (cond
          (reduced? next-acc-value)
          @next-acc-value

          (instance? SqlNodeList statement)
          (recur next-acc-value
                 (concat statement statement-stack))

          :else
          (recur next-acc-value
                 (rest statement-stack)))))))

emccue04:02:48

Is there a less manual way to do this?

emccue04:02:33

I don't particuarly understand IReduceInit, but it feels as though there is some way to just hook into the builtin reduce with a tad more logic

seancorfield04:02:17

@emccue Can you provide a bit more context around what you're trying to do?

emccue04:02:01

I am trying to parse sql scripts and extract the columns and tables that were written to and the ones that were read from

seancorfield04:02:26

I'm trying to understand your two recur cases -- you're reducing using acc and the top of the statement list in both cases, but if the first element is a SqlNodeList, you're concat'ing the first element to the front of the whole stack which includes that first element???

emccue04:02:42

...that was dumb

emccue04:02:05

yeah, should be a (concat statement (rest ...)))

seancorfield04:02:38

But then it will reduce on the sql node list and then... reduce on each element of that as well?

seancorfield04:02:55

(I'm assuming sql node list behaves like a Clojure list?)

emccue04:02:03

its an iterable, yeah

emccue04:02:47

I am translating this code because calling scalac from leiningen isn't supported and I need some basic parsing to be able to test the rest of what I am working on

emccue05:02:16

and this part here

emccue05:02:19

class Visitor extends SqlBasicVisitor[Unit]

emccue05:02:42

is a class which implements calcite's SqlVisitor interface

emccue05:02:03

which has a bunch of visit methods with different types of arguments, as visitors do

emccue05:02:25

and all SqlBasicVisitor does is auto loop through children of a list node

emccue05:02:49

but I can't actually use that from clojure because proxy isn't up to snuff

emccue05:02:35

and seperate the visitor thing would mandate a bit of local mutability with an atom to translate 1-1

seancorfield05:02:40

Posting that large a code fragment inline killed my Slack client. You should post a link to code that big 😞

emccue05:02:08

I did post a link

emccue05:02:13

to the superglue one

emccue05:02:20

your client must be configured wierdly

seancorfield05:02:21

Ah, yes, I removed the expansion of it now.

seancorfield05:02:34

It auto-expanded the link 😞

emccue05:02:47

I guess your client didn't know to slack off

seancorfield05:02:17

I don't see SqlNodeList anywhere in that file...?

emccue05:02:06

Nor do I and I am realizing I borked up

emccue05:02:44

I need to do this logic

emccue05:02:08

in my defense it is hard to keep Sql*** stuff straight

emccue05:02:29

...which is more involved since there isn't a straightforward way to remove the mutability

emccue05:02:52

since the actual tree traversing logic seems to be inside of the actual nodes

emccue05:02:15

and not the same in each one

seancorfield05:02:21

If you walk the tree of nodes, transforming each node into a pair of inputs and outputs, merging them as you go, you'll have no mutability.

seancorfield05:02:06

A multimethod would probably be the easiest way to handle the transformation?

seancorfield05:02:07

(since the default could produce [[] []] and you'd only have to implement transforms for the node types that actually have input/output components -- I bet the resulting Clojure code would be a lot shorter than that Scala code)

emccue06:02:55

Hypothetically, yeah

emccue06:02:20

but adapting the acceptCall wouldn't be trivial

emccue06:02:37

and also i don't think that strategy will really work out

emccue06:02:04

at least not that simply

emccue06:02:42

SELECT a.c FROM APPLES a LEFT JOIN BANANAS b WHERE b.id = c.id

emccue06:02:55

This is possibly not valid

emccue06:02:06

but definitely far from the gnarliest sql to be handled

emccue06:02:42

and maybe im not thinking it through enough right now

emccue06:02:36

its too late

hiredman06:02:35

Likely what you'll want is to write an evaluator for sql expressions, where the result is the set of selected columns (instead of a sql result set) which would let you do things like check that tables referenced in where clauses are defined in from clauses (the evaluator will build an environment and check that tables mentioned exist in the environment). https://en.m.wikipedia.org/wiki/Abstract_interpretation

kaosko07:02:05

(java interop) how do I instantiate a (non-static) inner class in clj? googling, only references I see are for instantiating static nested classes

andy.fingerhut07:02:54

I haven't done this recently, if at all, but often inner classes are named OuterClass$InnerClass, so perhaps something like (OuterClass$InnerClass. my constructor args here)

kaosko07:02:16

yes, that's the easy one for static nested classes

kaosko07:02:06

somehow, I need to refer to the outer-class instance when instantiate an actual, non-static inner class

kaosko08:02:23

ah, I was totally thrown off by Cursive. it flags this with incorrect ctor arity: (OuterClass$InnerClass. outer-instance) but it does work if you just run it

kaosko08:02:18

it's because the reference to the parent instance is implicit. what a complex language this Java is

grounded_sage09:02:45

Is there an idiom like side-effect! but for when you reference an external symbol inside a function.

dominicm09:02:34

What do you mean by external symbol?

grounded_sage10:02:56

I realised it would need to be on the actual symbol as well. Like say you have (defonce bucket-name "my-aws-bucket") and you use that throughout your functions in that ns. It would be nice to quickly see what isn’t passed to the function. Like @my-atom is usually a sign. I know my example is not that good because the top level function itself would be a side-effecting one due to aws.

grounded_sage10:02:47

It would make glancing over the functions to see how pure they are faster. Though we could just simply pass it in as a param I guess..

dominicm10:02:22

All symbols could be made a parameter 😉

👍 4
grounded_sage21:02:57

Actually the downside of that would be using a function defined in said namespace from another namespace. I’ll just keep it as is.. it would be nice to see at a glance what is coming from outside of the function. Though I guess there is no way because then it’s implying that that symbol is always used without being an explicit input.

dominicm21:02:06

You might enjoy playing with Dr Racket IDE

grounded_sage19:02:13

I’ll get to Racket one day 🙂

acron10:02:52

Does anyone have any experience of intercepting java.util.logging log writes? I would like all my logs to go via timbre and I am aware of libraries like slf4j-timbre, but iiuc I am dealing with java.util.logging, not SLF4J and I can't seem to find an equivalent library

jsyrjala10:02:03

There is a jul-to-slf4j, which will send everyting logged by java.util.logging to slf4j, and from there to what ever destination slf4j is configured to use

acron10:02:34

Ok, thanks, but no jul-timbre?

jsyrjala10:02:41

No idea, I have never used timbre

jsyrjala10:02:53

I guess you could try jul-to-slf4j and slf4j-timbre together? Something like this: jul -> slf4j -> timbre

acron11:02:15

Yeah I could, it's just...a lot of deps!

levitanong13:02:02

I’m trying to access a directory to get a list of files. Conventional knowledge suggests I use (-> ( "absolute/path/to/dir") (file-seq)). While this works normally in dev, it fails once uberjarred because the directory is moved as informed by the classpath. If it were just a file, I would’ve just used (io/resource "relative/path/to/file"), but if it’s a dir I get an exception complaining that the path does not lead to a file. Does anyone have any solution for this?

dominicm16:02:38

You can't list files from the classpath under normal circumstances

dominicm16:02:06

You might try resauce as a workaround for common classpaths, but it isn't general purpose

levitanong18:02:45

oof 😞 At least now i know that it isn’t possible. At least i have a workaround in mind.

levitanong18:02:14

Thanks for responding!

emccue14:02:28

Maybe something like this would work then

emccue14:02:41

produce the plan, then just scan through the plan

emccue14:02:50

at least for basic usage

emccue16:02:41

for now the ugly ducking wins

emccue16:02:47

can't reliably reverse the acceptCall logic otherwise

ghadi16:02:51

@emccue I have a lightning talk on this from a few years ago: https://www.youtube.com/watch?v=FjKnlzQfAPc

emccue16:02:04

seems like all i need to do is wrap what i have in an IReduceInit

emccue16:02:19

yep that worked

emccue16:02:33

be cooler if that were a protocol but c'est la vie

ghadi16:02:04

It already is a protocol

emccue16:02:57

All I see is the concrete interface

emccue16:02:07

which mandates a reify, not an extend-type

Alex Miller (Clojure team)17:02:30

you can extend CollReduce if you want a protocol

Alex Miller (Clojure team)17:02:44

IReduceInit is helpful if you are making a Java thing

Alex Miller (Clojure team)17:02:02

(which has no way to extend a protocol)

ghadi17:02:22

IReduceInit is also a better factoring of CollReduce, which has an extra arity without the "init" arg

ghadi17:02:48

for all intents and purposes you can treat reduce as an abstraction in Clojure

datran19:02:07

how do test fixtures compose? I've got a test with multiple fixtures and I don't understand how to call those fixtures with the test manually from the repl. Well, I do, but not multiple fixtures

noisesmith19:02:33

they are functions, you can use comp

noisesmith19:02:37

or nest them by hand

noisesmith19:02:01

there's also a function in clojure.test that runs a test with your fixtures

datran19:02:16

I can call one fixture from the repl by doing (foo-fixture mytest), and that works fine. But when I try (base-fixture (foo-fixture mytest)) it blows up because foo-fixture doesn't return the test fn

datran19:02:57

oh, I see compose-fixtures, let me try that

noisesmith19:02:00

oh, right - my bad clojure.test/compose-fixtures

noisesmith19:02:16

or you can just use clojure.test/test-var which uses your fixtures iirc

datran19:02:19

or join-fixtures

datran19:02:23

cool, join fixtures does exactly what I'm looking for. Thanks!

zane19:02:49

I'm curious what people's personal guidelines are when it comes to using for vs map.

p-himik19:02:18

They're interchangeable only in the simplest case. And in that case, I prefer for simply because there's no extra function.

4
isak19:02:47

I prefer for, since the collection comes before the 'body', which is more readable. It also lets you filter, assign variables, etc (`:let` and :when) without increasing nesting further.

4
andy.fingerhut21:02:35

I usually reach for map when the function is already named, or a one-liner, and I don't need the extra features of for like :let or :when, perhaps just from habit.

4
isak22:02:26

map is also nice sometimes because it lets you move to similar functions like mapv , map-indexed, keep, etc with a very small diff

Lone Ranger00:02:49

Just to give a diversity of viewpoints -- I avoid for . It's a personal aesthetic preference. I would rather use into with a transducer if I need something eager, eduction with a transducer if I need something lazy. I only choose for if it's the preferred convention of the project I'm working in.

richiardiandrea21:02:38

hi there! is there a way to see the keys for a record in the repl? my colleague @ivanjensen1 is interested in this 😄 for instance we would like to explore the properties of datascript.db.Datom

hiredman21:02:19

depends what you mean

hiredman21:02:47

user=> (defrecord Foo [a])
user.Foo
user=> (->Foo :a)
#user.Foo{:a :a}
user=> (keys (->Foo :a))
(:a)
user=>

richiardiandrea21:02:13

Oh right I could definitely do that 😄

hiredman21:02:59

the keys function words on records just like on a map

hiredman21:02:10

but you might only be interested in the declared keys that a record must have, not just what keys a particular record object has

hiredman21:02:55

the class generated by defrecord has a static method which you can call to get those

hiredman21:02:07

user=> (Foo/getBasis)
[a]
user=>

dpsutton21:02:55

(doc ->Foo) might help as well

richiardiandrea21:02:32

oh cool let me try that

richiardiandrea21:02:02

thank you folks this is helpful

Eduardo Mata21:02:59

Is there any consideration about security when I declare a function as private? It is private as it uses a connection to the DB. However, I wanna use this function outside the namespace. Should I wrap it with a public function?

bfabry21:02:54

private/public are pretty much just documentation. they don't have any security implications

Eduardo Mata21:02:16

oh, that is good to know

noisesmith21:02:06

this is my trick for checking keys of a record

user=> (defrecord Bar [a b c])
user.Bar
user=> (keys (map->Bar {}))
(:a :b :c)

Ivan Koz21:02:14

i was thinking of a way to find min\max elements and respective indices in a vector and came up with a such contraption, is there a better way?

(def v1 (vec (take 20 (distinct (repeatedly (partial rand-int 100))))))
=> [81 61 13 21 3 98 48 92 72 30 37 2 15 71 34 73 82 50 52 29]
(reduce (fn [acc [idx val :as e]]
            (let [update-fn (fn [v f]
                                (if (f val (peek v))
                                  [idx val]
                                  v))]
              (if (empty? acc)
                [e e]
                (-> acc
                    (update 0 update-fn <=)
                    (update 1 update-fn >=)))))
        [] (map-indexed vector v1))
=> [[11 2] [5 98]]

Michael J Dorian21:02:23

is the reason that you aren't doing (apply max v1) that you want the index as well?

Ivan Koz21:02:40

index aswell

noisesmith21:02:40

a literal vector would likely be easier to read than two chained updates

bfabry22:02:25

cljs.user=> (apply max-key second (map-indexed vector [12 78 31]))
[1 78]

4
hiredman22:02:50

that but, use reduce and run max-key and min-key at the same time

👍 4
🙏 4
Ivan Koz22:02:25

@doby162 wouldnt linear search increase complexity? I'm not very proficient with algorithms yet.

Ivan Koz22:02:09

thanks guys, that was really helpful, i was looking into max-key but wasn't able to figure it out

👍 4
Ivan Koz22:02:22

(reduce (fn [[min max :as acc] val]
            (if (empty? acc)
              [val val]
              [(min-key second min val) 
               (max-key second max val)]))
        [] (map-indexed vector v1))

👍 4