Fork me on GitHub
#beginners
<
2018-07-31
>
lee.justin.m00:07:14

@hoopes I would direct you to one of two strategies: (1) bundle all your javascript code with webpack and then include it use :foreign-libs (https://clojurescript.org/guides/webpack), or (2) use the shadow-cljs build tool. https://shadow-cljs.github.io/docs/UsersGuide.html

lee.justin.m00:07:42

shadow is probably best if you don’t already have a big lein infrastructure in place

hoopes00:07:59

yeah, i’ve heard of shadow, i guess i should probably learn it…it’s meant to work best with npm?

lee.justin.m00:07:31

the npm-deps feature is pretty “alpha”. it’ll break on quite a few things and is hard to debug. it’s getting better but it’s not quite there yet.

lee.justin.m00:07:09

shadow works great with npm packages. it is super smooth: you just install via npm and it reads directly from node_modules

hoopes00:07:30

and there’s no need for any type of externs files or anything?

lee.justin.m00:07:15

likely not if you use externs inference. jump into #shadow-cljs if you decide to go that way

hoopes00:07:34

10-4, got my project for tomorrow. thanks very much!

d4hines01:07:50

Thanks @michael.gaare and @noisesmith. In my case I do in fact need to manage a stateful connection object, but you're right, a connect function to create the handler and passing the handler in gives the most flexibility to the user. Appreciate the input!

noisesmith02:07:10

as a value add you can premake eg. the version that stores the connection as a global singleton, or the version that implements a stuartsierra/component object, but bare minimum should be the ability to make your domain object with a function, and pass it to another function, and usually that's enough

valtteri05:07:53

What’s going on when my webapp works fine when I run it in REPL but when I package it as uberjar I’m getting this when trying to run java -jar blabalba.jar > Exception in thread “main” java.lang.NoSuchFieldError: thunk__0__

valtteri05:07:45

This probably has something to with aot and having right settings in project.clj. I’ve specified :main pointing to a namespace where I have -main function and :gen-class. I’ve tried specifying :aot :all in my lein uberjar profile and leaving it unspecified but I’m getting this same error.

valtteri07:07:54

Hmmm, after removing dependency [com.fzakaria/slf4j-timbre "0.3.7"] uberjar works! Interesting. I’m not even sure why I had that dependency. 🙂 Anyways, is it a common thing that some libs or combos of libs just don’t work with uberjar?

keithmantell08:07:40

@valtteri - I am not an expert but https://github.com/fzakaria/slf4j-timbre has the version at 0.3.12 and also mentions 3 other dependencies you should have.

valtteri08:07:30

Thanks Keith, I had some rough times figuring out all the Java logging frameworks/wrappers/utils a few weeks ago and I guess slf4j-timbre was leftovers from my experiments. I ended up using just timbre and excluding any other logging libs. But it’s interesting that it breaks my uberjar. I’d like to know why that happens.

eggsyntax13:07:27

@valtteri I don't know offhand why that's causing problems, but the first thing I'd look for would be dependency version classes, which you can do (in projects using Leiningen) with lein deps :tree. The beginning of the output from that should show any potential conflicts. If you find a conflict that seems relevant, you can exclude it in project.clj by adding exclusions like

[com.fzakaria/slf4j-timbre "0.3.7"
   :exclusions [some.lib]]
It may not be a dependency conflict at all, but it's a good thing to check.

valtteri09:07:15

However, I was able to proceed by removing the dependency. I just don’t like to leave ‘holes’ to my understanding, because I’m sure it will haunt me in the future. 🙂

keithmantell09:07:53

timbre is what I use (ok, inherited from an example)

valtteri13:07:53

Cool, thanks @eggsyntax! I didn’t realize there was useful human-readable debug info at the beginning of lein deps :tree output.

valtteri13:07:50

..and suddenly I un-learned how to use Slack threads.

somedude31413:07:27

What is "deps.edn" exactly? It seems like an official replacement for leiningen project.clj. Is that correct?

orestis13:07:59

@somedude314 Not quite - it deals mostly with dependencies, whereas lein is a build tool.

orestis13:07:57

There has been a push recently to try and replicate a lot of lein plugins into standalone libraries that can be then consumed without lein (e.g. uberjar) but it’s not quite widespread.

somedude31413:07:37

@orestis Hmm, that's odd. It deps.edn doesn't seem to be doing anything that can't be done in project.clj

orestis13:07:30

It has a different philosophy. Plus you can get dependencies from git, github, gists and so on — also it’s simpler (in the clojure sense) than lein.

orestis13:07:50

FWIW, when I was trying out a Clojure project at work I went with lein 🙂

somedude31413:07:32

@orestis Ok thanks. At least I am sure now they do the same thing in general.

james08215:07:16

👋 Using Clojure spec how do I specify an "XOR" on keys. Namely that a map should have either :foo or :bar, but not both :foo and :bar?

james08215:07:13

So far I've got this, but it's a bit clunky:

(s/def ::foo int?)
(s/def ::bar int?)
(s/def ::foobar
  (s/and
   (s/or
    :f (s/keys :req-un [::foo])
    :b (s/keys :req-un [::bar]))
   #(not (and (contains? % :foo)
              (contains? % :bar)))))

