Fork me on GitHub
#beginners
<
2023-01-16
>
noob.clj00:01:32

A sort of dumb question, but how do you guys fluently type clojure program? Thing I struggle with is thinking everything from the start. Eg: I have to write a method to parse a log-string and extract message from it. So Input: "[ERROR]: Invalid operation" and Output: "Invalid operation". Now the way I think is I need to split first so I’ll write

(str/split message ":")
Then I’ll have to remove first so I’ll move cursor to start and I’ll type (rest) now the editor will close the bracket, so I’ll delete the closing bracket and find a place to put it so:
(rest (str/split message ":")
Now I’ll realize there might be : in the log message so I might join them back with :. So I’ll do the same song and dance and fight the editor delete the closing ) and write code below:
(str/join ":" (rest (str/split "[ERROR]: Invalid: operation" #":")))
Now I’ll realize that I should trim it so again move cursor, fight with editor, find place to put ) and finally:
(str/trim (str/join ":" (rest (str/split "[ERROR]: Invalid: operation" #":"))))
I sort of build the logic from inside out. This was a fairly simple method, but if method is bit complex it gets quite frustrating. Do you guys try to think the complete logic and type in one go, or there is a better approach which I am missing 😞.

seancorfield00:01:15

For something like that, I'd probably turn to regex... Clojure exposes all of Java's regex functionality in an idiomatic way.

seancorfield00:01:13

(str/replace input #"^[^:]+: " "") might be reasonable to just remove the leading text, up to and including the : characters?

noob.clj00:01:25

Fair, I was mostly trying to learn Clojure so decided to implement the logic in clojure.

seancorfield00:01:18

That feels like imperative/iterative thinking -- part of being fluent in Clojure is trying to work at a higher level: working at the whole collection (or whole string) level instead of at the element (or character) level.

seancorfield00:01:50

Depending on your background, that can take time since you may need to "unlearn" a bunch of habits from other languages...

noob.clj00:01:18

True, have been using Java and similar languages for over 10 years.

seancorfield00:01:06

That's a lot of "bad" habits to unlearn 🙂 If it's any consolation, I did Java and similar for over ten years too before coming to Clojure back in 2010.

seancorfield00:01:31

(and before Java I did over a decade of C++/C)

noob.clj00:01:22

Yup, I guess I’ve to push through the discomfort of feeling of starting from scratch again. Thanks for suggestions though 🙂 FWIW I think using -> in this method is making things more readable.

seancorfield00:01:57

Yeah, coming from a lot of OOP to FP, it really feels like being a complete beginner all over again...

2
👍 2
skylize01:01:32

Sidestepping your methodology for the particular example, I often build things from the inside out just like that. To help with this, the popular editors should offer both automatic parentheses balancing and Paredit ( "strucural editing" ). You should not try to swallow all of Paredit in one go, but picking up useful commands here and there over time will definitely pay off. A good straightforward place to start is with Slurp and Barf, which will move expressions into and out of parentheses without having to add/delete parens or copy/paste any code. So at this step ( representing the cursor with | ) ...

(rest|)(str/split message ":")
... instead of deleting the closing paren, I would type the hotkey for Slurp Forward, which slurps the next form into the current one...
(rest |(str/split message ":"))
... leaving everything still balanced. If I do not already know an appropriate Paredit command, I am more likely to cut/paste intact forms than to try fighting with the auto paren balancing. When I first started, it was a regular occurrence (still occasionally) for me to put the cursor in an empty space above a function and just re-type it from scratch because of some missing/extra paren I could not find. 🙈 Now I often type small-ish code blocks right into this chat, just counting backward through the open parens to see how many need to be closed. So I would say it gets easier.

didibus01:01:04

What editor are you using?

skylize01:01:01

Me? VS Code.

noob.clj01:01:12

Yup, same. VSCode with Calva

noob.clj01:01:34

@U90R0EPHA slurp is really neat trick 🙂 thanks a lot for that.

skylize01:01:42

If not mistaken, Paredit originated in Emacs for Common Lisp.

didibus01:01:47

In my Emacs setup, it looks like this:

skylize01:01:36

@U0K064KQV I did it that way before I learned to Slurp.

skylize01:01:34

@U04JZS3AC59 You're welcome. Slurp can also go backward instead of forward, and Barf does the inverse, spitting the expression closest to the containing paren out of the front or back of the form.

skylize01:01:29

Once Slurp and Barf are getting into your muscle-memory, go look at https://calva.io/paredit/ to find something else that looks promising to your workflow. (After slurp/barf, my next step would probably be some navigation commands, but you find your own path.)

didibus02:01:47

Never got used to slurp/barf, went back to just backward/forward/up/down/raise sexp instead. Feels I'm faster with those and they are more reliable.

didibus02:01:02

You can also do this:

didibus02:01:51

The slurping seems slower to me, but also I don't like that it temporarily means I don't have the parenthesis the way they are meant to. But YMMV, the point is there are many options.

didibus02:01:19

If it wasn't obious, in none of those examples did I use the mouse

skylize02:01:01

> Feels I'm faster with those and they are more reliable. Fair enough. I got an extra boost on Slurp/`Barf` because, at the time I learned it, I was getting way more mileage from Slurp Backward than would be normal because of writing experimental code that would typically end up in either -> or comp in the wild.

(some-fn)|
(some-fn)(some-val|)
((some-fn) some-val|)
Slurp Backward much more unnatural to replicate that Slurp Form with other methods.

skylize02:01:47

> You can also do this: editor-flow2.gif Not sure what command you are using here, but the behavior is exactly the same as slurping; except you are doing extra keystrokes to move the cursor the next contained form before doing what amounts to a Slurp.

didibus02:01:42

I'm using TAB. It's more like parinfer, it just aligns the parenthesis with the spacing. It's called Lisp indent and List dedent (the opposite).

skylize02:01:08

Sorry I misread it.

didibus02:01:58

You're right, it behaves a bit like slurp forward and barf forward I guess. Never really thought about it too much haha. But it only works on independent lines

skylize02:01:19

Not sure exact logic of what you are showing, but the result is still the same steps as Slurp, but Slurp use fewer keystrokes and less precision of cursor placement. You are going to the form you want to move and somehow pushing it backward into the target, while Slurp lets you just pull it in from where your cursor already is, inside the target.

didibus02:01:43

I'm just doing TAB or SHIFT-TAB

skylize02:01:41

No idea what command Tab or Shift-Tab does in your setup. In Calva neither of those keys would have any effect on paren balancing by default.

noob.clj02:01:55

Yup I think that luxury is limited to emacs 😞

didibus02:01:00

Don't think it exists in VSCode.

didibus02:01:11

It's called adjust-parens mode in Emacs

skylize02:01:01

It reminds me of Parinfer.

skylize02:01:56

I would absolutely hate it if Tab affected paren balancing.

didibus02:01:12

Ya, it's kind of like a less intrusive Pareinfer. Pareinfer indents based on the parenthesis, so you type the parenthesis and it indents. This does the opposite, you indent or dedent and it fixes the parenthesis.

didibus02:01:50

Hum, no I got that wrong. Pareinfer fixes the parenthesis based on indentation as well, sorry, but this only does it for explicit indent and dedent calls, while pareinfer is always doing it even if you space, erase, etc.

skylize02:01:42

Pretty sure Parinfer has 2 modes? the well known one editing parens based on indents, and the other editing indents based onb parens. But it doesn't sound like you are activating such a toggle, so idk.

skylize02:01:34

Not a fan of Parinfer myself. Not enough value added to pay for the use of magic, imo.

didibus02:01:50

Oh right, that's probably why I got confused. No this is just one mode, basically you say indent to the next level and it indents the form adjusting the parens. Or you say dedent and it does the opposite.

didibus02:01:04

Pareinfer is too intrusive, like if you paste code, it will rewrite the parenthesis if the indentation is wrong for example. I find this is less intrusive, though it is a bit less powerful as well.

2
skylize02:01:47

Hmmm. Less intrusive, but also less powerful..... It's almost like there are trade-offs when choosing your tools. 😉

didibus02:01:45

They say: Parinfer [...] It could be seen as a more advanced adjust-parens.

seancorfield02:01:15

The pasting code issue was my biggest annoyance with parinfer. But my only real obstacle with paredit was just investing the time to learn it (and learn the key bindings for my current editor). It was time well spent - and it just continues to make me more and more productive as I learned more of it.

seancorfield03:01:00

(I was not a fan of paredit for years BTW)

seancorfield03:01:19

We are a long way off the OP's question at this point... So I hope this diversion has been useful...

👍 2
skylize03:01:57

> We are a long way off the OP's question at this point... So I hope this diversion has been useful... From my interpretation, OP clearly described a frustration keeping parens balanced. So I do not think we are all that far off track... 🤷 @U04JZS3AC59, please feel free to restate your concern if you think we've gone off the rails.

noob.clj03:01:45

This conversation have been more than helpful thanks a lot guys. I learned quite a few things today. I am already loving slurp 😛

metal 4
Kees16:01:38

@U04JZS3AC59 , my recommendation up next after slurp, if you haven’t seen in the paredit guide, is the 2 pairs of commands for alt-arrow keys! (Correct me if I’m wrong I believe these are default calva bindings) Alt-left and -right traverse to the start/end of sexp. So, outside a paren you’ll jump across the form to its match. Inside a paren, your cursor points to the individual form it’s touching, which means jumping across individual symbols/primitives/etc Alt-up and -down jumps the cursor similarly, but move the form it’s touching along with it. It just swaps the position of neighboring forms without rebalancing anything. So it is probably the simplest/most linear way to reorder the content within a sexp, easiest to use without garbling up the structure. And, paredit bonus, alt-up and -down will maintain pairs in maps, moving two forms the k and v at once! To me, slurp/barf, forward/back, and shuffle are the simple trinity of paredit with the most bang for your buck :)

👍 2
skylize18:01:50

It's helpful if you can try to use Command Names instead of (or in addtion to) shortcuts. This way, no matter what platform someone uses, they can find the command in the Command Palette or the Keyboard Settings Panel, or know what to look for in the https://calva.io/paredit/. Plus in this case, many other editors also offer Paredit, so your suggestion is potentially useful to anyone. I think you are describing Forward/Backward Sexp (which defaults to Ctrl+ /`←`on Windows or Linux) and Drag Sexp Backward/Forward ?

Kees03:01:49

Hi, all true! Wrote that on the couch early morning without a desktop in front of me. Correct, just checked and didn't know fwd/bkwd sexp defaulted to ctrl outside of macos. Thanks for the clarifications, all accurate, and helpful advice

Guild Navigator04:01:04

What’s the rationale for Clojure to be hosted in the JVM and not compiled to native code?

lread05:01:39

See also work-in-progress https://jank-lang.org/

didibus07:01:04

Clojure can now be compiled to native code as well. https://github.com/clj-easy/graal-docs

daveliepmann18:01:52

Some additional details on the native question in the https://clojure.org/guides/faq#native

gratitude-thank-you 2
o-hassidi07:01:50

Hello, I have this code that return a lazy list, how do I write this to get non-lazy list?

(map #(str %) "some string")
Thanks

didibus07:01:00

(mapv #(str %) "some string")

o-hassidi07:01:00

well this will give me a vector, and I wanted a list 😞

o-hassidi07:01:23

(type (map #(str %) "hi there"))
=> clojure.lang.LazySeq
(type (doall (map #(str %) "hi there")))
=> clojure.lang.LazySeq

didibus07:01:11

Oh, a list specifically,.maybe wrap it in with (list ...)

didibus07:01:33

Or try: (into (list) ...)

o-hassidi07:01:12

if wrapping with list then I need to do (first (list (map #(str %) "hi there"))) a bit ugly, isn't it something build -in like map to return non lazy list?

pavlosmelissinos07:01:02

What are you trying to achieve? It's not idiomatic to work with specific types.

o-hassidi07:01:48

I want to build a list from a string and peek on an element

o-hassidi07:01:16

and vector peek and list peek are different

delaguardo07:01:41

call first from the result of map. you don't need a list for that

☝️ 2
didibus07:01:18

You can peak into a LazySeq as well:

(first (map inc [1 2 3]))

o-hassidi07:01:33

ok, and how do I pop if needed?

pavlosmelissinos07:01:47

You don't have to "pop", you traverse the sequence

didibus07:01:48

Otherwise you can use the transducer map to return a list: (into (list) (map inc) [1 2 3])

pavlosmelissinos07:01:16

To rephrase: why would you need to pop?

didibus07:01:11

You would pop with rest and peek with first over sequences

o-hassidi07:01:59

OK let say for example I want to check a string that is valid only if I have paired brackets so this is a valid string (())[{}] in java we do that with stack data structure

didibus07:01:52

@U04V4KLKC I don't think so. Pop doesn't seem to be implemented for LazySeq

pavlosmelissinos07:01:12

> OK let say for example I want to check a string that is valid only if I have paired brackets so this is a valid string (())[{}] in java we do that with stack data structure > I'm pretty sure you can do that with filter and then just string substitutions. A more imperative approach would be reduce. Neither solution requires popping lists :)

didibus07:01:29

I think you're trying to do this:

(->
 (reduce
  (fn [acc e]
   (if (= "(" e)
    (conj acc e)
    (pop acc)))  
  (list)
  "(())(())")
 empty?)

☝️ 2
👀 2
pavlosmelissinos07:01:28

(This would work with a vector too btw)

o-hassidi07:01:28

Thanks guys, I'll try that 🙏

didibus07:01:38

Ya, both vectors and lists can be used as a Stack. Even though conj/pop/peek on a list is the first element, and conj/pop/peek on a vector is the last element, for a Stack it doesn't matter, conj/pop/peek still behaves in a first-in-last-out manner.

Carlo Ascani09:01:59

Hi all, I would love to start learning clojurescript. My plan is to follow a book and use Clojurescript to solve a very specific problem (that's the way I like). The specific problem in question is: rewrite an image gallery for a python based monolith I am developing. Do you think that's a use case for Clojurescript? Doesn't need to be the best, but is that doable?

moe09:01:46

Absolutely!

Carlo Ascani09:01:46

Is it easy to integrate Clojurescript in my webpack bundling? Or should I take an independent route to get Clojurescript into the project?

moe09:01:45

I would suggest going an independent route, with shadow-cljs

moe09:01:55

there's some information here about using it with webpack if you still have a need to, but I would try vanilla shadow-cljs and see how you get on https://code.thheller.com/blog/shadow-cljs/2020/05/08/how-about-webpack-now.html

Carlo Ascani09:01:34

shadow-cljs looks fine. Thanks

Carlo Ascani11:01:56

Do I want a Clojurescript specific book or is it ok a Clojure one? I will use Clojure for web client development only (to replace all my javascript code).

practicalli-johnny11:01:00

Clojure and ClojureScript are approximately 99.99% the same language, although the hosts they run on are quite different as are the types of applications build (e.g frontend, backend) http://funcool.github.io/clojurescript-unraveled/ is a good ClojureScript reference https://clojurescript.org/ provides a good starting point. If using shadow-cljs, then ensure to read https://shadow-cljs.github.io/docs/UsersGuide.html in detail Or https://figwheel.org/ if using figwheel.main instead of shadow-cljs

☝️ 2
oly14:01:38

Got another weird issue I am struggling to diagnose, related to connection pooling I am hitting

NoSuchMethodError 'void com.mchange.v2.cfg.BasicMultiPropertiesConfig.<init>(java.lang.String[], java.util.List)' 
The strange thing is I am only hitting this inside a generated uberjar, I am using polylith and have multiple projects with near identical startups everything works in one of the generated uberjars the db connection is established in the second project, I hit the above issue, to make things stranger using depstar it works using tools.build it fails I have been trying to diff the jars but I am not spotting much. Looking for any pointers on files to check in the jar, feels like it may deps related in a way as that's one of the major differences but open to suggestions, hit previous issues trying to switch tools.builds related to connection pooling freezing and that was deps related. any suggestions ?

Guild Navigator15:01:17

My deps.edn looks like this:

{:paths ["src"] ;; project paths
 :deps {org.clojure/clojure {:mvn/version "1.11.1"}}

 :aliases
 {;; Run with clj -T:build function-in-build (e.g. `clj -T:build jar`)
  :build {:deps {io.github.clojure/tools.build {:git/tag "v0.9.1" :git/sha "27ff8a4"}}
          :ns-default build}}}
When I do clj -T:build jar I get Namespace could not be loaded: build. What am I doing wrong?

Alex Miller (Clojure team)15:01:25

Where is your build.clj

Guild Navigator15:01:16

ah! I don't have one

Guild Navigator15:01:34

Somehow I thought using deps.edn meant you didn't use build.clj

Guild Navigator15:01:58

Okay so I created it:

(ns build
  (:require [clojure.tools.build.api :as b]))

(def lib 'my/lib1)
(def version (format "1.2.%s" (b/git-count-revs nil)))
(def class-dir "target/classes")
(def basis (b/create-basis {:project "deps.edn"}))
(def jar-file (format "target/%s-%s.jar" (name lib) version))

(defn clean [_]
  (b/delete {:path "target"}))

(defn jar [_]
  (b/write-pom {:class-dir class-dir
                :lib lib
                :version version
                :basis basis
                :src-dirs ["src"]})
  (b/copy-dir {:src-dirs ["src" "resources"]
               :target-dir class-dir})
  (b/jar {:class-dir class-dir
          :jar-file jar-file}))
I had to git init and commit it to get clj -T:build jar to work.

Guild Navigator15:01:22

But when I do clj -T:build uber I get Namespace build loaded but function not found: uber.

borkdude15:01:49

This is because there is no uber function in your build.clj? :)

Guild Navigator15:01:25

Yep just figured that out 🙂 It works now. Thanks for the help. It's my 1st day with Clojure.

👍 4
🎉 10
clojure 6
parens 4
2
didibus18:01:00

Think of tools.deps (aka deps.edn) as a Clojure launcher. All it does is launch Clojure programs (and download their dependencies if needed in order to launch them). Every alias describe a different program to launch or the same program launched with a different context (different entry point, different dependencies, different jvm arguments, etc.) And then the "build" tasks are just Clojure programs you launch with tools.deps. So what you're doing is just telling Clojure that clj -T:build uber should launch the script from build.clj with the uber function as the entry point, and that it should be launched in the context of a tool.

gratitude-thank-you 2
🙌 2
dharrigan17:01:23

If you have a map, say {:foo/bar 1 :foo/baz 2 :wibble/wobble 1 :wibble/fibble 2}, is there a way to just pull out, into a new map only foo/ keys?

feng17:01:06

well , there is no such filter by namespace existed, i think it's not hard to write one

moe17:01:33

(into {} (for [[k v] m :when [(= "foo" (namespace k)] [k v]))

moe17:01:01

(into {} (filter (comp #{"foo"} namespace first) m)) if that's how you roll

dharrigan17:01:35

I roll many ways 🙂

elken17:01:35

(defn select-keys-namespaced [key map]
  (filter #(= (namespace %1) (name key)) (keys map)))

dharrigan17:01:32

thank you everyone, very helpful 🙂

ghadi18:01:35

generally no reason to do that except at an edge in the system

4
ghadi18:01:07

(wire / database)

ghadi18:01:59

(ignore the stuff you don’t care about in a particular context)

dharrigan17:01:50

i.e., to end up with {:foo/bar 1 :foo/baz 2}?

Guild Navigator18:01:45

Is there an HTTP client in the standard library, or are we meant to use java.net.HttpUrlConnection via interop?

moe18:01:57

There isn't a Clojure one in the standard library

moe18:01:21

Most people would use a third party one over interop, I'd imagine

Ben Lieberman18:01:12

I've used the Java 12(?) HTTP client via interop and it's pretty easy but usually go with clj-http

didibus18:01:31

Generally the standard library is considered to be Java standard library + Clojure core library. It's very rare Clojure will provide its own when Java has one that's good enough.

didibus19:01:13

It's kind of part of the "being hosted" mantra, don't reinvent the wheel if there's not any major benefits.

Guild Navigator19:01:19

I guess I'm unclear as to what parts of Clojure are novel, and what are just wrappers around Java SDK.

didibus19:01:25

Hum, I don't think there's a clear ways to know haha. I/O is normally always wrappers, because the JVM already took care of creating Write ounce, Run everywhere IO abstractions over multiple operating systems and hardware targets. Everything related to the Clojure syntax, the immutable data-structures, the Lisp macros, the higher order functions, STMs, Atoms, Agents, transducers, sequence abstraction and all the sequence functions, core.async, etc. is all Clojure novel.

Guild Navigator19:01:12

Sorry for the silly questions. The last time I studied a Lisp-like language was in college in 1992 when I learned Scheme.

moe19:01:01

Clojure's even more fun than Scheme

hiredman19:01:21

Java comes with a better built in http client than httpurpconnection these days

Guild Navigator19:01:46

All I remember about Scheme is car and cdr

moe19:01:02

those days are GONE!

😂 2
Ben Lieberman19:01:26

^ that's the HttpClient I meant

2
dpsutton19:01:29

> I guess I’m unclear as to what parts of Clojure are novel, and what are just wrappers around Java SDK. Idiomatic Clojure allows the use of immutable, persistent data structures in your general coding. It has great data literal syntax to make domain modeling quite simple. Spec (and other 3rd party libraries) allows for opt-in contract enforcement at runtime if you like. Using a REPL is incredible once you get used to it. Using a query-able repl is a game changer in my opinion (check out (find-doc "binding") to search all docstrings that mention “binding” for instance. And after all of this, if you want to hit the host language, you can just interop directly with anything on the jvm already (like reusing an existing http client). There’s a lot to love about Clojure and there’s always the jvm underneath when you need it

Guild Navigator19:01:33

I was just playing around with GraalVM and being able to compile Clojure down to a single native binary is also very appealing.

dpsutton19:01:24

There are some pitfalls to it but there’s lots of tooling using that route to make some responsive goodies.

delaguardo00:01:07

clojure.core/slurp accepts url, kinda built-in pure man http client :)

🎯 4
oddsor08:01:14

https://github.com/gnarroway/hato wraps HttpClient and is pretty similar to clj-http if you don’t mind a third party library with no extra dependencies edit: I remember the reason I switched over to Hato over clj-http-lite (which uses HttpUrlConnection) was that HttpUrlConnection doesn’t support the PATCH verb, which was pretty annoying 😐

Fredrik Andersson22:01:17

I'm trying to go through the Lacinia tutorial which uses the user namespace. I get a compiler error when I try to require namespaces from the user namespace. Could somebody enlighten me why this fails? Code

(ns user
  (:require 
    [percap.schema :as s]
    [com.walmartlabs/lacinia :as lacinia]))

(def schema (s/load-schema))

(defn q
  [query-string]
  (lacinia/execute schema query-string nil nil))
Error
Exception in thread "main" Syntax error macroexpanding clojure.core/ns at (user.clj:1:1).
Call to clojure.core/ns did not conform to spec.
	at clojure.lang.Compiler.checkSpecs(Compiler.java:6989)
	at clojure.lang.Compiler.macroexpand1(Compiler.java:7005)
	at clojure.lang.Compiler.macroexpand(Compiler.java:7092)
	at clojure.lang.Compiler.eval(Compiler.java:7178)
	at clojure.lang.Compiler.load(Compiler.java:7653)
	at clojure.lang.RT.loadResourceScript(RT.java:381)
	at clojure.lang.RT.loadResourceScript(RT.java:368)
	at clojure.lang.RT.maybeLoadResourceScript(RT.java:364)
	at clojure.lang.RT.doInit(RT.java:486)
	at clojure.lang.RT.init(RT.java:467)
	at clojure.main.main(main.java:38)
Caused by: clojure.lang.ExceptionInfo: Call to clojure.core/ns did not conform to spec. {:clojure.spec.alpha/problems [{:path [], :reason "Extra input", :pred (clojure.spec.alpha/cat :docstring (clojure.spec.alpha/? clojure.core/string?) :attr-map (clojure.spec.alpha/? clojure.core/map?) :ns-clauses :clojure.core.specs.alpha/ns-clauses), :val ((:require [percap.schema :as s] [com.walmartlabs/lacinia :as lacinia])), :via [:clojure.core.specs.alpha/ns-form], :in [1]}], :clojure.spec.alpha/spec #object[clojure.spec.alpha$regex_spec_impl$reify__2503 0x2aa27288 "clojure.spec.alpha$regex_spec_impl$reify__2503@2aa27288"], :clojure.spec.alpha/value (user (:require [percap.schema :as s] [com.walmartlabs/lacinia :as lacinia])), :clojure.spec.alpha/args (user (:require [percap.schema :as s] [com.walmartlabs/lacinia :as lacinia]))}
	at clojure.spec.alpha$macroexpand_check.invokeStatic(alpha.clj:712)
	at clojure.spec.alpha$macroexpand_check.invoke(alpha.clj:704)
	at clojure.lang.AFn.applyToHelper(AFn.java:156)
	at clojure.lang.AFn.applyTo(AFn.java:144)
	at clojure.lang.Var.applyTo(Var.java:705)
	at clojure.lang.Compiler.checkSpecs(Compiler.java:6987)
	... 10 more

seancorfield22:01:06

Most likely a version conflict -- you're using a more recent version of Clojure than the tutorial works with.

seancorfield22:01:39

You could fix this by either using an older version of Clojure or by using a more recent version of Lacinia I expect.

Fredrik Andersson22:01:59

but I have chosen the newest of both

seancorfield22:01:45

Ah, then maybe you have a syntax error in your own code... what is percap.schema?

Fredrik Andersson22:01:16

that is my namespace located in the src/ folder

seancorfield22:01:25

and what does the ns form look like in your own code?

Fredrik Andersson22:01:49

(ns percap.schema (:require [http://clojure.java.io :as io] [com.walmartlabs.lacinia.util :as util] [com.walmartlabs.lacinia.schema :as schema] [clojure.edn :as edn]))

seancorfield22:01:11

What about the code where you are requiring percap.schema :as s?

seancorfield22:01:20

That's the form I think it is complaining about...

Fredrik Andersson22:01:53

I dont understand the question

seancorfield22:01:15

(user (:require [percap.schema :as s] [com.walmartlabs/lacinia :as lacinia])) is what it is complaining about in that exception.

Fredrik Andersson22:01:53

it should be percap/schema right?

seancorfield22:01:11

No, namespaces have . in them -- / is for files.

seancorfield22:01:37

What file is that (ns user ..) form in?

Fredrik Andersson22:01:42

(ns user (:require [percap.schema :as s] [com.walmartlabs/lacinia :as lacinia]))

Fredrik Andersson22:01:56

its located in dev/user.clj

Fredrik Andersson22:01:07

I think i found it now.

Fredrik Andersson22:01:27

[com.walmartlabs/lacinia :as lacinia])) should be [com.walmartlabs.lacinia :as lacinia]))

Fredrik Andersson22:01:11

thank you for your help! now i have a different error that I need to figure out

seancorfield22:01:27

Oh, ouch. Sorry, I should have spotted that...

seancorfield22:01:28

FWIW, group/artifact for dependencies has no relation to that might be inside it. It can be confusing if they look similar (as in this case).