Fork me on GitHub
#beginners
<
2017-09-14
>
drewverlee12: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.

drewverlee14: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

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.

alexmiller17: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

😂😂😂