Fork me on GitHub

There was a discussion in HN a while ago where one guy was claiming Clojure is transpiled to Java classes and the other claiming it targets the JVM directly. Who is right?


Clojure compiles everything to JVM bytecode -- which is classes at the compiled level. By default, Clojure compiles code in-memory, producing classes in memory. You can ask Clojure to write those classes to disk as .class files.


So maybe the guy claiming Java classes meant JVM classes rather than Java source code?


What is the difference between JVM and Java classes?


I'm trying to draw the distinction between "Java classes" possibly meaning "source code containing a class { ... } definition" and "JVM classes" meaning "bytecode that defines a class (in memory or on disk)".


"Though I started by targeting both the JVM and CLR, via generation of Java and C# source, by the end of 2006 I had decided I wanted to accomplish twice as much rather than do everything twice, so I decided to target only the JVM moving forward. That choice was driven by the much stronger open source library ecosystem of Java and the more dynamic nature of the JVM, e.g., HotSpot optimizations [Click and Rose 2002]. The compiler was moved to Java and eventually (prior to release) generated bytecode directly" -- Rich Hickey, History of Clojure (from )


What is the difference between JVM and Java classes?


First time I hear about JVM classes 🙂


Clojure targets the JVM, not Java 🙂 The JVM has classes. Java (source) classes compile to JVM (bytecode) classes.

Ben Sless06:06:42

I'm still fascinated by the similarities between the JVM and lisp machines


Yeah, the VM architecture was nothing new but folks didn't seem to take it seriously until Java broke out. I'd been working with VM systems for almost a decade before Java appeared.

Ben Sless07:06:13

Is it a commonality among VMs in general or the JVM and lisp machines in particular? From my understanding, some of the main features of lisp machines were tagged objects in memory, all memory space is shared, stack based, GCed. It looks very similar to the JVM with its objects, heap, stack and GC. Haven't looked into other VMs' architecture to know if this similarity runs across all of them. Which ones did you work with?


UCSD P-System was one of them. I ported it to several new architectures (including Sun SPARC back in the day).


I also worked with a VM-based COBOL system (again porting the compiler and runtime to new platforms).


Clojure namespaces compile to JVM (bytecode) classes and each function also compiles to a class with a static .invoke() method etc.


Aha, got it. Thanks.

Mahran Yousef05:06:35

Hi all, I want to ask if it is possible to use libpython-clj in windows. I've been trying to figure out the :library-path for the (py/initialize!) function but it seems that there is no way to find it in windows.


@myousef23 There's a #libpython-clj channel which might be able to help you.


In CLJS, using clojure.test, I have a series of tests that need to use with-redefs (several vars), but also rely on a setup and teardown using use-fixtures. I'd rather not copy/paste the with-redefs inside every deftest. But when I wrap the deftest in with-redefs, the vars aren't actually redef'd.


@U70QFSCG2 Can you share some code? I'm having a hard time visualizing what it looks like based on your description.


