Fork me on GitHub
Mark-James M.00:06:10

Just figured it out

👍 3

its a perfectly cromulent question 🙂

😆 3
Mark-James M.00:06:38

Needed to add float

Mark-James M.00:06:01

(def average (float (/ (+ 20 50 60) 3)))


float is only needed for interop (and even then is very rarely needed) - use double, and also you can count on the result being floating point if 1 arg is floating point

Mark-James M.02:06:45

I generated a new Leiningen project and am trying to run it using lein run but am getting the following error: No :main namespace specified in project.clj.


can you give me repro steps? sounds strange


(how you generated and then how you're running it)

Mark-James M.02:06:25

I created the project in Cursive, then I had been running it in the REPL

Mark-James M.02:06:31

Then I opened a command prompt and typed lein run in the project dir


weird. i wonder what cursive did.

/tmp ❯❯❯ lein new app thing && cd thing && lein run
OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
Generating a project called thing based on the 'app' template.
OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
Hello, World!

Mark-James M.02:06:55

That's really odd, creating a project through the command line worked


how did you create it in cursive? I'll try it there but i'm still new at cursive


and i get a little lost in cursive when it does a bit too much

Mark-James M.02:06:38

File--> New Project --> Leiningen

Mark-James M.02:06:50

looking at the non cursive project

Mark-James M.02:06:52

:main ^:skip-aot learn.core

Mark-James M.02:06:03

is inside project.cli


there are templates. i guess lein new app app-name adds that stuff


you can specify a template to be used. i put app in the template spot and it does what the command line version does. hope that helps

👍 3

What's going on under the hood when (seq [1 2 3]) is called? The suggests that seq returns an implementation of ISeq that "appropriate to that collection", but if that's the case why does (conj (seq [1 2 3]) 0) append to the left rather than the right, which would be the most performant way to append to a vector?


an implementation of ISeq is a seq, not a vector


"appropriate to that collection" means it returns a seq that knows how to traverse that collection, not some kind of seq that is different


i agree that wording is a little strange though


its correct when you know what's going on but is understandably confusing when reading for the first time


@abhiyantsingh This might be good reading, as it talks about the differences between "collections" and "sequences"


Got it. Appreciate all the replies! One example I'm curious about is (-> [1 2 3] (conj 4) (seq) (conj 5)) => '(5 1 2 3 4). In this situation, conj adds to the right of the vector but to the left of the seq generated from it. Based on the code that @dpsutton linked, it seems like seq contains references to the original vector, does that mean that any conj calls to a seq made from a vec are O(n)?


hiredman put it very well. it knows how to traverse a vector quickly. but you have a think with two functions on it: first and rest. and the only way to add is to put something as the new first


Once you call seq on a vector, you get a "chunked seq(uence)" and conj on a sequence acts like cons so it prepends the new item.


You can see some of the types in play here

user=> (type [1 2 3])
user=> (type (seq [1 2 3]))
user=> (type (conj (seq [1 2 3]) 0))
user=> (type (conj [1 2 3] 0))


if your view of the world is the first thing and then the remaining things, the only way to add quickly to it is to plop it as the new first.


(also, from the above types, you can perhaps infer that (conj (seq [1 2 3]) 0) is O(1) because it simply returns a Cons object with 0 as the first and the original sequence as the rest)


So is the cost of calling seq on a vector O(n)? Because it has to create the ChunkedSeq? It seems like there's a traversal happening in the constructor there in arrayFor so just wanted to confirm.


the cost is O(1)


reading that code i linked, its just a java object with the vector and an index


So, based on @seancorfield's example, it constructs a ChunkedSeq, and my interpretation of the code is that it's doing a traversal; am I misinterpreting what's calling what?


I suppose what I'm struggling with is that if you start with a vector and end up with an operation that appends to the left side, such as (conj (seq [1 2 3]) 0), I don't see how an O(n) operation is avoided, since you either append to the left of the vector, which is O(n), or spend O(n) to build a collection that has O(1) left appends. Does that make sense?


you don't append to the left of the vector in the sense that the vector is now [0 1 2 3]. you append to the left of the seq in the sense that you have 0 first and the rest is a seq view of the vector


Ohhh. Thank you! That finally made it click for me.


Appreciate all the help/patience, everyone!

parens 3

the chunked stuff and reading the java code can often introduce more complexity when first learning it. so i hope i didn't muddy the waters too much


Not at all, the concreteness helped! I'd been poking around the code base for the last hour trying to figure this out but was looking in the wrong places.


If you are poking around the Java implementation of Clojure to learn, then you might in some cases find this library useful for visualizing the in-memory representation of Clojure values as JVM objects:


This looks sick. Thank you!


as did i. i went right to APersistentVector and sean did a very thoughtful thing and asked the repl what is actually going on


I still get a little muddy understanding how IPersistentVector, APersistentVector and PersistentVector interact. but those concerns are far from #beginners channel 🙂


Yup, I'm saving that rabbit-hole for sometime... later 🙃

Mark-James M.06:06:54

I purchased the Getting Clojure book the other day and its been a huge help

clj 6

dear all, how to avoid circular require? Thanks.


Extract functions that cause the circular require into a new namespace


Hi all! I am getting started with clojure (with some javascript experience) and quite love it, though am having difficulty figuring out the app-packaging side and wondering if anyone had advice/or a good direction to point me. In short: I am building a daily-update page using clojure and hiccup…it reads some weather info, plus an .edn file I made of my feelings and observations I’d made about weather that day, and translates it into a single static html page. I made this with using lein new app and it works well enough, but where I am lost is how to add new feelings/observations. I was imagining a simple terminal interface that just said “how you doing!” then “how’s the weather?” and takes the input from both these lines and writes them as a new map to my feelings.edn, and then run the page generator and take the top map from this vector to update the page.


I’m finding it hard to conceptualize how to make this simple terminal interface…of essentially printing “What is your feeling: ” and waiting on text input. On searching online I found a cool looking [cljs-tui]( template plus [lanterna](, but felt that both might be overkill for what is a simple ask?


(part of this is that I’m coming from javascript experience of looking for a framework first, then making that work for my needs…and trying to get away from that)


Thank you for any opinions/directions you’d recommend on this!


clj -e '(println "how are you feeling?")(let [feeling (read-line)] (spit "feelings.edn" {:feeling feeling}))'

parrot 3

oh, awesome, thank you, @dpsutton! Do you think the best way to do a two-step question (e.g. “how are you feeling”->input, then “how is the weather?“->input) be to define a map of {:feeling :weather}, then do a print statement for feeling, assoc read-line to :feelings, then second print for weather, assoc read-line to :weather, then spit that map to feelings.edn? This feels like a straightforward /imperative way to do it, but not sure if it’s idiomatic.


I think that’s ok:

(let [_       (println "how are you feeling?")
      feeling (read-line)
      _       (println "how's the weather?")
      weather (read-line)] 
  (spit "feelings-and-weather.edn" {:feeling feeling :weather weather}))
Seems to work inside a clj repl, for some reason doesn’t work via the “clj -e” command


this is great!


run that in a terminal. will spit the results into a file "feelings.edn'


Hello everyone i am vishal ,i am a freelancer i offer services in web development,app development,SEO.I will provide services at lower prices without compromising the quality of product. Dm me if anyone has any project.

spam 9
David Pham16:06:03

Anyone who knows some resources to compile ClojureScript using GitHub actions?


Just a curious question... in Java it is possible to represent larger numbers with using underscore like this: 1_000_001 so it's more readable and actually writable. Is there anything similar to this in Clojure?


The Clojure reader does not support that, no. One could write their own code/data reader that does, but that would not help you write numbers in that way in an unmodified version of Clojure.


@andy.fingerhut do you think it's realistic to request such improvement? It's obviously nice to have, low priority thing, but still...


I suspect it already has been requested -- checking to see if there is a JIRA issue for it already. I don't expect such a change to make it into Clojure soon, if ever. It isn't pure advantage -- consider the use case of searching for occurrences of the number '1000000' in source code using tools like grep.

☝️ 3

I didn't find an existing issue in a minute of looking. You are welcome to ask the question on yourself and see what kind of response you get.


i would love the feature.

❤️ 6

Understood completely. I am not against it myself. But neither am I the decision maker, and it isn't a democratic process.


(nor do I think it should be a democratic process)


totally agree. just chiming in with a little +1


I've found this I actually give it a short and did some implementation myself. TL;DR I have a working implementation, working on tests. I'll try to be initiative and propose a patch with some rationale and pros and cons as I see them.


Cool. I didn't see any comments from someone like Alex Miller in that conversation, for or against the proposed change. That simply means there is no information there on whether the Clojure core team is interested in such a change. It is at least possible that they are not interested, but haven't mentioned it in that issue. If you enjoy making experimental patches for the sake of your learning, great, but if you are becoming strongly emotionally invested such that your world view will change if they say "no" to the idea, you may want to get some indication of that before spending lots of time on it.


How do I make this work:

(contains? (sort #{2 1 3}) 1)
It gives me contains? not supported on type: clojure.lang.ArraySeq


(sort #{2 1 3}) returns a seq (1 2 3) which doesn't support contains?


(contains? #{2 1 3} 1) should report true


yeah, that's just an example. In reality my set/arrayseq is coming from (sort (java.time.ZoneId/getAvailableZoneIds))


(def timezones
  (sort (java.time.ZoneId/getAvailableZoneIds)))


why do you need it sorted here?


using it on for display (web form)


check out (doc sorted-set)

🆗 3

could you have a sorted version of it for iteration and a set for membership checking?


yeah, sure. I thought there was a simpler alternative for contains? that works with arrayseq


arrays can only check membership through linear scans checking each element for equality. keep a datastructure that has O(1) membership check and a version that is an ordered version if you also need that


the docstring of contains? points you towards some if you do need to search through an ordered collection for an item


got it, thanks for the clarification


i point that out because (doc [thing]) is an incredibly useful thing. the repl is self-documenting to a large extent and very helpful. your editor most likely has some keybindings and UX to ease this as well


I've been using for the accompanying examples mostly, will give doc a try

andy.fingerhut19:06:39 contains output of doc at the top, before the examples


@somedude314 what editor are you using?


many have clojure-docs built into the editor


At least for things that covers. It does not cover many Clojure libraries, if any


hit control-j on a symbol and it should show the docs and clojuredocs in a popup


Ah awesome, thanks. F1 is showing me the docs for what's under the cursor


yeah. i think those are bound by default to the same keybinding. not sure. but i think you're seeing what i was suggesting


Am gonna roll with this then: (defn timezones [& {:keys [sorted?] :or {sorted? false}}] (let [tz (java.time.ZoneId/getAvailableZoneIds)] (if sorted? (sort tz) tz)))


Passing in sorted true is more verbose than just calling sort on the caller side


haha true, I think I'll do just that


This makes me wonder how many over complications I have in my Clojure code as a beginner 🙂


A good rule of thumb is for functions to do one thing only: a function to return the timezone IDs, a function to sort them. The latter is built-in. Small, composable functions, mostly pure.

👌 3

If I would like to provide a different implementation to a java method like isEmpty to my custom record, how should I approach it?

(defprotocol IMyInterface
  (isEmpty [this]))

(defrecord MyData []
  (isEmpty [this]))
The above code will not work with the following error msg: Duplicate method name "isEmpty" with signature "()Z" in class file


@iagwanderson Records already implement .isEmpty() based on whether they have any fields or not:

user=> (defrecord Foo [])
user=> (.isEmpty (Foo.))
user=> (defrecord Bar [x])
user=> (.isEmpty (Bar. 42))


I noticed that, I was following a java example where the property of being empty for a specific class had a custom definition. I wanted to implement the same and found this "problem"


I know I could change the name but I got curious about how to go about "overwriting" the default implementation


Changing the definition of isEmpty on a record could break all sorts of things in Clojure operations on it, I suspect.




I think you'd have to use deftype and build up a map-like data structure from scratch in order to provide custom isEmpty behavior... which would be a lot of work and also produce a custom data structure with "unusual" behavior...


or a protocol that has your own custom notion of emptiness


I didnt get the protocol option @dpsutton


i think you could maybe proxy here?


Hmm. I’ve never thought about protocols with name clashes


@dpsutton when you said about using proxy was something like this?

(defrecord Value [])

(def v
  (proxy [Value] []
    (isEmpty [] (println "You are empty"))))


the error informs we can't inherit from final classes.