Fork me on GitHub
#beginners
<
2016-05-06
>
seancorfield00:05:07

FWIW, clj-webdriver is a great, solid library and the maintainer is currently working on a major overhaul with a streamlined API.

seancorfield00:05:49

One of the key things about many Clojure libraries is that they’re rock solid, laser-focused, and they hardly need any maintenance.

seancorfield00:05:12

In addition, that stability makes them much safer to rely on for production use.

seancorfield00:05:22

@prokaktus: We’ve had Clojure in production for near five years now. It’s been so solid we’ve been able to run pre-release versions of it safely — in production — and we’ve had almost no problems with any of the upgrade releases over that time. We started with a prerelease of 1.3 and we’re on 1.8 now.

prokaktus01:05:48

@seancorfield: thanks a lot! I’m really appreciate your experience!

bwstearns01:05:47

@seancorfield: I didn't intend to malign clj-webdriver, I'm thinking of trying to use it for some testing automation soon. I actually almost suggested that clj libraries were qualitatively less in need of maintenance than other languages' libs, but went with suggesting that they needed fewer maintainers which I guess is a small difference in ways and a large one in others.

roberto01:05:54

is there a clojure way of converting an inputstream to bytes?

seancorfield01:05:14

@bwstearns: I didn’t take your comment as maligning the library, I just wanted to note that there’s a lot of (re-)design work being done (so it’s just not visible). We use it pretty heavily at World Singles.

seancorfield01:05:23

@roberto: Java interop is probably your best bet for that...

seancorfield01:05:42

@roberto: Looks like the easiest way is Apache Commons IO:

