Fork me on GitHub
#beginners
<
2017-09-14
>
Drew Verlee12:09:47

Is it recommended to name function params after their types? (m)ap, (v)ector, etc..? Like if there is a function (person/lookup …) defined as (defn lookup [???] …) would it make sense to have the param be name or m?

john13:09:09

for more generic code, I think it is idiomatic to use m for map and v for vector, etc. If this particular map has, for instance, only :first-name and :last-name keys, and the function will not be used in more generic settings, then calling it name could be more idiomatic. /my two cents

Jon13:09:29

I created a simple macro to write (f (+ 44 55) (+ 44 66)) as (verbosely! f (+ 44 55) (+ 44 66)), and

Jon13:09:42

then I get logs:

Calling: (f (+ 44 55) (+ 44 66))
With: 99 110
Returns: 209

Jon13:09:09

what tools do you use to debug your code?

ghadi14:09:00

I use a REPL and that's it

ghadi14:09:39

I make sure that the code I'm writing or using is amenable to REPL exploration

ghadi14:09:16

avoid mutable state, make sure things pass data and not objects, avoid long call chains A -> B -> C

Jon15:09:54

any video related? I'd like to see it in action

Jon15:09:12

not familiar with such tools actually, I barely used REPL for debugging before

Jon15:09:27

by the way, it's Clojure or ClojureScript?

grounded_sage14:09:56

Who here is interested in mob programming on open source together?

rcustodio14:09:39

What is mob programming?

grounded_sage14:09:23

One computer (one person driving the computer). Everyone else navigating, researching, discussing how the code should be.

grounded_sage14:09:07

I'm interested in giving it a go but don't know any clojure devs as I'm on the island of Australia where we are about the last country to adopt any decent tech or even get it.

Drew Verlee14:09:01

The morning paper talked about a pair programming Study. The outcome made it sound like pairing was a slight advantage in many scenarios. However, to me it hinted that it would have huge payoffs in longer projects where people would be more familiar with the entire project by having paired more often. Basically, if its foreseeable that you will be touching that system in the foreseeable future, you might as well be their for most of the building of it. Otherwise, you confine your team to silos and hope no one gets sick or needs help -_-.

grounded_sage14:09:53

@drewverlee sorry I didn't quite get what your conclusion was there

Drew Verlee14:09:36

@grounded_sage That pair programming and by extension mob programming, imo, is a valid approach. The study showed that solutions that resulted from the paired teams were half the code as the solo approaches. Which to me means a “mobbed” solution would be much less complex on average then a solo one. It also means the mob would understand the whole code base, which would show huge benefits when it came time for a refactor. I need to watch the video to comment on it specifically, which i should have before i commented.

grounded_sage14:09:01

Cool. Yea these are my conclusions as well. You also have the benefit of the team mentality. The best sports teams aren't the ones that assemble the best players. Instead it is the ones that play the best together.

grounded_sage15:09:19

Also just thinking at a higher perspective. You are always trying to write code for a future version of yourself or another person entirely. To a certain degree the more people you have contributing at the time of input. Then the more likely the code will be readable and understandable by others and your future self.

grounded_sage15:09:38

Which would reduce refactoring and chances of bugs. Significantly in my mind.

Drew Verlee15:09:58

Like most things, you can create “teams” but often times the borders dont make sense. Ops and Devs is a good example of a bad divide. Front and Back might be a good one, just because the goal might be significantly different and the contract very well defined. Its like building abstractions, if contract between two things has to change when one changes then maybe the belong “together”.

Drew Verlee15:09:28

Sorry, just explaining somethings to myself as were talking about them. Not trying to preach 🙂

grounded_sage15:09:21

Yea I got a bit lost there with what you said but I think I got what you were conveying

grounded_sage15:09:34

I like what is said in the talk. If you aren't learning or contributing to the team. Don't feel obliged to be there. The team should be dynamic and fluid.

grounded_sage15:09:08

Even if there is merely being present with the team. Not necessarily in a separate room.

grounded_sage15:09:26