sounds like (with-redefs [#'foo bar] (deftest ...)) which of course is a no-op, since deftest sees the real #'foo when it runs


you can compose fixtures and set up redefs as a fixture even better, you can write code that can be tested without with-redefs


Am I doomed to just repeat the with-redefs?


it is ok for pure functions to throw exceptions that enforce some business logic?

Timur Latypoff13:06:30

Division by zero throws an exception. I think throwing exception is fine as long as some preconditions for the function are not met (that is, the programmer made a mistake by using the function in a wrong place).

👍 3
agata_anastazja (she/her)13:06:31

Is anyone from the mentors here also active as a mentor on exercism?


How can I ask the REPL to revaluate everything? For example, I seed my dev DB with the following commands:

(in-ns 'myproj.db.seed)
(clojure.core/load-file "src/clj/myproj/db/seed.clj")
When I make changes to myproj.db.seed, they are automatically picked if I rerun the above lines. But if I change myproj.db.reset NS which is used by myproj.db.seed, I have to load that file (`myproj.db.reset`) first for the REPL to detect the changes.


instead of load-file, you can use (require 'myproj.db.seed :reload-all)


there are tools to automate reloads, but that will get you pretty far as a beginner


It worked perfectly. Thanks. It was such a pain 🙂


what most people do: edit code, hit the key command to send the top level definition to the repl. then you don't need to worry about reloading, in-ns, requiring, etc


Working on it. I just find Cursive key mappings all messed up. Maybe because I use other JetBrains IDEs and there are many conflicts. I am resetting them little by little.


the automation is great, but I think there's a value to learning the clojure-only version first - having a deeper understanding of what part of your workflow is the language and which part is the third party dev time tool


that's a very good point. being able to get around a simple clj repl and how to load, reload, doc, javadoc, etc. is quite nice


and extremely useful when you get a weird prod bug and know you can just use an extra jvm system property to get a repl into the running process


(while a coworker who only uses knows $EDITOR integration is stuck on how to run editor on prod or maybe tunnel but the prod image doesn't have nrepl etc. etc.)


all that said, I use editor integration too these days, but I got away with avoiding it for a very long time


Working on it. I just find Cursive key mappings all messed up. Maybe because I use other JetBrains IDEs and there are many conflicts. I am resetting them little by little.


i could live without it if there were a good send form to repl across processes.


that's what the socket repl is for right?


with that, you can use nc to send code and get a result back


i mean a keybinding from emacs to send it to the running process. i did a big pass over inf-clojure to get it very close to that


ahh - just call nc :D


in vim it looks like :w !nc localhost port, which just does the right thing if there's a selected region, otherwise sends the whole file


anyway, real editor integrations do things that doesn't of course, and some of those things are very nice


Curious question: what are ya'll deploy workflows? I guess we use compute engine / ec2 + docker? k8s? What kind of infra do ya'll use? Any recommended resources?


I use uberjar inside docker, I miss using bare uberjars + jsvc TBH

👍 3

the docker image gets run in marathon but we are going to move to k8s


I definitely see the advantage of docker if you need native deps, or want to mix clojure apps in with ruby / python etc.


but if you use clojure everywhere without native deps, uberjar + jsvc just works


though I haven't had to use cluster management like marathon with uberjars, maybe docker does make that simpler(?)


Follow on question (which I asked on the Discord yesterday, and got some info from, but interested in more perspectives) - any recommendations on free/cheap hosting providers for a simple 100% Clojure app that isn’t a webapp (it’s a once-every-24hr job that calls some REST APIs then posts a message to a chat server)?


hey @U0MDMDYR3, the java11 google cloud function support is out now and if you combine it with, that might be a good fit too.

👍 3

Awesome - thanks for the suggestion! I remembered my app will also have a (small) on-demand portion - it’s a chat bot that mostly sends timed chat messages, but I’m planning on adding a couple of responsive functions too. So in the end it made more sense to continue implementing it as a self-contained, long-running app that manages its own scheduled tasks, and in the end I just sprang for a “hobby” Heroku subscription ($7 / month).


I’ve used Heroku in the past, and it’s super simple to setup (no need to mess with docker or containers or any of that incidental complexity), so it was the path of least resistance. One slight gotcha that had me stuck for a little while, for anyone who happens to read this and decided to use Heroku:


^ ya, looks like the clojure build pack doesn't seem too far off from supporting a deps.edn only repository.


@U0MDMDYR3 the company I work at actually does host clojurescript chatbots, but we only support Slack and MSTeams today. When users talk to the bot, or click buttons (or whatever other interactive elements you put into the message), we route these messages back into function so that we can continue to utilize serverless runtimes. I guess you're building for Discord though, eh? We don't support that unfortunately. But if you were building for either Slack or MSTeams, I'd certainly send you an invite. Beyond the interactive message stuff, we also have support for waking the bot up on a schedule. Seems like it might "almost" be a fit.


Yeah this bot is for Discord. The idea of routing messages to functions is awesome though!


I'll let you know if we end up supporting Discord.

💯 3

for something standalone that you only run once a day, check out heroku, they do make clojure deploys easy (git based workflow) and that kind of usage shouldn't end up costing much

👍 3

Thanks - yeah I’ve already got a teeny little Clojure webapp deployed up on Heroku, and have found it easy to work with. My only concern is the “dyno sleep” behaviour on the free tier, and the fact that my job will be asleep 99.99% of the time.


Not quite sure how to wake the dyno up (currently the app runs all the time, and uses the chime library for job management).


Check Heroku scheduler add-on

👍 3

Thanks @U6N4HSMFW - that might be exactly what I’m after!

🙂 3

I would be tempted to create an aws step function that waits 24 hours, then invokes a lambda which spins up an ec2 instance, which starts your clojure code, then waits for your clojure code to exit, then shuts down the ec2 node, then loops


the step function and lambda would almost certainly end up in the free tier because they would be doing so little


Good idea. It may even be possible to implement the job itself as a lambda (don’t know much about that technology, except at a high level).


Though it does need disk access (it generates a PDF file from the results of the REST API calls, then posts that to a chat).


Not hard to access the filesystem within a lambda if required, or even to persist the file to an S3 bucket. As hiredman said, easily within the free tier if you don't run this thing too frequently.

👍 3

Thanks! And yeah right now it’s a once-in-24hrs thing, though it might involve into a “dozen times a day or so” type of thing.


I keep seeing people recommend in clojurians


Thanks - I’ll check it out!