mario.cordova.86216:07:44

Cannot open <nil> as a Reader.

mario.cordova.86216:07:33

^ Has been the bane of my Clojure experience

noisesmith16:07:01

my hunch is usually that would be prevented by nil-checking the return value of io/resource

mario.cordova.86217:07:50

yea, something was nil and cause that.

mario.cordova.86217:07:24

I changed a project's dependency to a different snapshot and I get this error Exception in thread "main" java.lang.NoClassDefFoundError: clojure/lang/Tuple

mario.cordova.86217:07:49

Anyone have an idea what might be causing that?

mario.cordova.86217:07:15

If I go back to an older snapshot the error goes away the project starts up as normal

mario.cordova.86217:07:40

I have a feeling its because we are using an older version of Clojure in this project

mario.cordova.86217:07:50

and the dependency is using a higher version

mario.cordova.86217:07:28

The Clojure/lang/tuple leads me to believe that

mario.cordova.86217:07:32

otherwise I am lost

seancorfield17:07:47

@mario.cordova.862 Yes, Tuple was briefly added and then removed IIRC.

ghadi17:07:47

you're on the right track. You might have a dependency that is accidentally AOT-compiled, or some stale files in ./target

seancorfield17:07:12

What's in your project.clj file?

seancorfield17:07:33

(and, maybe, lein clean will help you get back to a sane state)

mario.cordova.86217:07:44

Updating to clojure 1.8.0 got it working

mario.cordova.86217:07:55

So I guess it was language version mismatch?

seancorfield17:07:14

What version(s) were you trying to use?

mario.cordova.86217:07:53

The project I was working on was using 1.5.1

jgh17:07:11

hey, how can i have my resources path included in the jar file from lein uberjar? I tried adding it to :resources-paths [...] but it seems to just create the directory and not actually use it

seancorfield17:07:14

OK, so that was an official released version -- sounds like one of the other dependencies in the project was expecting a different version of Clojure then maybe?

jgh17:07:34

(i know it creates the directory cause i screwed up the name once :P)

seancorfield17:07:00

@jgh it's :resource-paths

seancorfield17:07:41

Is your resources folder not just called resources then?

mario.cordova.86217:07:50

The other dependency in question is using org.clojure/clojure "1.8.0" :scope "provided"

jgh17:07:15

in the base directory of the project, right?

seancorfield17:07:21

@mario.cordova.862 Ah, so it may well rely on things that weren't in Clojure 1.5.1 ...

seancorfield17:07:41

1.5.1 is pretty old and a lot was added in 1.6, 1.7, and 1.8.

seancorfield17:07:24

@jgh Yeah, whenever I've had resources and project.clj in the same directory, I don't think I've ever needed to specify :resource-paths... that's the default, after all.

jgh17:07:13

yeah for whatever reason it doesnt seem to be copying things into the jar....do i need to actually reference them in the program?

jgh17:07:39

the resources directory is in the jar, but it is empty

jgh17:07:01

oh wait, are they just copied into the base of the jar?

jgh17:07:32

ah yeah thats whats going on, it looks like the resources are just copied into the base of the jar and not in a resources/ subdir

noisesmith17:07:44

@jgh right, all your paths (source paths, resource paths...) are merged into the top level of the classpath

noisesmith17:07:27

if you used io/resource to access the files you'd likely notice already that looking them up with the resources/ prefix doesn't work

noisesmith17:07:34

(even before making a jar)

jgh17:07:22

is there a way i can tell what came from a resource path after the fact? Basically i'm compiling things down to a native image with graal and want to copy the resources but not the unnecessary java stuff

seancorfield17:07:18

Do you mean you want the "unnecessary java stuff" excluded from the uberjar?

vrcca17:07:41

Hey... I'm thinking about buying the book "Clojure Applied". Do you guys think it's a good book to read after you learn the basics?

seancorfield17:07:08

@vrcca What books/tutorials have you worked through so far?

vrcca17:07:27

@seancorfield Clojure for the brave and true

jgh17:07:44

