Fork me on GitHub
#beginners
<
2017-12-01
>
derpocious02:12:48

totally random, but the word "predicate"... in clojure it means something that evaluates to either true or false. Does this have anything to do with the english grammar "subject and predicate of a sentence" meaning of the word predicate or is it totally coincidence that these use the same word?

noisesmith02:12:38

@derpocious > state, affirm, or assert (something) about the subject of a sentence or an argument of proposition. “a word that predicates something about its subject”

noisesmith02:12:13

a predicate asserts something about the argument, and that assertion is either true or false

vienas0014:12:16

how can I connect REPL to a working program

alexmiller16:12:39

you can use the socket server with a repl listener to add one by just adding command line parameters https://clojure.org/reference/repl_and_main#_launching_a_socket_server

ghsgd215:12:35

@vienas00 1) add [org.clojure/tools.nrepl "0.2.12"] to lein deps 2) embed repl into program => (use '[clojure.tools.nrepl.server :only (start-server stop-server)]) ; => nil => (defonce server (start-server :port 7888)) ; => #'user/server 3) $ lein repl :connect 127.0.0.1:7888 # use actual IP instead of 127.0.0.1 see https://github.com/clojure/tools.nrepl for more details please correct me if I'm wrong (haven't tested this yet)

ghsgd215:12:46