I'm really interested in finding others who want to experiment with this approach. Perhaps by working on open source.

Zor15:09:58

hit me up

Zor15:09:47

only issue is the screensharing tho

Zor15:09:21

well I'm not available ATM for a peer session, but if you have the willingness to do the minimum viable amount of organization to make this happen, count me in

Zor15:09:34

would be neat to have some kind of twitch, but with https://www.wikiwand.com/en/NX_technology instead of awful video

Zor15:09:55

old school screensharing is SSH on the same box and use screen or tmux 🙂 but no IntelliJ or cursive 😛

Drew Verlee15:09:38

I’m very ready to jump into an open Source Project in Clojure. Im actively searching for a good fit for me. I have considered A) Something related to Onyx B) boot ported to node I would also be willing to try a mob pair programming approach.

Zor15:09:09

my "hack of the week" project is to reproduce http://httpbin.org in clojure. i aim to call it http://httpbis.org 🙂

Zor15:09:57

I could completely push what I have (some scaffolding and a bunch of routes) and well, if you're interested it's pretty easy to jump in I imagine

Zor15:09:26

how about some teamspeak for mob peering ?

Zor15:09:42

(fyi I'm not available right away, gotta work for the next couple hours

grounded_sage15:09:43

That's alright guys I have some things on over the next several days. But I am super stoked to have found some people keen on this. We shall all chat sometime soon about what time suits best for everyone. Yay!

Zor15:09:34

aaright, talk to you then :thumbsup:

Drew Verlee16:09:43

I'll take a look at the project @U716Q56R2

madstap16:09:27

I just wanted to jump in here and say that I'm also interested in participating in something like this

madstap16:09:20

Maybe it wouldn't be a bad idea to create a channel for this? #mob-programming or #pair-programming or something

Zor21:09:52

fresh souls ! 😋

Zor21:09:05

#mob-programming is open for business

grounded_sage22:09:25

@drewverlee Boot ported to Node sounds like an interesting project I could get behind.

Drew Verlee22:09:42

There is a Google summer of code for it. @grounded_sage , I'll link the doc when I find a minute.

vuuvi16:09:00

is there an easy way to compare two maps when one gets returned from a function and one is a regular map?

bfabry16:09:49

@alexkeyes in clojure maps (and most things) are simple data, so you can just compare them with the = function, regardless of where they came from

vuuvi16:09:11

@bfabry so the right kind of syntax to compare would be something like `(= (function-that-returns-a-map arg) (:crazy huge :map with :info in :it))?

bfabry16:09:08

yes! except the delimeters for a map are {} so it would be (= (map-returning-fn arg) {:map values :go here}) 🙂

bfabry16:09:27

you can also get a pretty reasonable diff using (clojure.data/diff first-map second-map)

vuuvi16:09:00

awesome thanks for the help!

vuuvi16:09:47

one more follow up question: the map I need to compare my function too is pretty large and unsightly, it’s valid to put it in a (def big-map {crazy huge :map with :info in :it}) right?

bfabry16:09:55

yup. that stores the map in a var named big-map and wherever you use that var clojure will replace it with the value stored

vuuvi16:09:12

okay awesome thanks for answering my questions! It’s great being able to have a place to ask questions like this I know are simple but I’m not 100% on.

bfabry16:09:55

no worries. btw if you're just starting out I'd recommend working through the "Clojure for the Brave and True" online/print book

vuuvi16:09:45

yep I have that sitting here on my desk. I’ve also gone through living clojure and honestly I have a bit of a preference for that since it provides examples and challenges on a per concept basis, instead of at the end of a chapter

bfabry16:09:09

nice. I've never actually read living clojure

dpsutton16:09:51

also, feel free to play around in the repl. try things out like (= {:a 1 :b2} {:a 1 :b 2}). the repl is a great place to explore and prod things and is a great separator from other languages that are more "compile and run main" types of languages

john16:09:09

this also get's folks up on the basics pretty quick: http://www.4clojure.com/

vuuvi16:09:09

breaking out of the ‘save then run’ mentality is definitely something I want to work on. It’s really cool how powerful the REPL is

vuuvi16:09:04

also, @john another cool point of living clojure is they have a series of daily 4clojure programming exercises to get done with a reference to each section the problem deals with

vuuvi16:09:34

do you guys have recommendations for actual classes I might be able to take, aside from reading books or writing code?

manutter5118:09:58

There’s also Eric Normand’s videos at https://purelyfunctional.tv/.

dpsutton16:09:50

well, writing code will be the most effective thing you can do. after that books. tbaldridge has really excellent videos if you are a video person

dpsutton16:09:20

at the conjs that happen every year (they are going to just one per year next year) there are classes for beginners

vuuvi16:09:31

okay all good

john16:09:48

There might be some other classes out there with a similar format. Keep tabs on the Cognitect team. Sometimes they give classes on various subjects at various locations.

Alex Miller (Clojure team)17:09:12

There will be an intro class before the conj taught by Carin Meier http://2017.clojure-conj.org/training/

vinai18:09:15

I'm building a bidi routes map. All works fine until I want to limit one of the routes to :get requests (according to https://github.com/juxt/bidi#guards) Here are variations that all work, but without the guard clause:

(defn- routes []
  ["/" {"" (-> start-page (tag :index))
        "login" (-> login-page (tag :login))}])

(defn- routes []
  ["/" {"" (-> start-page (tag :index))
        "login" {"" (-> login-page (tag :login))}}])

(defn- routes []
  ["/" [["" (-> start-page (tag :index))]
        ["login" (-> login-page (tag :login))]]])

(defn- routes []
  ["/" [["" (-> start-page (tag :index))]
        ["login" [["" (-> login-page (tag :login))]]]]])
Here are variations with a guard clause that I've tried but that DO NOT work:
(defn- routes []
  ["/" {"" (-> start-page (tag :index))
        "login" {:get (-> login-page (tag :login))}}])

(defn- routes []
  ["/" {"" (-> start-page (tag :index))
        "login" {:get {"" (-> login-page (tag :login))}}}])

(defn- routes []
  ["/" [["" (-> start-page (tag :index))]
        [:get [["login" (-> login-page (tag :login))]]]]])

(defn- routes []
  ["/" [["" (-> start-page (tag :index))]
        ["login" [[:get ["" (-> login-page (tag :login))]]]]]])
As far as I can see all of the above should actually work. I guess I'm only posting these to show I've tried 🙂 Finally I'd like to add that I'm using these routes in ClojureScript. Does someone have experience with bidi and can help me understand what I'm doing wrong?

kevinbheda19:09:39

Having hyphen in folder name gives error but when i rename test_utils to testutils it works

java.lang.Exception: namespace 'com.pay.boomerang.config' not found after loading '/com/pay/boomerang/config', compiling:(com/pay/test_utils/helpers.clj:1:1)
there has been a similar question posted here but no actual reason of the problem -> https://stackoverflow.com/questions/12718658/why-does-java-complain-that-namespace-is-not-found

seancorfield19:09:17

Answered in #clojure (it's best not to post a question in multiple channels, by the way).

manutter5119:09:08

There’s some implicit mapping that happens between namespace names and filesystem paths, so com.my.name-space in clojure maps to the file com/my/name_space.clj

manutter5119:09:34

It should be a dash in Clojure, and an underscore in the filesystem.

sb19:09:12

possible to use clojure.zip with matrix or how to create/manipulate matrix without repos?

sb19:09:03

(Hackerrank challenge)

vuuvi19:09:19

is there any way to read a line from an input stream without skipping it in the buffer?

noisesmith19:09:46

so you would call .mark, save the result, attempt to read a line, then call .reset passing the mark back in

noisesmith19:09:11

if you are reading by lines you should be using a BufferedReader already

vuuvi19:09:32

oh okay cool so I need to do a mark rdr and then call .reset and it’ll reset the position in the reader

noisesmith20:09:45

@alexkeyes I was slightly incorrect - there’s only one mark supported per BufferedReader

user=> (require '[ :as io])
nil
user=> (import ( StringReader))
java.io.StringReader
user=> (def rdr (io/reader (StringReader. "hello\nworld")))
#'user/rdr
user=> (.mark rdr 127)
nil
user=> (.readLine rdr)
"hello"
user=> (.reset rdr)
nil
user=> (.readLine rdr)
"hello"

vuuvi20:09:58

that’s fine I only need one

noisesmith20:09:51

for an alternate API there’s PushbackReader, where instead of mark and reset, you read and then unread

noisesmith20:09:59

but that doesn’t seem to have a simple readLine

john20:09:28

@alexkeyes Your situation may have unique requirements, but in general I would recommend getting away from the java interfaces ASAP by dumping all the data into a clojure datastructure ASAP, then cleaning the data afterwards, removing empty lines, whitespace, errata etc

john20:09:08

That way I keep most of my logic in clojure-land. Granted, some efficiency concerns will have you preferring the java interfaces sometimes.

vuuvi20:09:09

immediately after the bit where I am mucking about the program moves the input stream into clojure land

john20:09:43

Yeah, I figured

kevinbheda22:09:41

when i try to use refresh

(use '[clojure.tools.namespace.repl :only (refresh)])
(refresh)
'com.boomerang.hello' not found after loading '/com/boomerang/hello'
The hello.clj is basically
(ns com.boomerang.hello
  (:gen-class
    :extends  java.util.Arraylist))

bfabry22:09:30

I'm assuming seeing as you're using gen-class that you're aoting things? tools.namespace doesn't support aot'd stuff

kevinbheda22:09:06

@bfabry then how do i use gen-class in my project ?

bfabry22:09:16

you can still use it, it just won't play nicely with tools.namespace

bfabry22:09:39

so you'll need to be careful about source paths and build steps

bfabry22:09:57

personally I just wouldn't use it, I've always found it a massive pain

seancorfield22:09:54

@kevinbheda I would only use :gen-class if you want to produce .class files for direct consumption by non-Clojure JVM languages. AOT in general is a giant pain and has all sorts of caveats. It's very rarely needed but unfortunately it seems to have become the default recommendation for apps written in Clojure 😞

seancorfield22:09:50

We don't use :gen-class or AOT for anything at all at work.

kevinbheda23:09:00

@seancorfield the problem want to use java grpc . I cant do it without gen-class example here https://github.com/kishiguro/grpc-clj/blob/master/src/grpc_clj/server.clj

seancorfield23:09:45

I suspect you could work with Java gRPC without AOT but you couldn't use that library. I've gone down the :gen-class path with Clojure code several times (early on) and nearly always regretted it.

seancorfield23:09:37

(I don't know enough about gRPC to offer guidance but if I were attempting that, I'd explore alternatives first and only resort to :gen-class if I couldn't find a "better" way)

seancorfield22:09:02

We build uberjars without it, and then specify the entry point when starting the JAR: java -jar path/to/the.jar -m entry.point and that runs entry.point/-main.

seancorfield22:09:35

(this leverages the clojure.main namespace as the declared :main when building the uberjar)

noisesmith23:09:57

@seancorfield what do you use as a runner (I ask because the only reason I use AOT is so that jsvc knows how to run my app)

seancorfield23:09:09

We have an init.d script (and it configures JVM options etc based on the service being started -- and accounts for a couple of our older processes being run directly via Boot instead of as uberjars).

bfabry23:09:10

we use AOT on uberjar but not in dev. compile time turned out to be significant performance wise

seancorfield23:09:43

Looking at the jsvc docs, it seems you could tell it clojure.main was the class to run and then provide -m entry.point as command line arguments?

bfabry23:09:20

in places where we need a defined java class for a java process to pick up we write a java shim over aot+gen-class

seancorfield23:09:25

Oh, I see it expects a Daemon class?

noisesmith23:09:21

@seancorfield yeah, and I have a small shim that implements Daemon then uses require / resolve at runtime to run our real code, that way we avoid many of the aot problems (the namespace we aot has no logic beyond the require / resolve so I don’t need to mess with it during dev)

noisesmith23:09:05

since aot is contagious it would otherwise spread to all our other namespaces, but since it only uses require inside a function at runtime, the contagion does not spread

noisesmith23:09:44

maybe we could get all the things we need from init.d though - that would certainly be simpler if so

rcustodio23:09:11

A simple beginner question... aot is bad?

rcustodio23:09:15

For production

rcustodio23:09:58

If yes... could you explain the reason please

bfabry23:09:29

aot is a tool that is useful in a small number of scenarios. it is a tool with quite sharp edges and poky bits

noisesmith23:09:33

there are things that can go wrong in aot code that won’t affect code that isn’t aot compiled

noisesmith23:09:54

so if it’s possible to avoid it, you gain a reduction of complexity, and fewer corner cases to worry about

seancorfield23:09:46

TBH, my biggest beef with AOT is the contagion. A JIRA issue has been open for years about that I believe...

noisesmith23:09:54

in return for that trouble, aot gives you… code that java code can run without using clojure.java.api.Clojure - which - that’s a benefit, but a small one

bfabry23:09:59

it also gives you code that loads much quicker when you :require it. which is useful for.... people whose code is executed by some sort of distributed service and that's about it

rcustodio23:09:13

So, if I'm developing a library, aot would be a benefit

noisesmith23:09:26

never use aot for libraries, that breaks things all over the place

rcustodio23:09:44

Type ahead makes difference on aot?

noisesmith23:09:49

because it forces all your consumers to use the exact versions you used of every dep you use

rcustodio23:09:22

Sorry... typehint

bfabry23:09:22

type hints and aot are orthogonal

rcustodio23:09:26

I'm still a little lost... it make any difference in performance? Production that is longrun

noisesmith23:09:45

it is a small change to startup time, no change in runtime performance

noisesmith23:09:54

clojure is always a compiler, it doesn’t have an interpreted mode

bfabry23:09:09

it makes a difference in the performance of code loading, which matters to very few people. for those it does matter to they can always AOT the code they consume

noisesmith23:09:41

yeah - usually it’s good to avoid AOT, but if you need it, it’s better to do it at the app level, doing it in a lib just causes problems

rcustodio23:09:25

If you are developing a desktop app, that maybe needs a fast startup, so use it, otherwise, server (Back) apps you don't need it, its better to avoid it then

noisesmith23:09:55

yeah, I could see aot compiling a desktop app if you are delivering a jar

bfabry23:09:12

it wouldn't make enough of a difference to bother with a desktop app, because it only starts the process once, not enough cost. it makes sense in my particular case because the process gets started many hundreds of thousands of times

noisesmith23:09:39

there’s also cases where you really do need some java thing to be able to call your code, and the thing calling it is not flexible enough to use clojure.java.api.Clojure to do it, and there’s use for AOT there too

rcustodio23:09:33

I see... I'm understanding a little better... but I didn't understood about the typehint.. I don't know what orthogonal means (the translation is no good)

bfabry23:09:59

just a pointlessly fancy was of saying "unrelated"

noisesmith23:09:02

they don’t have anything to do with one another

rcustodio23:09:34

I see.. typehint helps in runtime performance, when interop with java, right?

rcustodio23:09:43

Even when we don't use aot

noisesmith23:09:48

right, it helps the clojure compiler emit better code

rcustodio23:09:06

I see, thanks

noisesmith23:09:10

whether you use aot or not, clojure still emits the same code (except gen-class which is aot only)

noisesmith23:09:26

the type hints do the same thing in code where you don’t have aot

rcustodio23:09:42

I see... thanks

rcustodio23:09:19

Só aot is recommended just if you use the clojure api, otherwise avoid it

noisesmith23:09:48

it’s for when you are using java to call clojure code, and the java code can’t use the clojure.java.api.Clojure class

rcustodio23:09:24

Okey, thanks

seancorfield23:09:18

TL;DR: AOT Bad! 😆

rcustodio23:09:46

😂😂😂