Fork me on GitHub
#beginners
<
2020-03-30
>
didibus02:03:08

You can even instrument in production, the only reason to not instrument is performance. So if you're not concerned about that, you could choose to have things instrumented all the time.

seancorfield02:03:14

Another reason: if you have a higher order function, instrumentation will perform generative testing...

Bill Phillips03:03:30

spec: How important is it to a n00b, really?

seancorfield04:03:04

@jings.bill Clojure existed for many years without it, but I think it's something that is important to learn.

porkostomus04:03:07

I resisted learning it for a couple of years, because I was too busy learning everything else. When I finally did, it seemed quite trivial to integrate into my mental model. (And very much worth it 🙂)

Bill Phillips04:03:11

What’re the payoffs? (From where I stand here, the #1 payoff seems to be… grokking error messages!)

seancorfield04:03:55

Having descriptions of your data structures. Being able to validate data against such descriptions. Being to able to generate examples of your data for testing.

seancorfield04:03:00

I wrote about our use of Spec at work last year https://corfield.org/blog/2019/09/13/using-spec/

Bill Phillips04:03:53

Interesting. Validating doesn’t seem… super interesting to me right now, except as it relates to another sort of basic question bumbling along in my head, which is… how best to represent data in Clojure When I started working on the back end of my little toy Clojure project, I jumped to thinking, “Okay, what sort of entities will I have in this, and what sort of data will they have?” And I looked in the Clojure toolbox and it seemed like Record gave me the sort of thing I was looking for now, the more I play around and look around the ecosystem, the more it seems like my choice is a little odd, and doesn’t actually achieve much. but I still think to myself: “how am I not going to drive myself insane with loosy goosy untyped hashmaps and lists flying around” (because I was scarred at an early age by making a right mess of things in python)

Frederik16:03:17

Exactly my feeling! Especially because in python I was walking away from passing dictionaries around towards using named tuples or data classes. Bit counter-intuitive that Clojure seems to be pushing you in exactly the opposite direction 🙂

Bill Phillips17:03:55

Right. But if you cross the line to using Record like a named tuple… you actually find that, unlike in Python, the Record doesn’t give you any new sugar. So why bother?

Bill Phillips04:03:22

and it seeeeems like it may be the case that spec is in fact a clojure-y answer to my concern here?

seancorfield04:03:53

Yeah, hash maps should be your go to.

Lee Adams04:03:56

Hello, I just tried to use the command line tools clj and clojure with a deps.edn file instead of what I have been using, which is Leiningen. My installed tools are missing clj and clojure doesn't seem to work. I get:

clojure -Sdeps
Execution error (FileNotFoundException) at .FileInputStream/open0 (FileInputStream.java:-2).
-Sdeps (No such file or directory)

Full report at:
/tmp/clojure-14940499844028101044.edn
I'm running Kali linux and lein seems to continue working just fine

seancorfield04:03:09

Records are for when you want type-based dispatch.

Lee Adams04:03:49

I also tried installing the tools using the script at http://clojure.org, but those seemed to suffer the same problem(s) and I don't see any further documentation about what I might be missing

seancorfield04:03:03

@beamjack Sounds like you might have some old, unofficial clojure script installed earlier?

Lee Adams04:03:39

I thought probably the package is not kept up to date or something like that, but surely the install script from the getting started guide should have worked?

seancorfield04:03:37

$ more `which clojure`
#!/usr/bin/env bash

# Version = 1.10.1.507

set -e

function join { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; }

# Extract opts
print_classpath=false
what does that command show for you?

Lee Adams04:03:47

oh I think I know what it is. I had installed via the script to a different prefix, and then tried to use clj which would not have used my prefix when invoking clojure facepalm it was invoking the packaged/incorrect clojure at /usr/bin/clojure

Lee Adams04:03:46

yep:

# more $(which clojure)
#!/bin/sh

if [ "x$CLASSPATH" = "x" ] ; then
	extra_classpath=""
else
	extra_classpath=":$CLASSPATH"
fi

while true ; do
	case "$1" in
		-cp | -classpath)
			extra_classpath=":$2"
			shift 2 ;;
		--)
			shift
			break ;;
		*)
			break ;;
	esac
done

if [ "x$1" = "x" -a "x`which rlwrap`" != "x" ] ; then
	rlwrap="rlwrap -r -c -C clojure -f /etc/rlwrap/clojure1.10 -b (){}[],^%
\$#@\"\";:''|\\"
fi

exec $rlwrap java -cp /usr/share/java/clojure-1.10.jar"$extra_classpath" clojur
e.main "[email protected]"