Hi! Encountered this code user=> (merge '^{:foo :bar} {:a 1 :b 2} {:b 3 :c 4}) {:a 1, :b 3, :c 4} Please suggest what ^{} construction means and why it's ignored by merge.

donaldball15:12:59

That is clojure metadata. Try calling meta on that value.

ghsgd216:12:00

Thank you @donaldball! It makes sense.

vienas0017:12:27

@ghsgd2 Yes I can see that, but how can I change a working program? and interact with it?

alexmiller17:12:30

require namespaces, invoke functions, update stateful entities

alexmiller17:12:41

all namespaces and vars are global and accessible

alexmiller17:12:35

or you can redefine function definitions from the repl, affecting the running program

seancorfield18:12:55

@vienas00 The way I work is that I start a REPL in my editor and as I write code in source files, I evaluate it into the REPL, so the program is a live, running, evolving thing all the time. So the "working program" is something I start from the REPL, via my editor, while developing.

seancorfield18:12:51

Once I have a program in production, I can still run it with a REPL server embedded in it -- for example using the Socket Server built into Clojure itself (starting the program with appropriate JVM arguments to tell Clojure to start the Socket Server) -- and then I can connect to it via a telnet session (for the Socket Server) or a full nREPL client (for an embedded nREPL Server) and I can treat it the same way as I do during development.

admay18:12:15

@seancorfield Can you give us some examples of things you’ve done on production applications via a live REPL?

noisesmith18:12:58

@admay one example I can give is trapping data in an exception handler, and then dumping that data to a file format I can use in a regression test via the repl

seancorfield18:12:58

@admay Mostly we use the live REPL on production for debugging: running functions that query data, so we can see what they are actually returning in based on our (large) production database, but we have used it to patch data in the databases -- because using Clojure to transform and update data (in MySQL and/or MongoDB) is usually easier than a raw command-line tool for the specific database. In addition, we sometimes redefine a function to have some extra debug output (logging via timbre, for example) when we're trying to track down a problem.

noisesmith18:12:00

@seancorfield ditto on timbre, not to mention it’s easy to change log levels and blacklist / whitelist namespaces from the repl which makes seeing the right logs much easier

noisesmith18:12:35

also it’s much easier to make a small function which queries the state of some stateful process than it is to hook that up with the right api and auth etc. etc.

seancorfield18:12:53

In very rare situations, we have applied a live patch -- a new definition of a function -- when it's been a critical bug that we don't want to do an entire new build for. We mostly only do that on our internal-facing apps (since our member-facing apps run on a cluster of servers and connecting to and updating each instance would often be more work than just running a build!).

noisesmith18:12:55

especially when the repl makes it easy to extract precisely the info I want out of that state

noisesmith18:12:08

the repl is nicer than any status query api I’d have the time/energy to make haha

seancorfield18:12:24

Agreed, yes, being able to temporarily dial up logging is very useful.

noisesmith18:12:26

so eg. there’s a namespace that keeps track of user quotas and running tasks - often repl code dereferencing the state atom is much more effective than attempting to query the state via an api then use that data in a ui

seancorfield18:12:55

But -- big caveat -- running code via a live REPL into your customer-facing production applications is of course fraught with danger so you need to be careful 😈

noisesmith18:12:02

it reduces friction to increasing info and reduces the cost of providing info we very rarely need

noisesmith18:12:19

yes, indeed - you do need to be careful

seancorfield18:12:43

We run our regular DB migrations all via Clojure so, for us, using Clojure to run DB queries -- or DB updates -- is a pretty natural way to work.

admay20:12:26

> fraught with danger This is what I’ve always worried about. My team has a few very new Clojure developers on it and I don’t want them to feel pressured into using something they aren’t 100% comfortable with. Those a great examples of how/why to use a REPL connection with a prod environment and I’m definitely going to start looking into incorporating it in my practices. Maybe starting with a REPL connected to our QA and DEV environments first and then moving to PROD when we’ve nailed down application safety.

admay20:12:38

Thanks @seancorfield and @noisesmith!

alexkeyes21:12:50

can someone please explain why (contains? [1 1 1 1 1] 4) evaluates true?

smith.adriane21:12:01

contains? works on associative types

smith.adriane21:12:20

vectors implement the associativity by mapping indexes to values

smith.adriane21:12:50

since it has a value at index 4, it returns true

smith.adriane21:12:07

> (contains? [1 1 1 1] 4)
false

admay21:12:29

@alexkeyes if you want to check if a vector contains a value, you can with some and an anonymous function like (some #(= 4 %) [1 1 1 1 1])

admay21:12:38

However, this won’t return true of false, it will return true or nil. Usually that won’t be a problem, but it’s worth noting I think

alexmiller21:12:25

note the link to Rich’s explanation at the end too

admay21:12:28

@alexmiller I know Rich isn’t a big fan of sequential lookup but is there any reason why there aren’t two functions for contains? like contains-key? and contains-value?

alexmiller21:12:49

contains? is effectively contains-key?

dpsutton21:12:27

(contains? {:a 1 :b 2} :a) => true

admay21:12:45

Well, literally it is. I’m just curious as to why no contains-value? really

alexmiller21:12:55

because contains-value? is sequential lookup

admay21:12:36

So it’s just, “We don’t think sequential lookup is good. We don’t want to encourage it because there are better ways. Here are the better ways, use these instead.”

alexmiller21:12:56

yes - if you need to look up a value, put it in a hashed set

dpsutton21:12:58

it's pretty simple to do if you like (contains? (set (vals {:a 1 :b 2})) 2) => true

alexmiller21:12:03

or as a key in a hashed map

admay21:12:18

So rather than (some #(= 4 %) [1 1 1 1 1]) you’d suggest (contains? (set [1 1 1 1 1] 4))

alexmiller21:12:24

I’d suggest not using [1 1 1 1 1]

alexmiller21:12:48

the point here is to choose the right data structure that supports the operations you will need in your program

alexmiller21:12:04

then you won’t find that you are missing an operation

alexkeyes21:12:09

thanks for the explanation everyone!

alexmiller21:12:18

most collection libraries in other languages define a set of ops and a set of colls and make everything work on everything. the problem with this approach is that it destroys your ability to reason about the performance of any particular operation as it may be fast on one collection but slow on another (in terms of O(1) vs O(log) vs O(n)).

admay21:12:50

@alexmiller Just shared that back and forth with my team, that’s a great bit of information. I very rarely see an emphasis on ‘how to choose the proper data structures’ in beginner documentation

alexmiller21:12:08

Clojure takes a different approach in defining a small set of collection operations based on traits. Not every collection implements every trait, but when they do they are expected to follow certain performance expectations.

alexmiller21:12:44

This allows you to reason about the expected performance of arbitrary code you see in the wild just from operations it uses.

alexmiller21:12:57

I wrote a lot more about this in Clojure Applied btw

derpocious22:12:14

hey all, I have some code that returns a promise object, but I want to evaluate it and get the result.

sundarj23:12:12

if you mean synchronously getting the value out of a promise, it's not possible with native js promises, but is with promesa promises

derpocious22:12:32

(def url "")

(js/fetch url
  (fn [data] 
    (println "got data "))
  (fn [error] 
    (println "data error")))

ghsgd222:12:46

hi, please suggest how to limit exception stacktrace length or turn off it altogether in tests i. e. $ lein test lein test test lein test :only test/issue ERROR in (issue) (AFn.java:429) expected: (= “Foo” (app/func "")) actual: clojure.lang.ArityException: Wrong number of args (1) passed to: app/func at clojure.lang.AFn.throwArity (AFn.java:429) clojure.lang.AFn.invoke (AFn.java:32) app$fn__260.invokeStatic (app.clj:40) app/fn (app_test.clj:39) Also clojure.test ignores test cases declaration order and runs them in random order.

derpocious22:12:27

in general, unit tests should not be written in a way that order matters

derpocious22:12:26

possibly pipe it to grep

ghsgd222:12:27

that's true but it's convenient for me to see results in the same order

derpocious22:12:40

lein test | grep Failed