This discussion ("Clojure just needs to start saying Yes") has Yegge explaining his opinions on this subject.
EDIT: link updated to start at Yegge's first post - my first link started further down the chain.
The tool's usefulness depends on your understanding of it, I suggest reading Rich's paper on the history of clojure https://clojure.org/about/history to get a sense of why he built this tool.
Rich had been doing enterprise java development for a long time before he spent the time to build Clojure, your concerns are addressed in the paper.
Clojure 1.10.1 is a small release focusing on two issues: working around a Java performance regression and improving error reporting from clojure.main.
Recent builds of Java 8 (u202), 11 (11.0.2), 12, and 13 included some changes that drastically affect optimization performance of calls from static initializers to static fields. Clojure provides support for loading code on startup from a user.clj file and this occurred in the static initializer of the Clojure runtime (RT) class and was thus affected.
This issue may eventually be resolved in Java, but in Clojure we have modified runtime initialization to avoid loading user.clj in a static initializer, which mitigates the case where this caused a performance degradation.
clojure.main is frequently used as a Clojure program launcher by external tools. Previously, uncaught exceptions would be automatically printed by the JVM, which would also print the stack trace.
This release will now catch exceptions and use the same error triage and printing functionality as the Clojure repl. The full stack trace, ex-info, and other information will be printed to a target specified by the configuration. See clojure.main docs for configuration details.
See the change log for a complete list of all changes in Clojure 1.10.1.
All you need is:
This combination has been working perfectly with any version of Clojure.
This article repeats a mistake of the main Clojure.org documentation on metadata: both begin by talking about how "Symbols and collections support metadata", which is insufficient framing.
It leaves out a common daily use of metadata, probably the most common. Most metadata will be on vars, not symbols or collections, hence all the use of #'
in the examples.
E.g., this is probably the order many newcomers first approach retrieving metadata:
(defn- my-fn [] :bar) ;; where's the private metadata? (meta 'my-fn) => nil ; not on the symbol (meta my-fn) => nil ; not on the resolved fn obj
;; ... goes off, reads the docs, looks at examples
(meta #'my-fn) => ; aha! now it works {:private true, :arglists ([]), :line 1, :column 1, :name my-fn, :ns #object[clojure.lang.Namespace 0x3d223aea "user"]}
This was going to be my suggestion as well. As much as I like Clojure, Racket is a much better choice for teaching a beginner. It has a super easy "get started" experience by providing the runtime, IDE (DrRacket), and a bunch of basic libraries in a single package. As an IDE, DrRacket isn't a good choice for an advanced user, but it's great for a newbie, with good-enough usability, good error messages, and great visual feedback for things like showing where a defined function is called in the code, or even cool things like being able to store and display images in the REPL.
Plus, the combination of a Scheme and How to Design Programs lets you teach programming principles instead of focusing on language syntax. Even without HtDP, Racket's a good beginner-friendly, batteries-included Scheme, making it a good choice for teaching FP, abstractions, library usage, and other basic programming concepts without getting hung up on syntax and language oddities. Basically, you get most of the same advantages as teaching Clojure, without a lot of the major negatives of it, and you get a good base for moving onto another language, maybe even Clojure, later.
If you do decide to try using Clojure, though, I'd suggest going with ClojureScript by way of Lumo. CLJS is slightly better with error messages, and Lumo makes it fairly easy to get up and running, good for scripting tasks and the like, and no Java or figwheel baggage to interfere with learning. The basic things learned will still translate to normal Clojure or ClojureScript use, but allows learning with less up-front effort that might be discouraging.
> What did make me happy? My paycheck. That's really the exchange here...
We all perceive the universe differently. My perception is different than yours. What makes me happy when writing software is much more than a paycheck. I am not a Ruby programmer, never was, but I played with it. It was fun, and I enjoyed it. I am a Clojure programmer, it is fun, and:
"I think that it's extraordinarily important that we in computer science keep fun in computing"
Alan J. Perlis from Structure and Interpretation of Computer Programs
I truly believe that. But that's just me.
> No employer or client cares how happy you are writing software
False.
My employer and most of my clients care very much how happy I am writing software. This is precisely a reason I am able to go from one place to another and do Clojure, because I make it very clear that what makes me happy. I do Java at some places where my happiness does not benefit the client since it's almost impossible to find good (not remote) Clojure developers to maintain the code, but that's another story.
As joinr says, no need to worry about that warning (yet) but 2.9.6 is the latest version of Leiningen and it contains a number of bug fixes since 2.9.1 so it might be worth upgrading. See https://github.com/technomancy/leiningen/releases for details.
Most of the tutorials and books still feature Leiningen but you will also see books and tutorials -- and clojure.org itself -- refer to the Clojure CLI and deps.edn
files (instead of Leiningen's project.clj
file) so at this point I think it's worth learning the official clj
and clojure
commands as well as Leiningen since that's where a lot of the focus is now with newer tooling. See https://clojure.org/guides/deps_and_cli if you want to go down that path, assuming you're on macOS or Linux, or you're using WSL2 with Windows. The Clojure CLI doesn't have a good story for Windows CMD or Powershell yet.
Whatever you do, please don't repeat my mistake and start writing text files and then check the result in the browser or something. Even if you use figwheel, do REPL-driven development!
You can tinker around with the application state in the REPL with almost instant feedback! Use that to figure out how to make the details of your program work. Once it works, you can test it right in the repl with some sample data your make up. You can also easily do some quick performance checks. Once your're done, you can copy your code into a source file. You can also copy the test.
Writing your code like that from the start will have a great impact on how you design your stuff, how you represent your data, how you manage your state and also the granularity and testability of your functions.
It's a bit of a hassle, you have to learn how to properly use the REPL first. and you may think: "hey, my time is limited and I want to learn the important stuff first". But trust me, learn to do apply the workflow first. It will pay off every second you do the actual work that way later.
Super quick guide: Let's assume you have loaded some clojurescript source file "file.cljs" with the namespace "xy" that contains some (def x "y") How can you interact with it in the repl?
Check out: https://github.com/matthiasn/talk-transcripts/blob/master/Halloway_Stuart/REPLDrivenDevelopment.md
The next level is probably to use the Spec library (https://clojure.org/guides/spec). The idea is really neat: you use it to write composable expectations about data or functions ("specs"). You write them once and then you can use for three things:
SwiftKey recently released Clarity Keyboard Beta, which is written in Clojure and uses skummet. There is also a thread on the mailing list, but not much discussion.
If your initial goal is finding out if you want to learn Clojure, you should probably not be looking for ways to improve startup time, but learn how to use the REPL: https://clojure.org/guides/repl/introduction
I think that Steve's point has been widely misinterpreted as "Clojure should add every feature that users want" but that's unduly narrow. I believe his main point was that the way that many of the key people in the community react to suggestions that something could be changed is brusque to the point of being hostile. e.g. from the original Google Group thread: click click. It's even possible to say no while at least being empathetic to the user's pain. This is another good answer.
While the majority of the community is very helpful, I agree with his assessment and I think it hurts Clojure in the long run. There's been endless discussion around this and related problems in the mailing list and at every conference I've been to, but for better or for worse it doesn't look like it will ever change.
The Documentation covers this somewhat:
https://clojure.org/reference/datatypes
Basically you are right in that you can do nearly everything with maps. Types and Records create java classes, so there can be some performance gains on the JVM. They also help create clean interface based api's for Java consumers to interact with your Clojure data.
The documentation also indicated structs are pretty much superseded by records. Clojure values backwards compatibility, so it will stay around even though there is now a better way..
If your project uses leiningen then `lein uberjar` will create an executable jar file containing all dependencies.
If you are using the deps cli then I recommend looking into the new tools.build library https://clojure.org/guides/tools_build#_compiled_uberjar_application_build
I think this is a fair point and is mostly historical. Some libs, like spec, are dependencies of the language itself and should really be considered core, whereas things like core.match or core.cache are not. Something like core.async is somewhere in the middle. Unfortunately, it's not convenient to rename things. Hopefully the new doc at https://clojure.org/community/contrib_libs is a little clearer about the important buckets. On the upside, it's unlikely we'll make the problem any worse by making more "core" libraries. :)
>Note that recur is the only non-stack-consuming looping construct in Clojure. There is no tail-call optimization and the use of self-calls for looping of unknown bounds is discouraged. recur is functional and its use in tail-position is verified by the compiler.
I personally find Rails to be absolutely terrible. It's a huge frameworks and it's often very difficult to tell what effects calling a particular method will actually have. You either simply have to memorize things, or spend a lot of time learning ins and outs of Rails.
The amount of code that runs implicitly each time a request is served is mindboggling. The fact that it takes over 100k method calls ro render a Hello World page is absolutely insane.
On the other hand, the Ring stack is incredibly simple and you can know pretty much exactly what happens to a request when it's processed. I also much prefer being able to simply take a bunch of libraries that make sense for my application and glue them together to do what I need than figuring out how the framework designers expected me to do a particular workflow.
I also find that in most cases it makes more sense to do the presentation logic on the client as opposed to the traditional server side rendering. This is where things like Om and Reagent really shine. The server side becomes a very simple stateless service layer and there's simply no value in having a framework in that scenario.
I find library management with Leiningen to be far superior to anything I've seen with Ruby. Packaging and deploying Clojure apps is also much easier in my opinion.
I'd be really curious to hear from somebody who actually uses Rails as to what these supposed improvements actually are.
Boot coauthor (and longtime Leiningen user) here - I think
this message on the ClojureScript mailing list is an accurate comparison. The only technical inaccuracy in the message is ~/.profile.boot
is now ~/.boot/profile.boot
.
Boot does have robust shebang support, so it's possible to write standalone command-line scripts in Clojure. While useful, these scripts still incur Clojure startup time and are thus much slower than e.g. Python scripts to start.
I've been writing Clojure for over a decade (in production) and we started with Leiningen because there was no choice, then switched to Boot in 2015 because we wanted something more "programmable" with tasks being just Clojure functions, but we switched to the new CLI and deps.edn
sometime in 2018 and we're very happy with that change.
We switched away from Boot because we were running into performance issues with the fileset abstraction and also bugs in the pod machinery.
Even before the new CLI from Cognitect, Boot was already very much a niche tool compared to Leiningen. According to the State of Clojure 2020 https://clojure.org/news/2020/02/20/state-of-clojure-2020 85% of Clojure developers are using Leiningen still with the new CLI up to about 50% of Clojure developers (it's multiple choice). Boot was down to about 6%.
First, install the command line tools on your machine:
Then create a file named "cx" with the following contents:
#!/usr/bin/env clojure (print "x")
chmod +x ./cx
Then just run ./cx as normally.
Just in the interest of historical clarity... Stu Halloway is one of the founders of Relevance (along with Justin Gehtland), a consulting company that specialized in a variety of technologies. Stu became interested in Clojure as a post-Java language, made contact with Rich, and wrote the first Clojure book. Relevance eventually steered towards making Clojure their primary focus. Separately, Rich and Stu began the work on Datomic, under the banner of Metadata Partners. Ultimately, these two entities combined, forming what is now Cognitect.
Rich didn't write a book because Stu was writing one and they were working closely together to express the ideas of Clojure via that book.
I'm new, too, but the functions have started to stick. I use the same strategy I used in school: Don't memorize. If it's important enough to be used frequently, you'll remember it. If not, it's not worth remembering, as long as you know where to go to find it when you do need it.
As for where I go: https://clojure.org/api/cheatsheet and https://clojuredocs.org/clojure.core
> However F# keeps you in the windows ecosystem
Not necessarily. I haven't spent as much time with it as I'd like, but it worked pretty well from what I could tell. It's even in Debian, so it passes their reasonably strict free software requirements.
Love listening to Antonio's talks, and I've had a great experience introducing Clojure into our JavaScript stack by way of Lumo. One thing I didn't understand during this talk, however, is the claim that bundle splitting is weirdly magical in webpack land.
The point about special/magical comments is only slightly true; they can be used to name chunks, but for all practical purposes are entirely unnecessary[1]. We leverage bundle splitting quite heavily on our React application, and it's honestly a breeze. Webpack is smart enough to notice split points defined by dynamic import()
calls, and that's it, you're done. That ultimately frees you up from static configurations, which only become necessary for your primary entry point and static vendor bundle.
Looking at the ClojureScript way, it's still an improvement on how things were done (in CLJS) previously, but I struggle to see how it's objectively better than what's available in the larger ecosystem. Now, of course I absolutely adore Clojure and ClojureScript (I'm at the Conj, after all), and am pushing to work the latter further into our stack, but this claim seemed a bit hand-wavy.
I realize there is a permeating hatred of webpack and JavaScript tooling, but I do legitimately think there are some things that the community does quite well, and those things shouldn't be discounted just because of the stack. If ClojureScript does them better, awesome! I'm sure such rationale exists, but it is difficult to drill into such detail during a quick talk.
So, if I'm completely misguided here, I'd appreciate it somebody could help me understand the issue more clearly. There are of course great benefits to be had with the new module integration, such as Google Closure optimization, but this one point in particular stuck with me.
Definitely agreed there. While not Clojure, it was close enough while being small and fast. I used it to do some shell scripting stuff and it was really nice for that, though I started looking elsewhere for that (Planck and Lumo, Gauche Scheme) after development on it died out.
Despite that I still use something I made with it, and occasionally have to dig into the code to tweak it. I'd gotten tired of using a bunch of disparate nix commands, and nox didn't work correctly for me at the time, so as an excuse to spend some time with Pixie, I hacked together a vaguely apt-like wrapper (named nixie, naturally) to save me some trouble. After Pixie became a bit of a dead end I lost the motivation to polish and release it, but I still occasionally do some tweaking here and there if something comes up.
I noticed there's some activity on the pixie git again, so maybe it will pick up once more.
I am also new. I have been enjoying http://exercism.io/ The problems seem to give you one or two bites to chew on at a time. It doesn't give you any instruction, but I have been able to figure most everything out by looking through the Clojure cheatsheets etc. Once you have completed the projects you can browse everyone else's solutions and find quite a few better ways, or "why this way and not that way" to investigate.
I enjoy the various books, youtube lectures etc. but until you have enough real-world generated questions it is very hard to absorb and retain content. Once you have struggled through a few problems, solved it with great difficulty, when you see a better solution in a book or a "Don't do it that way, this way is better" it makes a lot more sense when you can relate it to you past victories and failures.
It is overwhelming, but if you keep at it pieces start falling into place.
Most of Rich's "content production" time for the last couple of years went into the History of Clojure paper if you haven't read that yet...
Can you implement fizzbuzz?
How about a simple text game like "guess the number"?
Any small, trivial task that requires you to express solutions (crappy or not) "in the language" is how you get experience and form connections. It's no different than learning a human language; you need to leverage cognates where possible, learn basic vocabulary, and start trying to form phrases. The nice thing is that you get to have a raher immediate conversation with the REPL.
How would you figure out the 13th odd number a collection?
These little things end up exposing you to the vocabulary and concepts of the language. I find solving little puzzles (combined with a cheat sheet of common functions and forms aka vocab) is of great pedagogical value. It also forces you to get mileage at the REPL, toy with stuff, see how it responds, etc. As you make progress on the little mundane stuff, the neurons start to click and you can refer back to your previous solutions to build up. You can even port solutions to problems you've solve in other languages, and see how they look in Clojure (hopefully following Clojure idioms and not trying to write mutable Java OOP in clojure just because).
I maintain a list of per-alpha dev releases at https://clojure.org/community/devchangelog. Really the only other work so far is prepl.
We are still working on the 1.10 plan but I suspect at this point that it will be shorter and focused more on bugs and compatibility than big new features.
1 and 3 are the same notation, but you're wrapping it into an anonymous function literal and added a type hint which helps avoiding reflection.
I don't know what the hash is doing in front of the type hint though. This does the same thing:
(map #(.length ^String %) v)
memfn
is a macro which expands to a function like examples 1 and 3, while (.foo x)
itself expands into (. x (foo))
which is the dot special form: https://clojure.org/reference/java_interop (special form means primitive baked into the compiler).
I don't see memfn
used a lot, but that's matter of taste. You can also add type hinting with memfn
:
(map (memfn ^String length) v)
It sounds like your boss has determined that getting the entire team on the same dev environment will lead to more productivity in the future, and he's willing to accept some initial slow-down in productivity in order to get there. It sucks, and personally I agree that you should be able to choose your own tools. Someone has already suggested cljfmt to scratch the formatting itch you mentioned - I wouldn't be surprised if you could add that as a git hook process.
However, if you are unable to convince him, I strongly recommend Spacemacs. It will give you a battle-tested emacs environment that is better than you can configure on your own and free you from the C-x bullshit. The Clojure layer is one of the best packages in the repo.
I was able to learn Spacemacs over a couple of weekends without any prior experience in Emacs and only marginal Vim knowledge. The docs and tutorials are superb, and the Slack channel is very friendly.
Best of luck!
I've been using Dash + Alfred integration for docs.
It's OS X only, but I get any doc I want within a few keystrokes even if I'm not in my repl. Pretty sweet.
Also, sorry, but I'm never a fan of clickbait titles. I just get an awful emotional reaction to them since I assume someone is trying to manipulate me.
You can use MELPA-stable (http://melpa-stable.milkbox.net/packages/) instead of the default MELPA; it has 0.7.0. However some of the packages there are old or non-existent (in particular the midje-mode there depends on slime, so breaks completely with cider).
However if you really want to stick to cider-0.7.0 then you could include both and then use package-load-list to pin to 0.7.0; I've never tried myself though, I just copied 0.7.0 into ~/.emacs.d/elpa/.
With Single Page Applications you're most likely to track part of the state of the client in the URL (eg. think https://mail.google.com/mail/u/0/#inbox and the #inbox tells Gmail that you're viewing the Inbox page).
The links on your app would change the fragment part of the URL (the part after the #) and Secretary would execute different functions based on the routes you define. Secretary is able also to extract certain info from the URL (parameters).
The functions you call at different routes in the client may also perform HTTP requests to the backend using a library such as cljs-ajax. These routes in the backend are defined using Compojure.
Here's a snippet of a client route in an app I built:
(defroute home-path "/home" [] (if (@user "email") (swap! user assoc :screen :home) (GET "/api/userinfo" {:handler (fn [data] (reset! user (assoc data :screen :home))) :error-handler (fn [response] (reset! user {:screen :home})) })))
So when the client goes to the URL "myserver:8000/#home" it performs an HTTP GET to the route /api/userinfo on the backend.
You might want to read this really nice write-up on Solving Sudoku by Peter Norvig. It tackles the topic gently, with working Python code that you can basically treat like pseudo code.
Peter Norvig is the co-author of "Artificial Intelligence: A Modern Approach" and he's pretty good at explaining this stuff clearly.
CoA maintainer here. Skummet works, it allowed Clarity to go from >10 seconds to 2-3 seconds startup without much effort.
Even without Skummet, startup time is reasonable for applications which don't have many dependencies, and that you don't start/restart often. E.g. 4Clojure takes around 4-5 seconds to load which is fine considering you launch it every once in a while.
I would suggest searching github for Clojure projects that use the premiere Clojure Neo4J library neocons. There is also a separate Google group for neocons that might be helpful.
Both Om and Reagent are fantastic, however I found Reagent to be much simpler than Om. I think it's a better fit for most applications especially for people starting out with Clojure web dev. I've blogged about some of the major differences here. There's also a great discussion on Google Groups on why some companies switched from Om to Reagent recently as well.
Keep in mind that Lisp has is also effectively compiled on traditional hardware architectures, and not just bespoke Lisp machines.
Trivia: 32-bit SPARC had tagged add and subtract instructions that worked on 30-bits of a 32-bit word size. The point of this was to give the machine a fast path for addition and subtraction of the tagged numbers often used in dynamically typed languages like Lisp and Smalltalk. The 64-bit SPARC removed these instructions.
https://groups.google.com/forum/#!topic/comp.arch/CElwU78HuwQ
https://cs.wmich.edu/~trenary/files/cs2230/GalleryOfInstr_HTML/taddcc.html
React.js in a type
data React s m i = React { render :: s -> HTML i, update :: i -> s -> m s }
Incremental React???
data DReact s m i = DReact { render :: s -> ds -> ΔHTML i, effect :: i -> s -> m ds, update :: s -> ds -> s }
Stuff is omitted obviously, but you can see the update function takes a state and delta-state to return a new state, and render takes a state and delta state to return a delta-HTML. That tells us quite a bit.
Source: https://www.slideshare.net/jdegoes/halogen-past-present-and-future
> I have a feeling chans are too heavy weight for event servers IO and you'd want to roll your own implementations as well but I'm not sure since I haven't actually done anything with it yet.
It sounds like you are debating threads vs event loops. I don't think your statements are accurate in regards to core.async, but I don't know enough to rebut it sufficiently.
Have you considered throwing this to the mailing list, where your statements could be answered/addressed by the people involved in core.async?
I think I'd write it like this: https://hastebin.com/riwizevoya.lisp
I'm using destructuring to cut down on the let
, a transducer to filter the comment stream, and I'm trying to write more general functions.
I've also put all logic into a function, so that the namespace can be loaded without it starting any background work. I've also moved the client from a def
to a let
for the same reason.
I'm also curious what these strange syntax constructs are too. I've only ever dipped my toes into Clojure, so all I've ever needed to use are keywords :key
, sets #{1 2 3}
, and thread-last ->>
.
Are there special characters or weird forms out there that aren't on the Clojure cheatsheet? How about strange, unintuitive combinations of them in idiomatic code? Something else?
What you're doing was how I learned through 4clojure. Viewing what others had done was the most enlightening way to learn of functions I had not come across. I also recommend checking out the cheatsheet for seeing many of the core functions all in one place.
Yes
source: https://clojure.org/news/2016/05/23/introducing-clojure-spec
> Improved Developer Experience
> Error messages from macros are a perennial challenge for new (and experienced) users of Clojure. Specs can be used to conform data in macros instead of using a custom parser. And Clojure’s macro expansion will automatically use specs, when present, to explain errors to users. This should result in a greatly improved experience for users when errors occur.
Also see https://clojure.org/about/spec
That's a nice hack. I wonder if OP realizes that he took all that time to write his post, but very few are going to read it because we get plenty of technical blog posts w/o subscribing to Medium, so why do it?
Related: Free Code Camp is leaving Medium for this reason: https://www.freecodecamp.org/forum/t/we-just-moved-off-of-medium-and-onto-freecodecamp-news-heres-how-you-can-use-it/279929
Have you considered using Postgres. It allows storing JSON documents using jsonb type that allows for efficient quering within the documents, and it provides JSON query functions. I find that this covers most of the cases I would use a NoSQL database for.
Have you tried IntelliJ IDEA (free Community edition) with Cursive (with the non-commercial, free license)?
Cursive supports features such as "Go to Definition" via static code analysis so you don't need a running REPL to do that.
`print` most definitely prints. It's hard to say without your actual code and knowing how your running it, but if I had to guess, you've probably discovered the joy of buffered streams. In many situations, both internal to your program (e.x. BufferedOutputStream) and external to your program (e.x. pipes in your shell), output will be buffered for performance reasons. In most cases the buffer will be flushed on newline (hence why `println` appears to work while `print` doesn't), when your program exits, or when the stream in closed. You can try forcing it by calling `flush`, but if it's a bash pipeline for example, that may not help.
> On that note, how is the book Clojure for the Brave & True? I've been working through that as well as looking up examples on how to do things online, but I feel like it does too much of "here's how to do this or use that, but we won't go into the details until 4 chapters later." Are they doing me a favor by doing this? Will this book set me up for being a professional Clojurian?
I don't think any one book will make you a pro. There are other Clojure books, some of them are listed in the sidebar, it may be worth investing into them. In the end though the only way to be a "pro Clojurian" is to write many lines of code.
> I've read about some people porting off, like AppCanary.
AppCanary person gave a talk about his Clojure experience. I think it's an interesting talk and at the same time a lot of it is not Clojure related. AppCanary's moral of the story IMO is the following: Don't use an unfamiliar technology stack if you're on a tight deadline. Use what you know.
> Also, I'm on #clojure on freenode often, it seems a lot of the best and most active guys there don't do Clojure professionally. But they said it's made them a better Java developer. What do y'all think about this?
This has been the case for me. Along with reading Effective Java by Bloch and Concurrency in Practice by Goetz.
A little off-topic, but the best critique I've seen of Clojure was Yegge's: https://groups.google.com/forum/#!msg/seajure/GLqhj_2915A/E0crn6zHLi0J
I've liked other lisps I've used (Common Lisp, Scheme, Racket, even Emacs lisp). Not so much with Clojure, in large part because it had very leaky abstractions of the underlying platform and was forever barfing up stack traces. It's a good language if your are very familiar with Java, want to solve the same problems Rich Hickey does, and agree with his rather rigid stances on the one right way to do things. Not so good otherwise.
There has been a discussion recently that should give you a starting point to answer that question.
In short, yes, there is interest in Clojure to native but not a great solution.
Quite welcome. I've gotten tripped up on similar issues plenty of times. It's generally a good place to check when you run into things hanging for no apparent reason on startup (on a server).
I'm definitely not an expert, but yeah, haveged is probably the best solution I'm aware of.
Here's a pretty good tutorial from the DO community on PRNG/entropy which happens to recommend havged: https://www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged
How? And I'm not trolling.
From what I can see this is basically Clojure to JS compilation but... you can not work with JVM libraries anymore (doh), no STM, no vars(!), functional programming with mutable data-structures, numbers are plain-old-javascript numbers, variables are plain-old-javascript variables. So this is like... alpha quality Clojure implementation for node.js people?
Also, pedestal-app (the client side part), is on not anymore actively developed, due to recent developments with core.async and Om.
https://groups.google.com/forum/#!topic/pedestal-users/jODwmJUIUcg
That quote was real and was from Chris Granger. It looks like the documentation effort may be entirely up to the community. At least, that's the impression I get from this thread: https://groups.google.com/forum/#!topic/light-table-discussion/HVgLv4G4Kzk
> "As far as I can tell the only place this is a real problem is mobile development."
Slow startup times might be bad for an AWS Lambda function and the like as well, especially if it's with API Gateway and a serverless app. But then ClojureScript might be alright?
Ok, so I actually submitted the issue myself some time ago. I've also prepared a basic code prototype and put it on GitHub, but the real problem is deployment. For some reason I can not get in touch with AI Challenge people on IRC (different timezone most likely, nobody is there when I'm trying to get in touch).
Some people, me included, tried to get Clojure into the previous edition, but failed due to admins not caring much, although there are signs of tampering in the compilation Python script, that suggest Clojure was being worked on. This time they started with heads-up early on, so I think we may have a fighting chance here.
Any help will be greatly appreciated.
From Leiningen, everything else is bootstrapped, isn't it?
curl https://github.com/technomancy/leiningen/raw/stable/bin/lein chmod 755 lein lein new helloworld cd helloworld lein deps lein repl
done
Cake has an extra step as it is installed via gem install cake
but othewise the above "instructions" should work for cake as well.
Hmm, maybe this is just because I'm not nearly as familiar with JS as I am CLJS, but there are lots of things that I think are far more painful in JS land:
- I can't eval stuff as the code is running (how am supposed to test handlers if I have to save and lose the app state every time I make a change)
- you can't map over an object e.g (for [[k v] {:foo "bar"}]...
- I don't think there is a good replacement for assoc/dissoc/update etc
- a bunch more small stupid things like 0 being falsy and commas etc
And then there's the editor experience, again, maybe comes down to experience but I am many times faster in a Clojure file than when working with JS. Is there anything like paredit in VSCode?
And as for the pain of integrating CLJS, it really isn't that bad at all. I definitely spent a lot more time slowed down by React Native/Expo issues than CLJS.
I have been playing a lot with tools outside the Clojure ecosystem and there definitely are a lot of things out there that just don't exist in the CLJS world.
I built my personal blog using this technique, and I don't see how you could achieve such a setup in Clojure (obviously it's technically possible, but realistically no company like Vercel is going to support such a thing).
Overall though, I will still pick Clojure for anything involving non-trivial data processing logic every time. I really believe that even for this simple 2-week project I saved time by using ClojureScript, and that advantage only gets bigger the more complex the application becomes.
There was an excellent talk on Mount given by its author at Clojure Remote conference. The abstract follows:
> Clojure is powerful, simple and fun. Depending on how the application state is managed, these 3 superpowers can either stay, go somewhat, or go completely. Apps we build for clients are quite different from tools and libraries on github; they are full of state. While there are frameworks that allow you to join the “application context party”, this talk will take a very different approach to manage and reload state with the help of a tiny library called “mount“.
> This exact point could also be made to support the 'fund more projects'-standpoint: with lower amounts someone can continue their project like they probably did before: as a side-project (but with the promotion within and recognition of the community). With higher amounts it becomes necessary to carve out a substantial amount of time - this requires a flexible day-job (and/or family).
No argument from me. :-)
> Too harsh indeed IMO: despite the amount increase, current funding is far from a real (ie durable, sustainable) solution to fund opensource work: it's limited in time, amount and only well-established opensource projects are eligible/selected. This means that with (hopefully) increasing funds the choice between more projects or more funding is inevitable, and a good discussion to have (and it's good to read that varying grants are in the pipeline).
Fingers crossed. We're definitely moving in the right direction, but there's a long journey ahead.
> With that being said, I'm grateful for Clojurists Together (& supporting individuals/companies) and I'm now heading over to https://opencollective.com/cider to donate the equivalent of a commercial IDE license. Thanks for creating and maintaining a great Clojure editor bozhidarb!
Thanks and you're welcome!
The stuff you can do with Haskell's types is interesting and it's worth learning (real life use-cases are basically going to be data science and some ML. Then there's stuff like xmonad.), but with Clojure and SBCL most of everything has been "Christ that makes so much sense" and "oh my God there's a macro for this thank you."
I am also a noob -- but I have been really enjoying the exercises at
Lots of little bite sized "puzzles" that are real programs you build in a real environment.. Occasionally you get helpful feedback as well -
This isn't so much a question, but can someone take a look at this short code and see if it looks alright? I'm new to Clojure. I want to make a reddit bot that searches comments for a regex match and pushes matches to an async loop.
Well, part of the work is sort of done...
​
On iOS, it already has the replete:// scheme registered, so all that is required is for the app to accept certain arguments and decide what to do with them.
​
Say, it could be that if you invoke replete://scipt1.cljs/arg1/arg2 it could invoke the script1.cljs with arguments arg1 & arg2. But some more code is required to handle that.
​
Pythonista already does something like that and at the end of the script, it invokes the new URL, which can be just a path to Shortcuts.
​
Not sure how this is done on Android platform.
I agree that it would be a large change, but it certainly would be very helpful to users.
A proper solution is obviously not trivial, but it's certainly is not intractable either. This is probably one of the most common time wasters for the developer, as you see a lot of silly errors all the time and you have to spend those extra seconds parsing them in your head.
I think a good example of the impact is Clang vs. GCC error reporting. Right now, Clojure reports errors like GCC and it causes pain and frustration to all the users on daily basis.
See those $? Those are labeled statements. Compiler recognizes them and just inserts appropriate code for invalidating/recomputing them.
Each year there is a community survey that asks Qs like these.
2021 State of Clojure full results: https://www.surveymonkey.com/results/SM-S2L8NR6K9/
Here's the clojure.org post about it, with links to every year's results: https://clojure.org/news/2021/04/06/state-of-clojure-2021
My own setup is:
deps.edn
stuffI haven't used Leiningen for about six years at this point (switching to Boot in 2015 and the CLI / deps.edn
in 2018).
Linux has about 37%. Windows with WSL has about 5%. Windows (without WSL) has about 5%. macOS has the rest (53%).
Your problem is first with the section of the code that states
((dec n) b (+ a b))
(dec n) returns a number, which you've put in front of an open parenthesis, so that number will be called as a function.
The broader problem with your code is that it would lead to a stack overflow exception with bigger aguments. Clojure cannot make use of tail call optimization with your code. You should take a look at: https://clojure.org/about/functional_programming#_recursive_looping
That said, simply replacing the recursive call to fibonacci-it with recur
should skip over that problem.
I did not design Clojure, so cannot give an authoritative answer to your "why" questions. The main reason I am responding is to point out that there are ordered set and map implementations for Clojure provided by the 'ordered' library here: https://github.com/clj-commons/ordered. It enables these to be printed and read using Clojure's tagged literals: https://clojure.org/reference/reader#tagged_literals
I think it's the Clojure information model, the overarching thesis of state and identity offers a different way to accomplish the same objectives
https://clojure.org/about/state
So "value oriented programming" (map, reduce, loop/recur, transformations ... things where you care about the shape of the value) would be a lower level mechanic than "identity oriented programming" (namespaced keywords, EDN, graphs, datoms, entities, datalog).
>Clojure running on JVM is a mildly interesting implementation detail.
I think this dramatically understates how central the JVM is to Clojure's fundamental nature. From clojure.org's Rationale:
>Clojure meets its goals by: embracing an industry-standard, open platform - the JVM; modernizing a venerable language - Lisp; fostering functional programming with immutable persistent data structures; and providing built-in concurrency support via software transactional memory and asynchronous agents.
The JVM is first in that list for a reason. More succinctly, Clojure is designed to be a hosted language, that host is the JVM (and JavaScript, and sort of the CLR), and working with the host (such as to use libraries) is central to Clojure's reason for being.
> Rust's version uses Rust's syntax; what's the difference beyond that?
That's not the case, which is the point. Outside of a macro, this is not syntactically valid to say nothing of having semantics at all.
I think some lisps (e.g. Scheme) can do that with reader macros (so that a custom reader is used to convert a form into a lisp structure), and clojure does have a way to dispatch to alternative reader macros but I don't know that it is possible for users to define their own reader macros.
Never tried or seen namespace aliasing done to import, I believe best you can do is (:import [some.namespace Class1 Class2])
and use Class1
without namespace.
You can do both (new Scanner *in*)
and (Scanner. *in*)
, see Java interop for cheat sheet. There are other fun things like memfn
and doto
that will be handy.
I've hit bumps in the road where I've told myself, "Wow, I wish I knew what was in this map" before. Working with Lacinia for instance, there is a large context map passed into all of the resolver functions in order to work with the graphQL engine. However, knowing that it's a HashMap<?, ?>
would not help a bit. What I was hoping for was either a document that said something like, 'Context is this ... blah' or a specification of what the map contained.
I'm not a fan of static type checking because it's rarely ever helped me as a human, mostly just helped my IDE (when I was using Java). However, I'm not against having some kind of type specification, i.e. Clojure.spec or docs, to make large structures more palatable.
Another tool that has helped me (and many others) is the REPL. Everyone talks about it but it's not always super clear on how to take advantage of it. The user
namespace, which you can define yourself on a 'per-project' basis, will be your best friend in development. I've used this to store example requests, context maps, data, etc... for development purposes without having to run a local DB to allow data to persist. A strong combination I've found is a dev-resources/dev-data.edn
file and something in the user
namespace to read it in and convert it to a Clojure map.
Most of my work revolves around parsing requests and GraphQL however, so 'big' maps are the thorn in my side. If you have any more specific questions (function input and return types are on many beginners minds') let me know!
> This has been canvassed elsewhere (it's fairly prominent on clojure.org - https://clojure.org/community/success_stories)
Do you mean specifically web programming? Or Clojure in general? I may be missing what you mean by "funnel."
One thing that I'm not seeing on that page is a lot of big names using Clojure for web programming, and even fewer (maybe none, I'd have to go back and count) using Clojure to create the sorts of CRUD-focused sites that frameworks like Rails and Django excel at.
And I don't think anybody is going to look at that list of success stories, and from that conclude that the web programming ecosystem around Clojure is as competitive as that around Rails or Django or even - say - Laravel.
One small thing is that lines 11 to 15 are ripe for associative destructuring.
Another is that doseq
lets you do binding and filtering like for does (with :when
and :let
).
Another is typically instead of single-branch if
forms we use when
.
Oh, and I'm not a huge fan of :refer
, especially when you're referring so many fns that you don't use.
Other than those stylistic / syntactic things, if you're doing this asynchronously for performance, you might want to have the relatively expensive operation of matching the regex to be inside the go loop rather than the main thread.
Would love to see a revised version if you can be bothered :)
You will still need 3 jars for most things. The load of core specs is now delayed till your first macroexpansion though. The new deps and Clojure scripts will ease this however - https://clojure.org/guides/deps_and_cli
> The fact that clojure.spec is explicitly opposed to type checking the corresponding values of keys in maps may be a deal-breaker for me...
The fact that "map specs should be of keysets only" does not mean that the values are not checked in spec, since we tend to tie the keys themselves to specs. In fact, validating entity maps is probably one of the most common use cases for spec: https://clojure.org/guides/spec#_entity_maps
I don't think I could do without it now that I know how expressive it is. I use it all the time to extract the keys I'm interested in using :keys, extract the first (and second and so on) element in a list in a concise way, and to find everything I want from a tuple-like structure (like a point).
I think the destructuring guide does a pretty great job of explaining how it works.
From: https://clojure.org/reference/datatypes
> fields can have type hints, and can be primitive > note that currently a type hint of a non-primitive type will not be used to constrain the field type nor the constructor arg, but will be used to optimize its use in the class methods
I verified with a quick gen-class test and using javap on the .class it spat out. As long as the type hint is for a primitive, a public field will be generated in the resulting class.
Really, though, especially in the case of defrecord, you should not be banging on the fields directly. You treat defrecords like a map on the Clojure side. If you need to hand a Java class off to someone else who's looking for explicit types, if primitives don't cut it you may need to write a small Java shim (which is a totally legit thing to do, many libraries that need sophisticated Java interop do this).
Hopefully that helps, let us know if you were asking a different question :)
Chart.js is pretty easy to use as well. Here's an example. Add the following dependency in project.clj
[cljsjs/chartjs "2.5.0-0"]
Then use it as follows:
(ns myapp.chart (:require [cljsjs.chartjs] [reagent.core :as r]))
(defn bar-chart [data] (fn [component] (let [node (r/dom-node component)] (js/Chart. node (clj->js {:type "bar" :data {:labels (map :title data) :datasets [{:label "data label" :data (map :value data)}]} :options {:scales {:xAxes [{:display false}]}}})))))
(defn chart-component [data] (when (not-empty @data) (r/create-class {:component-did-mount (bar-chart @data) :component-did-update (bar-chart @data) :render (fn [] [:canvas {:width "400px" :height "200px"}])})))
[chart-component (r/atom [{:title "foo" :value 10} {:title "bar" :value 20} {:title "baz" :value 30}])]
You first have to load the namespace using use
or require
, e.g:
lein new aproject
Generating a project called aproject based on the 'default' template.
The default template is intended for library projects, not applications.
To see other templates (app, plugin, etc), try lein help new
.
~/tmp/> cd aproject/
~/tmp/aproject> lein repl
nREPL server started on port 61427 on host 127.0.0.1 - nrepl://127.0.0.1:61427
REPL-y 0.3.5, nREPL 0.2.6
Clojure 1.6.0
Java HotSpot(TM) 64-Bit Server VM 1.8.0_25-b17
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e
user=> (use 'aproject.core) nil user=> (foo "Test") Test Hello, World! nil user=>
However, normally the way you'd work is to either open the repl from the editor or connect an editor to it. The simplest example would be with Light Table where you open up your aproject
folder in LT, then open a namespace from it and hit ctrl+enter
, or cmd+enter
on os x, at that point the editor will connect to the REPL and any functions you write you can send there for evaluation. The REPL keeps the state of the application and the editor knows what namespace you're working in. The REPL becomes an integral part of the development process as you can run any code you write in it directly.
There are differences between frege and haskell, so I'd bet against being able to use arbitrary haskell libraries from hackage.
This would seem to indicate that a JVM or .NET implementation is non-trivial.
There's also compiling to javascript, but I wouldn't expect that to run with arbitrary GHC code either - parallelism wouldn't work for instance.
> How has clojure been working out for you?
> I program mainly in Python and Ruby now-a-days and have been meaning to use > Clojure in real world projects.
Pretty much the same for me. My daily work is in mostly Python and HTML/CSS/JS and I've been looking for excuses to use Clojure.
> From what I have seen till now, Clojure is succinct and expressive, but I am > better off designing the app as multiple services, where Rails/Django/Flask do > what they do best(templating, orm, controller logic) and Clojure implements > backend services, communicating with the Ruby/Python code over message queue.
I think the main problem overall with using Clojure for webapps is that the libraries and ecosystem simply aren't as mature and aren't documented nearly enough. Python has libraries for damn near everything you could ever want to do, and most of them are fairly well documented.
When building this app and looking at Clojure libraries, a disturbing number of them said "look in the examples/ directory" instead of having documentation. Example code complements documentation but doesn't replace it. The Python community seems to get this, but it seems like the Clojure community is still working on it.
Some other libraries I saw at least have auto-generated API docs. At least those aren't completely useless, but they're still no replacement for hand-crafted documentation.
A good example: Noir has the best docs I've seen from any Clojure project. Compare it to one of its Python counterparts: Flask. It's no contest.
Yes, Flask has been around longer (I think...), but I still believe the main reason for the lack of Clojure documentation is the ecosystem/community. Python has had things like Sphinx, Django's documentation, and Read the Docs all encouraging programmers to create docs, while Clojure really hasn't.
Hi, I’m a co-author of the blog post.
Lambda will try to reuse the JVM process, rather than recreating it. Once your function is “warmed up”, you’ll only occasionally incur the container/JVM/Clojure startup penalty. https://aws.amazon.com/blogs/compute/container-reuse-in-lambda/
Anecdotally, I ran a relatively simple Clojure function today that runs for ~50ms in the worst case, but ~0.5-0.7ms once “warm”.
Also, sorry to hijack this for an unrelated thing but I don't know what the proper channel is for bug reports (the feedback page only lists feature requests), and I figure you would want to know that some of the shortcut keys repl.it uses aren't working.
The help page lists some console (repl) keybinds but they're not all valid. Specifically, can't use Ctrl+H or Ctrl+G in either Firefox or Chrome because they're both using them for history and search and that's taking priority over the page requesting them. Attempted to use binds in Conkeror since it doesn't hijack those keys and they didn't do anything at all.
Not sure if the help is outdated or there's a problem with the site, but figured someone should know. I noticed it because I was trying to bring up the examples list to see what you used for Clojure, but the examples link that's supposedly in header seems to be missing so I tried the shortcut and found it didn't work. Only way to get them seems to be the "Not sure what to do? Run some examples" message that's there before you start typing
He mentions boot2docker as the way to use docker on osx, but vagrant has supported docker since 1.6. I'm told it's the better way to go these days. https://www.vagrantup.com/blog/vagrant-1-6.html#features
New Seasons is a simple Noir site that notifies users when new seasons of their favorite TV shows hit iTunes.
I made it partly because I was annoyed at having to check iTunes for new seasons of shows I like all the time, and partly because I wanted to try putting together a small but useful app in Noir from start to finish.
I'm mostly a Python programmer and I threw this together in a few hours this week, so I'm sure there are lots of heinous things happening in the code. Feel free to comment on GitHub and tell me what I did wrong! :)
GitHub: http://github.com/sjl/newseasons BitBucket: http://bitbucket.org/sjl/newseasons
I would have to disagree. Effective Java is not a book for Java starters. Effective Java describes the best way to do certain things when you actually know Java. It's a great book for the serious Java programmer, but it's not for newbies.
>Since I am not a compsci degree holder, am I going to be over my head with Clojure and functional programming?
Absolutely not!
>Should I continue learning it?
Definitely!
(disclaimer: I'm a grad student in theoretical CS myself, so of course my answer is going to be very biased) I think you would benefit greatly from a deep understanding of functional programming. Try learning about the lambda-calculus (there are a lot of good overviews out there that aren't excessively technical), and how to encode the usual datatypes and functions (integers, booleans, comparison, etc) in it. This will help you understand exactly just how expressive plain functions are.
If you plan on using Typed Clojure, you might want to try and get a deeper understanding of type systems (a good introduction to the topic is Benjamin Pierce's Types and Programming Languages, although it might have too much math).
Finally, there's the excellent Structure and Interpretation of Computer Programs. I can't recommend this book enough. I think every serious programmer should read it at least once. Although it's written for a different dialect of Lisp (Scheme), translating it to Clojure should be more or less straightforward.
Couple things:
Not easy to do as a Closure novice, but I can at least relate the project I just worked on.
I've developed a robust framework in Java for actors using 2-way messaging http://www.agilewiki.org/projects/JActor2/index.html and as both a learning tool and a motivational device I decided to work on converting it to Clojure. After some study (a day, which is a long time seeing how I've only been looking at Closure for a week), I decided to build on Clojure core's agents.
For a first draft, I abandoned robustness and indeed any form of exception handling or performance considerations. The result was a set of code short enough to reasonably pass in an email: https://groups.google.com/forum/?hl=en#!topic/agilewikidevelopers/PCXdMm65mmE
In Java, this code would likely span multiple files and it would be difficult to rework when adding the additional features. The Clojure code is harder to read, but seems to be much easier to refactor--something I will need to do a lot of since there are so many features that are missing.
What I like is that there just is not that much code to read. And I do spend a lot of time reading code when I am working with it. I also did not feel like I was having to force the code to do unnatural acts, as nothing I did seemed to be that out of place for Clojure.
I do miss objects. But I found that dynamic vars were much more suitable to what I was doing than member variables. Mind, Java has all the equivalents. There is nothing (except maybe agents) that Clojure is providing that Java does not provide ample support for. But it just all seems to go together that much more smoothly than the Java code. And I've been programming in Java since they invented applets.
Ug, I've been thinking in common lisp macros, I believe if you change the second let
to
(let [~'channel (ssh-sftp session#)] ; rest as before )
It should work.
Addendum. The reason why this would work has to do with variable-name capture, channel
would expand into a fully qualified your.namespace/channel
variable whereas ~'channel
just expands into channel
without referencing the namespace. There's a thread about this very subject in the clojure mailing list.
I should have been clearer: manipulating classloaders correctly at run time is sufficiently tricky that it can produce unexpected behavior. Clojure used to have a clojure.core/add-classpath function, but it has been deprecated for years: https://groups.google.com/forum/m/#!topic/clojure/h_QO6HiNVN0
You (and the OP) can try the pomegranate project, it has a replacement. That said, as a fellow Common Lisp fan, I suggest just embracing the project-centric nature of JVM and Clojure development. It's just easier not to fight the established tools, most programs really are "projects", and once I'm working on one, I don't restart the REPL often at all.
Clojure runs on the JVM, and consequently, Java. The JVM cannot bootstrap Clojure code. When you run the java
command, it cannot be given a Clojure source file. Thus in order to have it run your Clojure code, you need a shim, that's what gen-class
is for.
So we want a Java class which will wrap our Clojure code, so that we can have it bootstrap our code. Clojure has a facility which helps you create this shim automatically, called gen-class
.
The most basic way to use it, is when you just want to wrap a main method. The first function called when a program starts. Thus you'd call java and tell it to load your Java main shim, and it will, in turn, load the Clojure runtime and call your Clojure main method.
The more advance use cases are when you need to have other entry points, that are not the main method, into your Clojure code. So say you have a Java program, and want to call into some Clojure code, again, you can use gen-class
to create a Shim that wraps a bunch of your Clojure code into a Java class.
It's important to note that gen-class
is a compiler directive. It tells the Clojure compiler to generate this class for you, thus it requires AOT.
Now, there are other ways to bootstrap Clojure code, mainly through the use of a launcher. Popular ones are using leiningen, boot, or the new clj command line tool. With a launcher tool such as those ones, you do not require a pre-compiled Java class shim, and thus can avoid needing AOT.
Unfortunately, it turns out that log4j2 plugins are not compatible with uberjars as described here.