Fork me on GitHub
#clojure
<
2016-11-08
>
jimmy00:11:02

hi guys, is this the right place to ask about how to train new developer to use Clojure ?

seancorfield00:11:51

@nxqd Either here or #beginners depending on their background I guess...

jimmy00:11:34

@seancorfield I wonder how do you guys train new developer to learn clojure ? I find that most of them find the syntax is weird :)) , and they find other language ( like go ) much more productive ? I would love to find a good way to communicate and sell Clojure to them ? Where should I start ? ( like, writing the same language front end and backend, no more type and static type. clojure.spec ) ...

seancorfield01:11:42

Depending on what languages they already know, there are likely two things they’ll find “hard” about Clojure: 1) syntax — although this really is a minor issue as Clojure has very little syntax: it’s just slightly different to C-family languages 2) FP — no mutable state, no encapsulation (In the OOP sense), no “variables”, no traditional loops. The latter is usually the biggest stumbling block if they have only ever programmed in Java for example.

seancorfield01:11:51

My question would be: under what circumstances are you trying to train them? Is it because you want to switch your current company from Language X to Clojure? Is it because you’ve started using Clojure on your team and need to grow that team?

seancorfield01:11:17

Do your management want you to use Clojure? Or are you trying to persuade them?

jimmy01:11:21

Great answer. For now, I have an authority to build my own team ( of 3 for now ) , they are fluent in other imperative languages ( go, python, java ). And I would love to grow this team with Clojure. My approach at the moment is to let them get familiar with the language through clojurekoans, and listen to their feedback. Along with their learning, I will try to feed some good examples of why Clojure is lean and more productive than other language ( through simple example cljs, clojure, building simple API .. ). I find productive seems to be the most interesting thing they love about learning a new language.

rymndhng01:11:56

@seancorfield do you ask the team to use standard tools, i.e. everyone on IntelliJ, or everyone on Emacs for example?

jrheard01:11:26

@nxqd the thing that attracted me to clojure in the first place was the focus on simple programs that are easy to maintain because they’re mostly just pure functions

jrheard01:11:08

maintainability is super important IMO - i’ve seen codebases in python where the original programmers were very productive in the beginning, but development years down the line had slowed to a crawl because the codebase relied so much on inheritance + mutable state that it was very difficult to understand anything / confidently make changes to things

jimmy01:11:08

@jrheard good point. I will take note this one

jrheard01:11:24

i had to print a “MultiDomainMixin” class (and two other classes that used it) out and tape them to a wall and spend two weeks marking them up with a pen before i was able to make a change one time 🙂

seancorfield01:11:31

@rymndhng We “encourage” our team to all use standardized tooling as that makes pair programming easier but we don’t enforce anything specific. Everyone just happens to be on Emacs on the server side team 🙂

seancorfield01:11:53

Becoming productive with Clojure takes a while @nxqd because the functional idioms are so different to most “traditional” mainstream languages (certainly the case compared to Go, Python, and Java). Some folks adapt quicker than others.

seancorfield01:11:46

Clojure encourages you to think more deeply about your initial design / solution but we’ve generally found maintenance remains easier over time — we don’t suffer from the “big ball of mud” problem that @jrheard hints at with OOP / imperative code.

seancorfield01:11:37

That’s not to say we don’t sometimes decide to do some major refactoring but even that seems easier when you’re dealing with (mostly) pure functions rather than classes with their own mutable state.

shaun-mahood02:11:41

@nxqd: One of the biggest selling points for me was the ability to use Clojure on the back end and ClojureScript on the front end, and with Garden for CSS I have very little context switching now.

Shantanu Kumar06:11:56

Can anybody explain why this works? (let [{:qux :foo} {:foo 10 :bar 20}] qux) (returns 10, Clojure 1.8.0)

bfabry06:11:05

in 1.9 it's a syntax/spec error from the let macro

pseud09:11:42

Hey, would the community weigh in on their boot/lein preference and more importantly - some reasoned arguments as to why they favour what they do

sveri09:11:32

@pseud I still prefer leiningen for the sole reason that boot has issues that make it unusable on W 7 / 8. At least that was the state like 6 months ago: https://github.com/boot-clj/boot/issues?utf8=%E2%9C%93&amp;q=is%3Aissue%20is%3Aopen%20windows Also leiningen has not let me down so far and gives me everything I need and cursive has great support for it, whereas it is harder for cursive to support boot (I remember @cfleming saying that some time ago)

pseud09:11:22

@sveri thanks for your input 🙂

pseud09:11:39