Bill Phillips04:03:06

Yeah. And it seems like type-based dispatch is a less frequently used tool in the toolbox than I’m used to from previous experience

Bill Phillips04:03:27

I haven’t needed it so far and I don’t think I will need it in this project. although we’ll see

seancorfield04:03:44

@jings.bill I tend to use records with protocols, if I want type-based dispatch and/or more performance than multi-methods.

seancorfield04:03:04

But otherwise hash maps are the go-to data structure for most things.

Bill Phillips04:03:00

Cool. And spec gives me the ability to document and enforce expectations for hash maps, as well as other higher level functionality built off those expectations

Bill Phillips04:03:26

That is in line with my impressions, but clarifies the whole ecosystem a bit. Thanks!

Brandon Olivier05:03:56

Does reitit offer a way to capture params that are multiple path parts?

Brandon Olivier05:03:07

Specifically, I want to capture a path param like

Brandon Olivier05:03:14

/path/{rest/of/the/path}

seancorfield05:03:09

I don't know what syntax reitit uses but in compojure that would just be /path/:stuff and then you'd have that all in stuff (and you can use regex to specify a pattern if you want)

Brandon Olivier05:03:09

I tried that, but reitit only supports a non-slashed string in that slot

Brandon Olivier05:03:34

Digging into the source, I think there's support for a /path/{*path} that'll make it available under path

Brandon Olivier05:03:16

@seancorfield I feel like you're always on here when I'm struggling through some after-work project and I just wanted to say thanks 🙂

seancorfield05:03:18

I'm on Pacific time so I'm the last one to go to bed in America! 🙂

seancorfield05:03:06

I've got to look at reitit some time. I see a lot of folks asking questions about it and I don't know the answers.

ikitommi05:03:13

the reitit route-syntax is defined here, for future reference: https://cljdoc.org/d/metosin/reitit/CURRENT/doc/basics/route-syntax

Chicão12:03:29

Hello guys. Do you have any recommendations for links for beginners to learning clojure ?

Chicão12:03:29

Hello guys. Do you have any recommendations for links for beginners to learning clojure ?

Jakob Durstberger12:03:40

Hey, I guess you mean for learning Clojure in general? I really enjoyed https://www.braveclojure.com

Chicão12:03:08

That's right. I'm started reading this book.

Ben Sless12:03:55

I also recommend doing the exercises in 4clojure in tandem

Ben Sless12:03:32

If you do all the Elementary and Easy it will be a good basis, all of Medium is good.

Jakob Durstberger12:03:33

I have also been using the mentored track at http://exercism.io and it was quite good

SoV412:03:35

Always have a REPL open to test commands when starting out. The interactive feedback loop from programming with a REPL is where lisps derive much of their effectiveness.

teodorlu13:03:25

... and learn to use that REPL by evaluating forms directly from your editor.

Gulli12:03:04

I have an if statement with three conditions, is there an easier way to have these three conditions evaluated than wrapping them with two 'and's?

Gulli12:03:10

No, I'm not evaluating on a sequence

Jakob Durstberger12:03:54

Every-pred is not just for sequences?

Jakob Durstberger12:03:51

user=> ((every-pred number? even?) 2)
true
user=> ((every-pred number? even?) 3)
false
user=> ((every-pred number? even?) "2")
false

jaihindhreddy12:03:23

and can take more than two things. (and nil false false nil 2) returns 2.

Jakob Durstberger12:03:51

@U883WCP5Z (and nil false false nil 2) returns nil and returns either the first falsey value it encounters or the last truthy one

jaihindhreddy12:03:13

Oops sorry the example was for or. And would look like this:

(and 1 2 3 4 5 5 nil)
returns nil

Gulli12:03:32

Ahh, thanks to both

teodorlu12:03:27

I realize that I might have misunderstood what you asked for, but if you want a "three way if", there's cond

(defn describe-apple-arity [n]
  (cond (= n 0) "Zero apples"
        (= n 1) "One apple"
        (= n 2) "Two apples"
        (< 2 n) "Many apples"
        :else   "Sorry, I don't know how to describe that"))

Gulli12:03:31

Hmmm... (every? true? coll) maybe

Audrius13:03:51

I am trying this code: (str (take 5 "1234")) and getting "1234" How to make the string to wrap around if taking more than it contains?

vlad_poh16:03:48

Howdy y'all what is best practice when dealing with side effecty things. Do try & catch ? For instance i'm using clj-http and i have try catch around each http call which doesn't feel right.

hiredman16:03:49