(! 1316)-> boot -d commons-io repl
Retrieving commons-io-2.5.jar from 
…
boot.user=> (import '( IOUtils))
org.apache.commons.io.IOUtils
boot.user=> (require '[ :as io])
nil
boot.user=> (def snow (io/input-stream "./drawing/images/white_flake.png"))
#'boot.user/snow
boot.user=> (def bb (IOUtils/toByteArray snow))
#'boot.user/bb
boot.user=> (count bb)
6732

seancorfield01:05:01

The dependency would be [commons-io "2.5"]

roberto01:05:06

cool, thank you

rcanepa02:05:43

Hi all, I am trying to understand how does require and import work under the hood. The following blog post was linked several times as a good starting point to learn about the topic https://blog.8thlight.com/colin-jones/2010/12/05/clojure-libs-and-namespaces-require-use-import-and-ns.html , but I can’t understand this paragraph:

rcanepa02:05:48

"One important detail here is that the initial require is necessary—without it, you’ll get a ClassNotFoundException. Defypes work identically, though their printed representation will of course vary. You can use the same vector notation as with Java classes, but here you’d specify a namespace rather than a Java package as the first element of the vector."

rcanepa02:05:03

And that paragraph is related to this piece of code:

rcanepa02:05:33

So, requiring a namespace “force” the compilation of it? and importing one does not?

seancorfield02:05:24

Requiring a namespace will cause the corresponding source file to be loaded and compiled (if it isn’t already loaded).

seancorfield02:05:50

Import just declares an alias for the class in the current namespace — so the class must already be loaded.

seancorfield02:05:16

As of Clojure 1.8, defrecord can have :load-ns true in it which will cause its defining namespace to be automatically loaded when you import the record’s class. I haven’t tried that (and I don’t know how it does it) but that’s what the docs say.

seancorfield02:05:49

I doubt that’s very common out in the wild tho’ since libraries tend to continue supporting older versions of Clojure for a while.

seancorfield02:05:24

(FWIW, I can’t get :load-ns true to work locally for me so I’m missing some subtlety of it)

rcanepa02:05:37

Yes, totally. Thanks @seancorfield ! … I wasn’t aware of :load-ns, I will try it too.

srihari10:05:56

Is there a way to conditionally require a namespace?

srihari10:05:02

I’m building a library foo where some functionality, say foo.database, is opt-in, and applications that need foo.database need to have clojure.java.jdbc in the classpath. Now, for applications that don’t need foo.database, I’d like to not even load/require the namespace, so that there’s no complaint of clojure.java.jdbc not being in the classpath.

srihari10:05:23

I currently have this:

(when (matches-some-condition?)
  (eval '(require 'foo.database))
  (eval '(foo.database/some-function)))

srihari10:05:08

But, I’m not happy with this. evaling feels like a smell here.

plexus11:05:04

The eval around the require line is not needed, as long as the code doesn't get there at runtime it won't cause a problem

plexus11:05:33

for the second line you can resolve the function dynamically at runtime

plexus11:05:49

(ns-resolve (find-ns 'foo.database) 'some-function)

plexus11:05:36

(let [f (ns-resolve (find-ns 'foo.database) 'some-function)]
  (f with args))

srihari11:05:55

plexus: ah, that makes sense.

srihari11:05:27

plexus: thanks!

plexus11:05:52

you're welcome simple_smile

giga14:05:50

Hello Clojurians simple_smile I’m struggling with IntelliJ and Cursive… I don’t get how to evaluate function from editor to the REPL interactively.

st14:05:07

There may be a better way, but send XXX to REPL in the REPL menu will allow you to play with function XXX in the REPL. Interested to learn alternatives BTW.

st14:05:02

you can also load file to REPL and switch REPL NS to current file

nkraft14:05:10

That's one thing I find annoying about IntelliJ: I have to add the REPL through "Edit Configurations" for every new project. In Emacs I can start a new project and the REPL is always right there.

st15:05:34

@nkraft: you shouldn’t need to go via “Edit configurations” each time. Don’t you have a green arrow (on the top right) ?

st15:05:16

ok, for a new project, you’re right!

nkraft15:05:25

I do, but the selections there disappear when I start a new project.

nkraft15:05:51

It's little things like that which keep me using Emacs and Vim.

giga15:05:17

There’s no such “thing” “SEND XXX to REPL" in my cursive key-binding. 1. SEND top from REPL 2. SEND form before caret to REPL. I can load file but I want to execute a function at a time…

st15:05:56

@giga: If you hover over a (defn XXX you should have access to send XXX ...

giga15:05:20

oops, thank you simple_smile

st15:05:29

@giga: you’re welcome (adding a new keymap for these actions is also useful)

giga15:05:51

Thank you for suggestion. I had heavy customized keymap, my kind of mix of IntelliJ and Emacs, but with Dvorak makes it hard to cope with IntelliJ…

giga15:05:00

*heavily

noisesmith15:05:23

@plexus: this does not need ns-resolve, and ns-resolve is often misused. ns-resolve is when you want to ask "what symbol would this resolve to when used in some other specific ns" - eg, in your repl (ns-resolve *ns* '+) should return clojure.core/+. You can just use resolve when you know the ns you are looking for eg. (resolve 'clojure.core/+)

giga16:05:33

I’m trying to write a tail-recursive function which takes two collections(not vector) and returns the collection of common elements (duplicates included)

marcmartin16:05:19

Which book do you guys recommend for picking up clojure? (with already experienced java experience)

roberto16:05:51

Living Clojure

giga17:05:32

Perhaps “(conj commons (first list-one)" should have worked but it seems it doesn’t ^^

agile_geek18:05:06

@giga: the if statements you have written are not nested and return nil on their 'else' portion

agile_geek18:05:26

i.e. (if (empty? list-one) commons) will return commons value if list-one is empty and nil if it's not empty but then the second if gets executed regardless of what the first if returns so if list-one was empty commons would be disgarded and you'd execute the second if regardless.

agile_geek18:05:39

if expressions work like this: (if (predicate) true false) where if you omit the false portion it returns nil

agile_geek18:05:41

Therefore you need to nest the two if expressions

agile_geek19:05:29

(if (empty? list-one) 
   commons ;; return this on true
   (if (some #(= (first list-one) %) list-two)
      (find-commons-tail (rest list-one)
                                        list-two
                                        (conj commons (first list-two)))
       ;; what do you want to return if you don't get a match? if it's nil then consider using when instead
    ))

byron-woodfork19:05:04

(defn do-some-thing [entity]
  (entity/save {:a 2}))
I'm attempting to solve a problem whereas I can pass in whatever entity to the above method and the action is performed on it. Is this possible in clojure?

agile_geek19:05:03

remember Clojure works by executing a function on data... there aren't really objects that encapsulate data and function.

byron-woodfork19:05:16

Some data that resides at the DB level. I want to be able to pass in different entities. They all have the same save method on them.

agile_geek19:05:31

so you could do (save entity)

agile_geek19:05:27

@byron-woodfork: how are you associating the save fn with the entity? defprotocol?

byron-woodfork19:05:39

Correction: The entity would be a namespace value.

byron-woodfork19:05:08

Sorry about the confusion

byron-woodfork19:05:20

The save function resides on the entities namespace

agile_geek19:05:32

so you would have to require the namespace and eval it dynamically

agile_geek19:05:18

assuming you are passing a different name space for each entity?

agile_geek19:05:50

There's a much simpler way of doing this though

agile_geek19:05:21

You could use either protocols or multi methods to dispatch on a type or key representing the entity with a different implementation for each entity for the save fn

byron-woodfork19:05:24

Ah, I gotcha. I knew of the multi method option already. I'll look into protocols as well.

agile_geek19:05:29

remember multi methods can dispatch on things other than type which is more powerful than pure OO polymorphism which is only by type.

byron-woodfork19:05:31

Just realized that as I was reading the docs on multimethods. Haha. Thanks again.

giga19:05:21

@agile_geek: thank you so much. It’s takes a time and practice to get use to Functional world when Java/Python point of view where return stops the function… It still returns nil and I think issue is with carrying a value. I want to keep all common items in “commons” and perhaps (conj commons (first list-two)) doesn’t do the job…

agile_geek19:05:59

@giga I think you are on the right lines. I am a reformed Java developer so I completely understand the 'return from end of s-expression' takes learning

giga19:05:18

@agile_geek: yeah, perhaps I should read more about common lisp and not just Clojure

agile_geek19:05:37

@giga: take a look at Structure and Interpretation of Computer Programs (the original MIT talks are on youtube and are funny if only for the clothes - I remember wearing similar and the hair cuts too). Also my friend Tommy Hall has converted some of the book to Clojure - http://www.sicpdistilled.com/

giga19:05:43

@agile_geek: wow, thank you for this resource. I glanced a few pages a year ago but never dived into.

nkraft20:05:48

I forgot about SICP Distilled. I saw that back when chapter 1 was barely done. It's shaping up nicely, though slowly. I wish that had been around when I was learning Clojure, as that's the book I used to learn Lisp and Scheme back in the day. simple_smile

agile_geek20:05:55

I think Tom has been busy in 'real' life so it's been on back burner.

giga20:05:47

@agile_geek: one more question - let's take this simple function as an example: `(defn tail [one two sum] (or (empty? one) (empty? two) sum (if (= (first one) (first two)) (tail (rest one) (rest two) (conj sum (first one))))))` how should I “call” it? the first example that comes in mind is this: (tail [1 2 3 4] [1 2] []) but I want to emphasize on the third argument. It’s just an empty vector but but but… I’m lost ^^ 1 new message since 10:52 PM Mark as read (esc)Mark as read Team Directory

agile_geek20:05:48

@giga your call is fine but that or is not what you intended.

agile_geek20:05:02

I've got to get off my train in 5 mins so I'm going to drop off internet but take a look at doc's and examples for or

giga20:05:00

@agile_geek: it’s ok, thank you simple_smile

jswart20:05:10

@giga what are you trying to do with that function? Are you trying to add the elements of one and two together one at a time and then return the result in the sum vector?

giga20:05:05

@jswart: I’ve named that foolishly, my apologies, I want to return a vector of intersected elements

jswart20:05:39

clojure.set/intersection ?

jswart20:05:09

boot.user=> (clojure.set/intersection (set [1 2 3]) (set [1 2])) #{1 2}

giga20:05:50

yep, I now that but I want to make it work using my own tail-recursive function

jswart20:05:06

so clojure doesn’t have tail recursion

jswart20:05:16

you will blow the stack on large functions

jswart20:05:21

you need to use loop/recur instead

jswart20:05:36

but I’ll add that anything that can be done with loop/recur can be done with reduce

jswart20:05:47

If this is for learning purposes I would try to figure it out with reduce

giga20:05:26

yep, just for learning purposes, but before I solve it via reduce, I’d like to complete this using “recur"

giga20:05:45

I’ve done it using loop, and next in the list in tail-recursion - "recur".

jswart20:05:29

so loop/recur is tail recursion in clojure. You don’t do tail recursion by using a recursively defined function by name.

jjfine20:05:18

@giga i'd overload the function so that you can call it like: (tail [1 2 3 4] [1 2])

(defn tail
([one two] (tail one two [])
([one two sum] ...same code you posted above...))

jjfine20:05:49

is that what you were asking about here: "but I want to emphasize on the third argument..."

jswart20:05:55

Yeah but that teaches two non-idiomatic things.

giga20:05:29

@jjfine: thank you, arity does the job simple_smile

jswart20:05:31

http://clojure.org/reference/special_forms#recur, and avoiding the urge to pass in an empty datastructure to be “filled” is a bit more idiomatic

jswart20:05:41

and what you are likely to see in code

jjfine20:05:53

are you saying my example should call recur instead of tail?

jswart20:05:59

Assuming you use loop with it. You example will work, but on functions that generate a lot of calls on the stack it will blow up. Instead you can use loop and recur to do the same thing but you get a couple benefits: compiler verification, and constant space usage.

giga20:05:45

"Note that recur is the only non-stack-consuming looping construct in Clojure. There is no tail-call optimization and the use of self-calls for looping of unknown bounds is discouraged. recur is functional and its use in tail-position is verified by the compiler.” extract from docs

agi_underground20:05:16

hi, i`m reading the "living clojure" and see this function - (def animal-print (map #(println %) animals)) ;; -> #'user/animal-print and printout - animal-print ;; mouse ;; :duck ;; :dodo ;; :lory ;; :eaglet ;; -> (nil nil nil nil nil) why here we have this nil`s? and when using "doall" before map, in result we have only (nil,nil,nil,nil), why it happens?

jjfine20:05:28

so the 3 arity one needs to change to use loop/recur, but the 2 arity one is ok since it's bounded to 1 self-call?

jswart20:05:29

those nils are the return type. Everything in clojure is an expression and has a value. The value of printing something is nil. So the REPL shows you that.

jswart20:05:40

println is a side-effect whose return value is nil to the repl

jswart20:05:24

try this @agi_underground change #(println %) to #(do (println %) %)

jswart20:05:27

what happens?

agi_underground20:05:54

yes, here output without nil`s, but after definition, symbol that we define equal (nil,nil,nil,nil)

agi_underground20:05:28

user=> (def animal-print (doall (map #( do (println %)) animals))) :mouse :cat :rabbit :eliphant #'user/animal-print user=> animal-print (nil nil nil nil) user=>

jswart20:05:13

yes because you set them to nil

jswart20:05:46

(map #( do (println %) %) animals))

jswart20:05:56

that should print the animals and you should see them as teh return value

jswart20:05:10

assuming you didn’t def them to nothing

jswart20:05:12

previously

jswart20:05:51

Basically in the REPL you can “print” and see stuff but the last line of output from running something is the return value of that expression.

jswart20:05:17

(let [x (+ 1 2)] (println x) x)

jswart20:05:25

and returns 3

jswart20:05:30

b/c that is the value of that expression

jswart20:05:30

If println were a function in another language its type would be public void println(object x)

jswart20:05:01

but (def add [x y] (+ x y)) would be public int add (int x, int y)

jswart20:05:13

Things inside ( return values.

Alex Miller (Clojure team)20:05:14

(well, println is variadic :)

jswart20:05:26

trying to take it easy simple_smile

agi_underground20:05:30

i think now i understand, i was want to define symbol with action(function), but really i`m define symbol with results of function work

jswart21:05:21

yes defn defines a function you will run later to get results

jswart21:05:34

def is a name associated to a value

jswart21:05:37

(def foo (+ 1 2)) binds foo to the VALUE of the expression (+ 1 2) so user> foo returns 3

agi_underground21:05:18

ok, thank you @jswart all this simple things, but maybe i`m little tired)

jswart21:05:24

(defn three [] (+ 1 2)) binds three to a function. When you call (three) it runs the function

jswart21:05:31

and gives you 3

jswart21:05:05

(defn three [] (+ 1 2)) is the same as (def three (fn [] (+ 1 2))