The floor is still open, I’d love more input

cfleming09:11:31

@pseud: I develop Cursive, and it is definitely much harder to develop tooling for. That may only affect Cursive, though, since AFAIK it’s the only tool that needs to get much information from the build itself.

pseud09:11:04

@cfleming so would you say that boot support would, eventually, be able to surpass support for Leiningen ?

cfleming09:11:57

I doubt it. At best, it’ll be able to match it. Lein has its own problems WRT integration into tools like Cursive, but the support is pretty mature now.

achesnais10:11:36

@pseud lein allows you to get started writing your app directly, and provides a nice base structure if you’re not an expert, which is reason enough for me

mpenet10:11:05

lein just works, no reason to switch on my end. boot looks interesting but I didn't have a compelling reason to invest time in it so far

borkdude11:11:53

How does one redefine a defmethod at the REPL?

borkdude11:11:03

seems to not ‘just work'

dm311:11:39

@borkdude works for me if you just do a defmethod with the same key/selector

kah0ona11:11:10

@nxqd I can confirm this; I now have 3 fairly sizeable clojure/cljs apps in production. It's great not having to switch context! Once you work with it and you have one buildtool, one REPL, one flow, it just feels soooo much lighter. And then there is maintainability, as @seancorfield mentioned. I actually dare to refactor stuff. I remember back in the java days, and the occasional moments i have to go back to java, that i start programming much more functionally in the OO language that is java, just because it's so much easier to reason about. I remember Rich hickey also mentioning this 'at one point i was writing functional code in C++' i think he said

kah0ona11:11:16

immutability is really really an important concept

borkdude11:11:14

@dm3 Ah thanks, it appeared to be something else

kah0ona11:11:30

speaking of @borkdude: absolutely loved your tweet yesterday: 'REPL REPL, your state is a mess'

borkdude11:11:55

hehe. thanks

kah0ona11:11:13

it was extra funny because at the time I was actually listening to Bowie 😉

kah0ona11:11:21

now i can't hear that song anymore without thinking about that

witek11:11:16

Hi. What is the elegant way to check for first part of a key? I have k which is a key like :a/a or :b/a. I need a sexp which yields true if the first part is :a

witek11:11:55

Should I convert the key to a string and call startsWith?

dominicm11:11:06

namespace function

borkdude11:11:14

(namespace :foo/bar) ;;=> “foo”

seancorfield15:11:06

@pseud: check out my blog for a series of articles on why we switched from Leiningen to Boot at World Singles http://seancorfield.github.io

dpsutton15:11:39

I can't wait to read those this evening

dpsutton15:11:47

i'm interested in learning about boot

borkdude16:11:20

@dpsutton if you have a leiningen project you want to convert to boot: http://blog.michielborkent.nl/blog/2015/06/06/from-leiningen-to-boot/ (shameless plug)

dpsutton16:11:58

do you have the hacker news link by any chance?

dpsutton16:11:02

i love reading comments as well

dpsutton16:11:48

ah sorry. but thanks!

borkdude16:11:20

wasn’t there something against linking directly to hacker news?

roberto16:11:12

I’ve looked at boot also and haven’t had any compelling reason to try it out. I don’t see what benefits it offers and I haven’t hit a snag in lein that will force me to try out boot in anger.

dvorme17:11:23

@roberto : Some thoughts on Boot. I find that Boot helps me attain the ideal of hacking on live code more easily than Leiningen (my projects are almost entirely server-side, so lein figwheel doesn’t apply). I also find it much more flexible for builds across multiple projects. The flexibility means that once you depart from the well-trod path there is code to write. If you need the flexibility, this is great. If you don’t, you might find that Leiningen is easier—until the day you realize you need the flexibility. Hope this helps.

roberto17:11:20

yeah, it seems to me more like a power tool that the majority of us might never need

dvorme17:11:52

Until you do. 😉

pesterhazy17:11:14

I'm having trouble with clojure.java.jdbc performance. When using insert-multi!, inserting 1000 rows over a remote connection is very slow, almost as if the driver did a round-trip for each insert value.

pesterhazy17:11:31

that's on postgresql/AWS's RDS. Any ideas? (am I doing it wrong, @seancorfield?)

pesterhazy17:11:56

@albaker yeah that's what I expected (using a prepared statement)

Al Baker17:11:59

oops, I'm looking at the wrong one

Al Baker17:11:19

you were right it does do them one at a time, and postgres returns the row back

Al Baker17:11:21

for each one

seancorfield17:11:33