so im taking the jar and doing native-image ... to build a standalone executable, but this obviously doesnt include resources or anything else really.

vrcca17:07:13

I want to learn how to put all those things together. Clojure for the Brave taught me the syntax, but not how to use it in a structured real project

jgh17:07:16

so there will be no jar, just an executable and the resources needed by the program (as in stuff they added)

noisesmith17:07:40

isn't using a resources jar still an option?

jgh17:07:07

what do you mean

noisesmith17:07:22

you still need to ensure the resources are visible at runtime, right?

hiredman17:07:27

are you sure native-image doesn't include resources?

jgh17:07:45

i'm not positive that it doesn't, there seems to be some documentation suggesting that it may (via -H:IncludeResourceBundles=...) but it seems like that might be for something specific

jgh17:07:00

im thinking like...images or whatever

jgh17:07:46

so i need ot have a regexp

joshua.d.horwitz18:07:16

I ran across http://www.landoflisp.com the other day, I saw that it was published in 2010. Is this book still a good read and helpful getting aboard Lisp land?

manutter5118:07:26

I’ve got that book — It’s a fun read, although after Clojure the code looks a bit unwieldy (Clojure’s [] {} #{} etc make much nicer visual distinctions). The LISP way is a bit different from the Clojure way, but LoL is a good look at the LISP way, for comparison.

seancorfield18:07:41

@vrcca Clojure Applied should be a good second or third book. Maybe Programming Clojure first, after Brave and True?

jgh18:07:36

is there a way of inspecting the image to see if the resources are in there?

seancorfield18:07:12

@jgh For a JAR file? Sure, use jar tvf filename.jar

lilactown18:07:09

is there a way to have a s/keys spec use a key different than the name that a spec was registered with?

lilactown18:07:30

e.g. I have a map with :status that I want to use a spec called ::coverage-status to validate

jgh18:07:26

@seancorfield i mean for the native-image using something like -H:IncludeResources=".*" which doesnt seem to be changing the size of the outputted binary 😞

seancorfield18:07:25

Sorry, no clue about Graal...

jgh18:07:08

yeah, i figured...i wish the graal documentation for this was more than 25 lines 😕

seancorfield18:07:57

@lilactown how would :coverage/status do for you? (s/keys :req-un [:coverage/status]) will spec {:status "foo"} with a spec definition of (s/def :coverage/status ...)

seancorfield18:07:37

(@jgh and maybe Graal-related stuff isn't #beginners material? #graalvm might be a better venue...)

jgh18:07:10

yeah i can take the graal stuff in there, my original question so far still stands and is maybe not so graal related haha

lilactown18:07:37

@seancorfield I'm afraid that that might be clobbered by other ns's; I wanted to keep it in the current ns

seancorfield19:07:35

@jgh I think at this point I've lost track of your original question, sorry, or I thought it was answered 😞 Happy to try again...

jgh19:07:37

ah i just wanted to copy the non-java stuff in the jar...whatever was originally in the resources paths and not generated by the compiler, i guess

seancorfield19:07:47

@lilactown If you want to keep it in the current ns then ::status would work. But part of the idea of namespace-qualified specs is to make them "as unique as necessary" so you're not going to run across a single-segment ns called coverage so you could decide that :coverage/status is "unique enough" for your app.

lilactown19:07:59

thanks. I ended up just using :coverage/status. makes me a little nervous, but seems like the best case for now

lilactown19:07:17

I'm just worried someone else, in another ns, might have a different notion of :coverage/status (unfortunately)

seancorfield19:07:17

@jgh I thought you said resources was copied into the top-level of the JAR file? That wasn't the answer?

jgh19:07:07

sorry yeah i was originally confused by where they should be so i thought they werent being copied at all, but since they're in the top-level of the jar file i can't just copy the directory wholesale and get all of the resources...well, i can, but it comes with other stuff too

seancorfield19:07:27

Yeah, it's a bit of a sledgehammer/nut situation (I just ran across it in a situation where I point resources at a folder full of SQL files because I wanted them in the JAR -- and of course ended up with 800 of them in the top-level of my JAR file... urk!).

seancorfield19:07:58

If you're using Boot, you can "sift" files based on regex so you have a lot more control than Leiningen exposes.

noisesmith19:07:08

why not resources/foo/ - everything in foo is now in /foo/ on the classpath

chase-lambert20:07:49

hello. i'm in chapter 4 of the Brave book and it's already getting a little tough for me. like a seemingly easy example like this seems to be hard for me to wrap my brain around. I think i'm missing some of the fundamentals and was wondering if you could help with a strategy to break these functions down for understanding.

chase-lambert20:07:01

i had the same problem when playing around with Elm. when i see the same values (like new-map and key and val) all repeated over and over again in the same function my brain slows down.

noisesmith20:07:54

the repetition here is the binding vs. usage - wouldn't you bind the value to some value before using it in any language?

chase-lambert20:07:21

i don't really know any language to give a more clear starting point.

noisesmith20:07:26

the general idea is that to use a value, there's usually two steps - the name gets assigned to some value, then something is done with that name

chase-lambert20:07:53

so new-map is assigned to the vector [key val]

chase-lambert20:07:00

then we do stuff to new-map?

noisesmith20:07:03

(fn [x] (f x)) means that the function's arg is x

noisesmith20:07:20

no, new-map and [key val] are a binding and a destructured binding

noisesmith20:07:00

it's equivalent to (fn [new-map entry] (let [x (first entry) y (second entry)] ...))

chase-lambert20:07:12

ok, ok. i suspected it was the destructing thing again. that was tough for me.

noisesmith20:07:44

destructuring is a special syntax that helps us write more concise code https://clojure.org/guides/destructuring

noisesmith20:07:32

I bet if you spend ~15 or 30 minutes playing with variations of the examples in the above doc in a repl and seeing what does and doesn't work, you'd understand destructuring

chase-lambert20:07:42

will do. thanks! i'm hoping its not a bad sign that I am struggling this early on. with some introspection i realized i've been bouncing around various languages as soon as the going got tough with excuses that it wasn't the right fit for me. i'm trying to bear down and power through that now.

nickstares001:08:48

it's always rough going in the beginning! definitely not a bad sign, just very normal. keep at it and things will slowly click.

noisesmith20:07:43

best of luck

thiru013020:07:13

Hey guys - pretty new to Clojurescript

thiru013020:07:53

Is anyone here using Vim and Figwheel-main together?

thiru013020:07:15

Along with Clojure on the backend

thiru013020:07:53

I'm not sure how to setup Vim (fireplace) to talk through a single nREPL server with CLJ and CLJS

emilien11:08:45

I'm beginner too and I got successful with vim and fireplace for clojurescript. Here are my note: https://notes.pinboard.in/u:emak/notes/172850031b7a5053f9f7

emilien11:08:43

but I do not talk to backend in the same repl. For me it is a completely separated repo.

orestis20:07:04

@chase-lambert there’s also #programming-beginners that is aimed for people who use Clojure as their first language. You are welcome to keep asking here, of course! Don’t give up :)

chase-lambert20:07:15

oh nice. not sure how active that one is but i'll use that one for the super newb general programming questions and keep this one to clojure beginner topics

mario.cordova.86221:07:49

Has anyone seen a function (.executeclj)?

noisesmith21:07:43

that syntax indicates a method, not a function

mario.cordova.86221:07:22

I was under the belief that method and function are used interchangeably.

jgh21:07:40

typically a method implies that it is part of a class

mario.cordova.86221:07:35

Yea I just looked it up

noisesmith21:07:27

in clojure the difference is important, because methods are not first class and functions are

noisesmith21:07:00

you can pass str to map as an arg, you can't pass .toString

mario.cordova.86221:07:34

I see so that function is coming from Java world.

mario.cordova.86221:07:43

Explains why I can't find it anywhere

mario.cordova.86221:07:00

Also could someone explain

Returns a memoized version of a referentially transparent function. The
memoized version of the function keeps a cache of the mapping from arguments
to results and, when calls with the same arguments are repeated often, has
higher performance at the expense of higher memory use.

mario.cordova.86221:07:11

What is a referentially transparent function

mario.cordova.86221:07:22

So if I understand correctly memoize will store the mappings in memory so if I call a function with the same arguments it doesn't have to calculate the transformation?

hiredman21:07:06

that means for the same inputs there should be the same outputs without observable side effects

hiredman21:07:25

which is kind of hilarious, because memoize is almost always used to cache the results of an impure function

noisesmith21:07:08

@mario.cordova.862 even talking about Java and leaving Clojure aside, Java methods are not functions, and they have Function (and a bunch of related objects) that are first class and similar to clojure functions

mario.cordova.86221:07:11

@noisesmith duly noted! Idk where I got the idea that they are one and the same

noisesmith21:07:07

for Java before the Function interface, most people used the terms interchangeably (and inevitably many still do...) - and on a more abstract level they are similar things. But it's really helpful to remember the difference so I get pedantic about it in a Clojure context.

tbaldridge23:07:04

This is why I prefer the term elidable. PyPy uses the term to mean something that could have side-effects but not in a way that we care