for clj-http you can, if you like, make it not throw exceptions for http statuses

hiredman16:03:18

(it will still throw for lower level things, dns, socket errors, etc)

vlad_poh16:03:32

interesting! that would meet my needs.

tws19:03:05

is there a convention (or doc?) which specifies how to name memoized and non-memoized versions of a fn?

tws19:03:38

i’ve seen foo and foo* often, but nobody mentions it in any style guides that I’ve found

andy.fingerhut19:03:55

foo and foo* I have often seen as foo being the normal published API, and foo* is some implementation function/macro that does most of the work.

andy.fingerhut19:03:16

I have not personally seen that naming convention used for memoized vs. non-memoized versions of a function, nor any other convention that relates those two things.

andy.fingerhut19:03:08

If the memoized version was something I wanted to call out as the unusual version of a function, because of the memory usage it can incur, I would probably use the name of the unmemorized function appended with -memo or similar.

tws19:03:15

that’s clearer, thx

jtth20:03:03

Hello! I asked this question over at Clojureverse https://clojureverse.org/t/library-stack-for-isomorphic-webapp-these-decisions-make-me-feel-at-sea/5651. I’m stuck in a kind of stack anxiety state, where Fulcro seems nearly overwhelming in its complexity and the suite of concepts needed to even navigate its example code (even with the amazing fulcro-rad-example), but I’m worried I might be setting myself up for needless complexity if I start with something like just rum, then add citrus for state management (regardless of whether I start with an SPA or server side stuff) and slowly build up and add libraries as needed. Eventually the thing I want to build will be a PWA, but I like the whole idea of progressive enhancement and an isomorphic development model. Any advice is appreciated, even if it’s just “go study fulcro more”.

fricze08:03:58

don’t be hard on yourself. Fulcro is great UI/state-management library, but it is NOT the way most of Clojure projects are written

fricze08:03:29

if you’re new to Clojure and to Fulcro it will be hard to learn, at this stage Fulcro may not be worth it

fricze08:03:40

Reagent/Re-frame or, mentioned by you, Rum/Citrus are good choices, that are less way complicated and have smaller learning curve

fricze08:03:33

DataScript is nice, but also, NOT a must-have. it’s great for querying data, simplifies data modeling if you know how to use it, but it’s slow when you have a lot of data. You can build big, nice, performant application without it

fricze08:03:41

I’d say, if you have to choose between Fulcro and Rum and you’re just learning, go with Rum. It’ll be way easier to have application running and learn step-by-step. When you use Fulcro you have to know it all, or it won’t make sense. It’s a long, interesting journey, but maybe for later. Rum is nice choice, you won’t be disappointed

fricze08:03:31

lastly, if you go with Rum, or Reagent, more people will be able to help you, because more people understand how those work and it’d be way easier to communicate with others about problems you approach, when building your app

jtth19:03:58

thanks so much for this reply! this is kind of what I think I’m going to do. I’m not new to clojure exactly; I’ve worked through all of yogthos’ Web Dev book so I’m familiar with reagent/reframe. I saw Fulcro as having most of the sort of nice-to-have affordances for what I want to build, but maybe starting simpler is the way to go.

jtth19:03:15

It’s one of those situations where if someone had taken me aside when I started building apps in Angular and said hey, learn redux or something like it before it all becomes an imperative mess, I might not have believed them until I found myself in said mess without the luxury to just refactor. So my real worry is that I’ll end up building my own Fulcro. But by then if that’s the problem, then there’s a really easy solution, I suppose.

fricze20:03:47

If you end up in a situation where you build your own Fulcro that’s gonna be really lovely problem to have 🙂 and if that happens to be the case, you’re gonna know why, exactly, you need Fulcro, so it should be easier to learn it

johnj20:03:01

AFAICT, a pwa doesn't need to be isomorphic or requries a spa, so if you remove those two your complexity decreases a lot.

johnj20:03:32

I wouldn't dismiss a RDBMS, datomic is nice but it assumes you are experienced and know what you are doing enough to avoid having corrupt data.

jtth20:03:37

I know it doesn’t have to be isomorphic, I just wish there was a kind of progressively-enhanced story for development. I mostly work on a game-like education app that’s an SPA/mobile app, so I don’t know much about the PWA story without it first being an SPA.

johnj20:03:57

both are still relational, so that's not a reason to prefer one over the other.

johnj20:03:50

well clojure[script] doesn't have anything to do with PWAs, so you can't get around not studying them first.

johnj20:03:10

I don't think there libs to abstract a PWA away for you in clojure.