You'll want to use the other form of insert with the vectors of column values instead of maps, I think. I'm on my phone right now and can't check.

pesterhazy17:11:30

let me check

Al Baker17:11:09

ahhh:

When inserting a row as a list of column values, the result is the count of
  rows affected (1), if available (from getUpdateCount after executeBatch).

seancorfield17:11:30

If you provide maps, the assumption is they might not all be the same shape. If you provide column values, they have to be the same shape.

pesterhazy17:11:58

just tried it, it works

pesterhazy17:11:04

thanks @seancorfield, that was tremendously helpful

pesterhazy17:11:47

that wasn't obvious to me at all from the docstring

pesterhazy17:11:04

it makes sense when you think about it

seancorfield17:11:38

I've toyed with the idea of adding an option to convert the maps into the vector form (and throw an exception if they don't match). It would have to be an option.

pesterhazy17:11:38

but my expectation was that the two types of inputs are roughly equivalent

pesterhazy17:11:57

instead they have vastly different performance characteristics

seancorfield17:11:21

Feel free to create a JIRA issue with suggestions to improve the docstrings.

pesterhazy17:11:21

the vector form is 10x faster

pesterhazy17:11:31

I absolutely will!

dvorme17:11:02

@seancorfield Nice, useful blog! Thanks for posting the link earlier.

pesterhazy18:11:37

@seancorfield does this sound right?

The second style, specifying sequence-of-col-names and sequence-of-rows, can
  generate significantly more performant SQL statements, as all rows are
  guaranteed to contain identical columns.

timgilbert20:11:53

Hi all, got a question about destructuring and namespaced keys... I find this behavior a bit odd:

(let [{:keys [:user/id :company/id]} {:user/id 1 :company/id 2}] id)
=> 2

timgilbert20:11:19

Is there a good way to alias the two ids in the destructuring?

timgilbert20:11:54

Closest thing I can see is this, which works fine:

(let [{u :user/id c :company/id} {:user/id 1 :company/id 2}] [u c])
=> [1 2]
...but I'm wondering if there's a more succinct way to express this

timgilbert20:11:48

Actually, I guess I should say I find the first example "not immediately obvious" since if I think about it as sequential let-bindings it does make sense to me. Anyways, curious if anyone's found a good idiom for this kind of thing

pandeiro21:11:49

when using ring.adapter.jetty/run-jetty, what is the idiomatic way to set the default charset to utf-8?

mpenet21:11:06

it's a jvm flag: -Dfile.encoding=UTF-8, you can probably set this programmatically too

Alex Miller (Clojure team)21:11:54

@timgilbert: that's about the best option

mpenet21:11:02

ah charset might be something else actually

mpenet21:11:57

you can just set it with a ring middleware I guess

pandeiro21:11:01

@mpenet That does seem to override it; but I'd like it to work with ring.middleware.resource/wrap-resource

pandeiro21:11:14

So I assumed it would be best set somewhere in jetty

wei22:11:26

what’s get actually doing when you use it on a list?

(get '(a b c) 1)

wei22:11:29

I’d expect the behavior to be consistent with vector as an index lookup. I know that’s what nth is for, but just wondering what it’s actually doing

cschep22:11:42

it returns nil

cschep22:11:57

so i’m assuming it’s checking if the data structure is a map and since it isn’t returns nil?

cschep22:11:59

i’m not sure though.

jr22:11:24

user=> (.get '(1) 0)
1
user=> (get '(1) 0)
nil

jr22:11:28

that's.....surprising

cschep22:11:17

looks like it’s calling that under the hood

cschep22:11:10

checks for map, IPersistentSet, and.. if it’s a number and the coll is a string or an array

cschep22:11:16

returns null otherwise

cschep22:11:23

which.. lists aren’t those things? i guess? so it returns nil?

cschep22:11:34

but yeah jr that output is ..

cschep22:11:35

very confusing.

jr22:11:38

List isn't an array because it does not support random access I suppose

cschep22:11:50

oh yeah.. absolutely makes sense.

cschep22:11:10

maybe the .get call does some conv..ersions? or something?

jr22:11:27

.get calls nth on a PersistentList

cschep22:11:48

well there you go.

jr22:11:48

which avoids that call to get in clojure.lang.RT

Alex Miller (Clojure team)22:11:36

get is for indexed colls

Alex Miller (Clojure team)23:11:28

the results are undefined if you pass it something that is not an indexed coll

Alex Miller (Clojure team)23:11:28

When we have a spec on get, it would tell you this at invocation time (if instrumented)