Fork me on GitHub
#beginners
<
2017-08-28
>
donyorm05:08:52

So I keep getting this error:

Caused by java.lang.IllegalArgumentException
   No matching ctor found for class javafx.scene.image.Image
. But I know that class exists, what's going on?

bfabry06:08:40

@donyorm what's the line you're using to construct it look like? it's saying you don't have a constructor of that arity/type signature

donyorm10:08:17

Yeah that was it. I was pasing a vector when I meant to pass a vector of vectors, and that resulted in the constructor being passed a character instead of a string

donyorm06:08:56

oh, I thought it was where I imported it

donyorm06:08:00

I'll check that

bfabry06:08:26

it could be the import statement if the import statement is incorrect-enough syntax

yogidevbear06:08:16

Hi peeps. I'm doing some SQL experimentation. I'm successfully connecting to my DB and querying my data. If I print my data, I see the output, but when I use map on it to do things like group-by, I only see the the name of the stored result (e.g. #object[clojure.core$map$fn__4781 0xd76b3 "clojure.core$map$fn__4781@d76b3"]. If I wrap the map call in a print call, I see something like #object[clojure.core$map$fn__4781 0x7664aa clojure.core$map$fn__4781@7664aa]nil. How would I go about printing the output of the map?

yogidevbear06:08:49

(def initial-data [(jdbc/query db "SELECT c.companyID, c.companyName, d.departmentID, d.departmentName
                    FROM dbo.company c
                    INNER JOIN dbo.companyDepartment cd ON c.companyID = cd.companyID
                    INNER JOIN dbo.department d ON cd.departmentID = d.departmentID")])

yogidevbear06:08:00

(print initial-data) results in:

seancorfield06:08:43

query is eager by default. So initial-data is a vector of one element, the sequence of results from the query.

yogidevbear06:08:44

[({:companyid 1, :companyname Google, :departmentid 1, :departmentname DevOps} {:companyid 1, :companyname Google, :departmentid 2, :departmentname SysAdmin} {:companyid 1, :companyname Google, :departmentid 3, :departmentname Marketing} {:companyid 1, :companyname Google, :departmentid 4, :departmentname HR} {:companyid 2, :companyname Microsoft, :departmentid 1, :departmentname DevOps} {:companyid 2, :companyname Microsoft, :departmentid 2, :departmentname SysAdmin} {:companyid 2, :companyname Microsoft, :departmentid 3, :departmentname Marketing} {:companyid 2, :companyname Microsoft, :departmentid 4, :departmentname HR} {:companyid 3, :companyname Amazon, :departmentid 1, :departmentname DevOps} {:companyid 3, :companyname Amazon, :departmentid 2, :departmentname SysAdmin} {:companyid 3, :companyname Amazon, :departmentid 3, :departmentname Marketing} {:companyid 3, :companyname Amazon, :departmentid 4, :departmentname HR} {:companyid 4, :companyname Apple, :departmentid 1, :departmentname DevOps} {:companyid 4, :companyname Apple, :departmentid 2, :departmentname SysAdmin} {:companyid 4, :companyname Apple, :departmentid 3, :departmentname Marketing} {:companyid 4, :companyname Apple, :departmentid 4, :departmentname HR})]nil

yogidevbear06:08:03

I was noticing that and was wondering about it

seancorfield06:08:04

Bear in mind you have a vector of sequences there.

yogidevbear06:08:32

Here is an example of a map that I'm playing with: (map #(group-by (juxt :companyName :departmentName) :initial_data))

seancorfield06:08:00

(map f) returns a transducer

seancorfield06:08:38

You have a keyword :initial_data there which is not your defined symbol initial-data above.

seancorfield06:08:41

did you mean (map #(group-by (juxt :companyName :departmentName) %) initial-data) perhaps?

seancorfield06:08:34

(and I don't think you want the [ ... ] in the initial-data def in the first place -- query already returns a sequence)

yogidevbear06:08:35

Thanks Sean šŸ™‚

yogidevbear06:08:57

Let me test that out

seancorfield06:08:57

Normally you'd do something like (jdbc/query db ["select ..." params] {:result-set-fn #(group-by (juxt :companyName :departmentName) %)})

seancorfield06:08:31

(I think you only needed the map because you had a vector of sequences of hash maps instead of just a sequence of hash maps?)

yogidevbear06:08:19

Maaaaybe? šŸ˜†

yogidevbear07:08:08

Everything is behaving much better now

yogidevbear07:08:32

If we had Watney bot in here, I'd give you some karma šŸ™‚

sb16:08:23

(def atomka (atom {:wsmsg nil}))
(assoc @atomka :wsmsg "d") ; add "d" to wsmsg
(swap! atomka assoc :wsmsg (conj "d")) ; add "d" to wsmsg

but how could I conj in :wsmg?
I would like to get> ["c","d","g"] ; (:wsmsg atomka) 

sb16:08:19

My question is how could I add new value to > atomka :wsmsg?

donaldball16:08:17

The update fn is probably what youā€™re looking for

sb16:08:35

update-in + conj?

sb16:08:44

Ok, thanks I check it

abarylko16:08:10

update and update-in are different

abarylko16:08:20

update is for a regular key like (update key fn-that-takes-old-value-and-returns-a-new-one)

sb16:08:12

Ok, I understand! Thanks!!

abarylko16:08:14

(update-in [key1 key2 key3 ...] fn-to-update)

sb16:08:22

One more question

sb16:08:28

(swap! my-state update :wsmsg #(conj % 4))
(swap! my-state update-in [:wsmsg] #(conj % 4))

sb16:08:39

which is the best in this case, or the update-in is not correct?

sb16:08:52

both works

donaldball16:08:57

Theyā€™re functionally equivalent. update might be marginally faster.

donaldball17:08:19

I think you could do, fwiw, (swap! my-state update :wsmg conj 4) no need for the lambda

sb17:08:51

thanks for all the help!!

Lucas Barbosa20:08:52

Hi guys, Iā€™ve been studying Clojure for the past few weeks and Iā€™m starting to feel a little confident to try to build something more complex than solving exercises in http://4clojure.com Can someone please point me to some resources regarding the ā€œjumpā€ from toy examples to a ā€œrealā€ project? Stuff like separating concerns in namespaces, good practices, modeling complex domains, etc.? Thank you in advance!

seancorfield20:08:35

What books/tutorials (if any) have you read so far @lvbarbosa ?

seancorfield20:08:46

(and thanks for moving the conversation here!)

Lucas Barbosa20:08:50

@seancorfield Iā€™ve read Brave and True and Living Clojure (still completing the weekly training at the end of the book). Iā€™ve also tried to build a restful api using Clojure, but I feel that something is very wrong, like organization or separation of responsibilities (code here -> https://github.com/lvbarbosa/tasks/blob/master/src/tasks/api.clj).

Drew Verlee20:08:23

How do you write a test to check if a value is ā€œtruthyā€. Like i want something like (is (???? [:a :b])) to pass

Lucas Barbosa20:08:43

Iā€™m also reading the community style guide to improve the general code writing

seancorfield20:08:30

@drewverlee a value just is truthy or falsey -- (is [:a :b]) will pass

Drew Verlee20:08:00

@seancorfield should have guessed. Thanks

seancorfield20:08:32

@lvbarbosa Cool re: books, so maybe buy Clojure Applied for a more real-world next step?

seancorfield20:08:56

As for your code, I'd separate the persistence stuff into another namespace so the handlers aren't directly dealing with the database stuff.

seancorfield20:08:23

Are you familiar with MVC as a design pattern where the model and the controllers are separate?

noisesmith20:08:06

extrapolating from that, IMHO 80% of ā€œorganizationā€ and ā€œdomain modelingā€ in functional programming is solved if you push IO to the outside edges.

seancorfield20:08:35

(and at some point fairly soon you're probably going to want to learn about Component or something similar so you can package up separately the concerns of creating the pooled DB connection, starting the web server, etc)

noisesmith20:08:39

(where IO include channels, streams, files, network, and mutation of containers like atoms or refs)

seancorfield20:08:56

Yup, what @noisesmith said. It's hard with a simple CRUD example since pretty much all you're doing is "read something" and return it, "write something" and return status, but the more you can isolate the direct DB interactions from the rest of your app, the better.

Lucas Barbosa20:08:46

@seancorfield I just read the table of contents of Clojure Applied and it seems very likely this book will help me. Iā€™ll look into purchasing it asap! As for MVC, I have a good background in OOP and on the Java platform. I see that the code I wrote is completely coupled and messy šŸ˜…, but I still donā€™t really know what to do (due to my lack of experience and ignorance on the paradigm). My mind did not shift completely yet. I guess this will come slowly with time and reading other peopleā€™s programs. Thank you and @noisesmith for the comments, I really appreciate it!

noisesmith20:08:55

My inclination is that some things that would be considered ā€œwell factoredā€ in idiomatic java are a total coupled mess in clojure, and visa versa. With most of the differences having to do with side effects (clojure works better when you isolate them, java doesnā€™t usually care), data hiding (java needs it, clojure works better without it), and custom types (java uses them everywhere, good clojure code is much more conservative about creating new datatypes)

seancorfield20:08:16

If you use something like Component -- it'll be familiar as IoC/DI from Java (if you used Spring or something similar) -- and then you'll be passing components around to functions that need them, instead of relying on globals (as you are now for database connection stuff). The nice thing about that is that it then becomes very clear what dependencies your function have (only on their arguments, not their environment), and it becomes much easier to test them (because you don't have to mock a global environment -- you can test functions in isolation, passing them mock components if necessary).

noisesmith20:08:36

the combo of components providing stateful things as args, and driving your app with immutable data, means that creating tests that replicate runtime regressions can be very easy if you design things right

noisesmith20:08:49

eg. reifying important events as data you can store and replay

Lucas Barbosa20:08:08

Iā€™ve seen a talk on the official channel at YouTube where the guy that created Component talks about it, seems very interesting. Iā€™ll definitely give it a try. The DI facility is the aspect that I miss the most when trying to step out of Java EE. Iā€™m so used to annotating, configuring producers and letting the application container do the magic for me that it still feels bad to invoke resources by myself.

noisesmith20:08:06

clojure is definitely opinionated about explicit rather than implicit things in most cases, but you can still get the good parts of DI under that model

Lucas Barbosa20:08:13

@noisesmith testing is something that I love to do! I did not jump into it on Clojure yet, but is on the backlog for learning

noisesmith20:08:20

you just need to make sure you have well designed components and that you use them properly

noisesmith20:08:09

clojure testing is a lot simpler than people expect - most of what makes testing hard is implicit non-local state, and implicit context, and clojure is quite good about minimizing those things if you use it right

nes21:08:15

Iā€™m trying to make a macro that creates a dynamic var of a string, so far I have this:

(defmacro defvar [le-name]
  (let [n (name le-name)
        le-symbol (symbol (str "*" n "*"))]
    `(def ~le-symbol ^:dynamic
       (or (environ.core/env (keyword ~n)) ~n))))
but it ignores the ^:dynamic:
(macroexpand-1 '(defvar "a"))
(def *a* (clojure.core/or (environ.core/env (clojure.core/keyword "a")) "a"))
I tried using with-meta instead but iā€™m failing because i cant put metadata on the string itself. can some1 point me out?

noisesmith21:08:21

the metadata needs to be on the symbol, not the value

noisesmith21:08:39

and yes, use with-meta so that the metadata is on the form you emit, not the input to the form

noisesmith21:08:34

so it would look like

`(def (with-meta ~le-symbol {:dynamic true}) ...)

nes21:08:56

tyvm for clearing this out @noisesmith

seancorfield22:08:54

@lvbarbosa When you get around to testing, you can either use the built-in clojure.test or if you're used to a more BDD-style take a look at #expectations (disclaimer: I maintain that library!)