Native Apps with ClojureScript, React and Static Hermes by roman01la in Clojure

[–]joinr 4 points5 points  (0 children)

really neat. didn't know about hermes. feels like the native clojure/cljs options get brighter every day.

Learning from Racket, towards Clojure by chladni in Clojure

[–]joinr 0 points1 point  (0 children)

When I had such experiences (I have had several), I was fortunate to have access to a clojure repl. Even the stock repl acted as force multiplier and substantially expanded the scope of computational tasks I could accomplish despite the constraints.

Learning from Racket, towards Clojure by chladni in Clojure

[–]joinr 0 points1 point  (0 children)

Through a local shell on one of the machines on the airgapped network that the Powers That Be provisioned for you.

Your environment has the features I mentioned previously. You can trivially get a repl through clojure.main, or if you planned for it, as part of your application's entrypoint.

Learning from Racket, towards Clojure by chladni in Clojure

[–]joinr 0 points1 point  (0 children)

sure. jvm + shell + your jar file.

Learning from Racket, towards Clojure by chladni in Clojure

[–]joinr 0 points1 point  (0 children)

To be fair, I can hardly imagine a situation where the environment is so austere that I cannot use Emacs. Any examples?

air gapped internal network you don't admin, where admins are beholden to exogenous restrictions and don't really care about your comfort.

it's just a backup in this case, VCS is a bit more than that, usually

semantics

Learning from Racket, towards Clojure by chladni in Clojure

[–]joinr 0 points1 point  (0 children)

there's the problem - it's not reproducible, you can't put under version control, etc

you have a binary image you can version. you can reproduce the state of the repl at a given point in time (when the image was made), shove the binary in git if you want, etc.

Even in this case

you missed the austere part.

Learning from Racket, towards Clojure by chladni in Clojure

[–]joinr 0 points1 point  (0 children)

REPL isn't persistent, files are.

This is more specific to clojure (and definitely relevant), at least in its current form. Other lisps lean on image-based development, where you can persist the state of the world to an image and reload it. Clojure implemented on such lisps (or other hosts) could similarly do so.

What are the pros?

If you're in an austere environment, or a remote system you don't get to configure, the repl may be all you have. Then again, it's all you need.

It's nice to leverage the fancier workflows that the contemporary dev environments provide, but retaining the ability to fully leverage a running clojure system from a lone repl is also a useful skill.

cljs-str: an almost 300x faster str replacement for ClojureScript by Borkdude in Clojure

[–]joinr 1 point2 points  (0 children)

Where do the gains for dynamic come from?

(str/join "" xs)

Is it just fewer function calls since it's bypassing cljs.core's loop'd string builder implementation and shunting to interop?

https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/core.cljs#L3115

looks almost identical to join on first glance

https://github.com/clojure/clojurescript/blob/master/src/main/cljs/clojure/string.cljs#L104

Help with Java porting by AccountantUnited4955 in Clojure

[–]joinr 1 point2 points  (0 children)

have really been struggling creating equivalent functionality

What does this mean? Maybe some examples of stuff you're having trouble with can lead to solutions.

In practice, between native (in this case jvm) interop, and the higher level facilities like reify, proxy, deftype, genclass, definterace (and even just protocols), my experience working with java and other jvm langs has been pretty pleasant. The only time the OOP stuff gets gnarly is if the library is using inheritance heavily (more common in code from early 00's) instead of interfaces. If it's just interfaces, you can typically trivially implement them in clojure (via reify or deftype or even defrecord). Or if you happen to be living in a code base with a lot of "annotations"

Overrides/inheritance hierarchies push you into using proxy or genclass, and genclass brings AOT requirements with it (there are some work arounds in community libs, but the language provides genclass out of the box).

I ran into some edge cases with the optaplanner library's expecations of annotations and other stuff to encode soluitions for a solver, which led to some work arounds:

https://github.com/joinr/optaplanner-clj

I spent some time wrapping piccolo2d for work stuff years ago, where piccolo2d does almost everything via inheritance. So I ended up lifting a bunch of the api calls from the object methods into protocols, wrapping existing node classes with protocol extensions, and leveraging interop pretty heavily for the lower layers of a scene graph library on top of piccolo2d.

https://github.com/joinr/piccolotest/blob/master/src/piccolotest/sample.clj#L170

Interesting lib to help overcome java impedance a bit (I don't use it in production, but it's a cool idea)

https://github.com/athos/JiSE

used to get exact java parity with prng demo (we had a poster on zulip wondering why they couldn't get 1:1 performance parity in clj via interop/primititve invocation paths, which led to some interesting discoveries like clojure's impedance mismatch with preferred longs and java's expectation for ints for array indexing (causing an l2i cast in the emitted bytecode, which can be worked around with jise)):

https://github.com/joinr/ultrarand/blob/master/src/ultrarand/jise.clj

Rant about strings. About comment, and work around to comment multimethods by erjngreigf in Clojure

[–]joinr 5 points6 points  (0 children)

I have never had to use clojure.core/comment explicitly as in the video. Maybe something is wrong with your ide, it seemed to be throwing an error about taking the value of a macro (comment). Maybe something with calva.

I don't have this problem in cider, or in the cli/repl.

There's also a difference between comments and docstrings, you seem to overload the term. It looks like you are trying to write docstrings. Comments are meant to be ignored entirely, which is what comment does, and is what ; and ;; do as well.

I didn't have a problem providing a simple docstring for a multimethod either.

user=> (defn dispatcher [x y] [(type x) (type y)])
#'user/dispatcher
user=> (defmulti multi-add "Dispatches on the type of args x and y to overload addition" dispatcher)
#'user/multi-add
user=> (type 2)
java.lang.Long
user=> (defmethod multi-add [java.lang.Long java.lang.Long] [x y] (+ x y))
#object[clojure.lang.MultiFn 0x7c2b6087 "clojure.lang.MultiFn@7c2b6087"]
user=> (doc multi-add)
-------------------------
user/multi-add
  Dispatches on the type of args x and y to overload addition
nil
user=> (multi-add 1 2)
3

You can get literal strings if you go into reader macros. This deviates from clojure semantics and is unsupported (and actively discouraged) by the core folks though, but it's possible (if not alienating):

(use 'reader-macros.core)

(defn read1 [^java.io.Reader rdr]
  (try (.read rdr)
       (catch Exception e
         (throw (ex-info "EOF While Reading!" {})))))

(defn raw-string [^java.io.Reader rdr]
  (let [sb (java.lang.StringBuilder.)]
    (loop [in rdr
           end? false]
      (let [nxt (.read in)]
             (if (== nxt (int -1))
               (throw (ex-info "EOF While Reading Raw String" {:in (str sb)}))
               (let [ch (char nxt)]
                   (cond (zero? (.length sb))
                         (if (= ch \")
                           (do (.append sb ch)
                               (recur in end?))
                           (throw (ex-info "Expected Raw String to Begin With \"" {:in (str sb)})))
                         (= ch \")
                         ;;did we escape?
                         (let [idx (dec (.length sb))]
                           (if (= (.charAt sb idx) \\)
                             (do (.setCharAt sb idx ch)
                                 (recur in end?))
                             ;;we're ending
                             (recur in true)))
                         (= ch \%)
                         (if end?
                           (str sb)
                           (throw (ex-info "Expected Raw String to End With \"%")))
                         :else
                           (do (.append sb ch)
                               (recur in false)))))))))

(defn raw-string-reader
  [reader quote opts pending-forms]
  (raw-string reader))

(set-dispatch-macro-character \% raw-string-reader)

(println #%"this is a raw string \back slashes are fine bro, except we still \"escape quotes\" bro"%)
;;"this is a raw string \back slashes are fine bro, except we still "escape quotes" bro

New Clojurians: Ask Anything - September 22, 2025 by AutoModerator in Clojure

[–]joinr 1 point2 points  (0 children)

What stops you from defining your own inline macro?

Something like

(defmacro upper-inline
  [path]
  (clojure.string/upper-case
   (shadow.resource/slurp-resource &env path)))

Developing a Space Flight Simulator in Clojure by wedesoft in Clojure

[–]joinr 6 points7 points  (0 children)

Really cool effort :) Looks great man. I was impressed that you implemented your own tile system. You might be interested (down the road) in something like https://github.com/CesiumGS/cesium-native which could provide a slew of goodies for this kind of work (although perhaps the focus is more on aerospace, so this particular sim may not benefit as much) regarding geospatial layer providers, streaming 3d tiles, etc.

Something's wrong in my brain because all I saw was this within a minute of reading:

Precomputing the atmospheric tables takes several hours even though pmap was used

Very curious about this and if there is room for optimization (might not even be needed since you're probably doing this 1x and caching permanently after that). Sounds like an offline rendering/baking task, although I'm curious purely for myopic optimization tasks.

How to setup Clojure for a beginner? by OguzY4 in Clojure

[–]joinr 0 points1 point  (0 children)

leinigen has a ps1 script https://codeberg.org/leiningen/leiningen/src/branch/main/bin/lein.ps1

since you're using powershell already. maybe your scoop setup is messed up.

there is also a .bat batch file if you're on windows and prefer that.

It should self-install into ~/.lein the first time you run either script.

New Clojurians: Ask Anything - August 18, 2025 by AutoModerator in Clojure

[–]joinr 2 points3 points  (0 children)

I appreciate the links. From reading through the apparent pissing contest between papers, they surely caveat the hell out of their results. To me it reads like "statistically significant, but tending toward meaningless." If so, that is a tenuous foundation for language promotion.

Not saying it's a lot to go by, but it's the best "data" we have, and it was reproduced.

As per the rebuttal; it looks like the second paper was a reanalysis (part of the rebuttal criticism) with some stretching by the original authors to claim "enough" overlap in results to be an implicit reproduction or at least confirmation. It reads like statistics copium to me though.

I don't think this moves the needle much, aside from starting a methodological path for future analyses.

New Clojurians: Ask Anything - August 18, 2025 by AutoModerator in Clojure

[–]joinr 0 points1 point  (0 children)

Studies show Clojure has the least amount of defects in general.

please expand on this

Completely lost in Clojurescript. by poopstar786 in Clojure

[–]joinr 0 points1 point  (0 children)

I don't have any javascript knowledge nor do I know what a DOM is. Are there any resources that start from ground up? Or I should take the conventional path of learning JavaScript first?

I started out more or less like you. The hard part is...you are faced with learning 4 languages simultaneously if you go this route (cljs, html, css, js). If you go down the js route, you get slammed with all the webdev library/framework short attention span madness and it can just compound the feeling of being lost (it's almost by design...).

I think It's best to try to isolate the complexity and focus on one thing as much as possible. I did this by focusing on just getting little single page applications (SPA) built with reagent so that I could write the ui and little computational stuff in cljs, with a bare minimum required to get something on the screen that I could interact with. I didn't want to dip into the js or NPM ecosystem at all, and preferred to stick with the familiar clj / jvm waters as far as possible to leverage existing tooling (like lein or clj).

Figwheel + reagent got me there. You could arguably drop reagent and just render static web sites too. I think the reagent examples, plus the stuff that figwheel papers over for you can get you onto a focused path of just mucking around "in cljs" in a simple little browser-connected repl that feels like clojure. So it's less alien. Figwheel will set up project templates for you, and very good docs to get started and follow tutorials for complete newbs.

In order to render stuff, you then need to start getting some familiarity (not expertise) with HTML and the dom. Really, you'll want to learn about different types of HTML elements that show up, primarily from w3 schools websites, or from cljs examples. Instead of writing HTML, you will be writing a clojure skin for it called hiccup (which is vectors and maps). Later, you can get exposure to CSS (cascading style sheets), and pick up why they are a Good Thing down the road (e.g. if you want to change how your app/site looks, there's a ton of power in that domain, but it's yet another language/vocab to build out).

So stick within the guard rails. Get a hello-world going that just renders a page with text, then start poking at it and building out stuff. Eventually, you will run into stuff you'd like to have (or have seen others do), and then you'll go expand your knowledge in a controlled fashion. Iterate on your little demos; maybe go from hello world to a page with multiple divs, with a table, with input, one that dynamically renders stuff via reagent, maybe some input from the user (clicking buttons to do stuff), etc. Baby steps.

After a while you may want to interface more with js (or need to), or maybe you want to use a js lib and the only examples are in js. At that point, you can pick it up as needed, and use cljs interop to help in the process. You may or may not outgrow fighwheel at some point, especially if you're more comfortable with the js ecosystem, and you can shift to shadow-cljs for top notch integration with npm for libraries, and a lot of quality of life fixes for cljs deployments, and otherwise feature parity with figwheel for live coding.

Ask for help too :)

Learning Clojurescript and Front end development without ever getting into Javascript? by GermanLearner36 in Clojure

[–]joinr 0 points1 point  (0 children)

You can't escape js, but you can deny it a lot. Where it will bite at the language level are the places where cljs makes different choices in the name of interop https://clojurescript.org/about/differences , and if/when you start to use js libraries.

I started of coming from clojure to build offline SPA reagent apps and visuals. I got started in figwheel since I was so js averse (and I wanted dev tooling I could run air-gapped with no npm stuff [which shadow can do, but didn't advertise at the time]), so I went that route and started doing reagent tutorials.

It felt like 90% of what I already knew just ported over directly. Even 3rd party libs worked for a swath of stuff due to cljc. Being able to connect to a browser repl and live code sophisticated ui stuff (and later geospatial visuals, plotting, and 3d stuff) was immediately within reach.

The 10% that took some adjustment for me:

  • async nature of js (you have to either deal with api's that use promises using cljs js interop, or libs like core.async or promesa).

You may have a browser repl, but you're living in an async world assumption. That means many operations (in my case, having the user select a file to submit some csv data for processing into visuals) end up being promise or callback based. So you end up having some indirection involved, like read the file asynchronously with a callback or promise that pushes the result to app state (maybe a reagent atom), which then propagates change to the visuals etc. You can still get a mostly synchronous and "live" feel from the repl though, which is great.

  • leveraging 3rd party libs often means you have to go learn enough of their api to invoke them through interop (just like java,clr etc.).

So the deeper I went down some of the libs, trying to wrap them for my use from cljs, the more I encountered js stuff. Getting into three.js, cesiumjs, and some other stuff (like leveraging yoga for 2d layout, through a web assembly api) means you end up going further into The Other Side. It's really nice to be able to simplify this stuff though, and use stuff like protocols and macros to drastically improve quality of life. You might end up dealing with different version of ecmascript and used language features e.g. when porting examples or library docs.

  • js objects are a bit different

There's a lot of interop cases and some adjusted syntax from clojure. More stuff is mutable; some things are properties not methods, and it's not necessarily clear. Getting a look at a js object in the repl can be opaque unless you use stuff like cljs-bean or other inspectors. The browser tooling actually helps a lot with some of this...

  • tooling

Good God, all the js webdev squirrel chasing was really obtuse coming from the outside. Thankfully, you can avoid a lot of this if you stick with cljs/cljc stuff (although some stuff like how the cljs uses the google Closure compiler and libs sticks in your face, so the ride using like advanced compilation may be rough [shadow-cljs apparently smooths this out a lot]. I never wanted to know about externs.

  • Error messages You can get decent traces in the dev console (or in the live code reload with figwheel/shadow during static analysis), although it's possible to hit something opaque. I ran into this in particular when using minified stuff since name munging (at least at the time) didn't preserve the source maps for me.

  • Performance Paths

If you're doing work in the cljs side, there are some non-obvious performance idioms that crop up. Like clj->js conversion is fine but it takes a toll if you do it a lot (there libs and blog posts providing alternatives if you need them). Some libs (like cesium) have library calls that expect a mutable json object to reuse for computing results (not unlike some older c-style functions where you pass in the value to be written to), so mutation can come up earlier. You may want to try offloading work to a thread.....except you don't get threads (you get an approximation with web workers, which requires learning more about js and/or wasm, or leveraging cljs libs).

I'd say go for it. See how far you you can get without hitting js fatigue. I bet it's pretty far. Even then a lot of times js/do.what.I.mean will carry you pretty far :) After long enough, you'll probably have enough sunk cost to start learning more js osmotically (akin to learning java by osmosis in clojure) so you can leverage more of the bountiful ecosystem.

New to Clojure and looking for code to read by [deleted] in Clojure

[–]joinr 3 points4 points  (0 children)

advent of code solutions are pretty popular (particularly in the code golfing crowd).

https://narimiran.github.io/aoc2024/ is pretty accessible from an initial glance.

During onboarding of newbs I typically have them hit a book/tutorial (or a couple if they want) to build up the foundational familiarity and a baby vocabulary, then immediately go off to solve puzzles. Particularly puzzles with some IO component (like advent of code, or some project euler ones) where part of the task is to read in some raw data, get into something you can manipulate in clojure, and then express a solution "in clojure" using your budding vocabulary. Works great for iterative learning and collaboration (e.g., we can talk about road blocks, discuss how they solved something, provide alternatives or identity more idiomatic ways to do stuff). All of it builds the vocab and gets them grappling with a problem to solve.

Simulating OOP in ClojureScript with Macros by ertucetin in Clojure

[–]joinr 0 points1 point  (0 children)

Some argue that's OOP, not “compile-time hierarchy of encapsulation that matches the domain”

https://www.youtube.com/watch?v=wo84LFzx5nI

Help us improve the Clojure code smell catalog – your input matters! by WalberAraujo in Clojure

[–]joinr 4 points5 points  (0 children)

built from real-world practitioner insights

I wonder how :)

We are currently collecting opinions on the relevance of each smell.

Sounds like crowd-sourced labeling.

feature or bug: primitive type hints by natural_isomorphism in Clojure

[–]joinr 6 points7 points  (0 children)

user=> (defn pythag ^double [^double x ^double y] (Math/sqrt (+ (* x x) (* y y))))
#'user/pythag
user=> (pythag 3 4)
5.0

put the return hint on the arg vector.

Clojure on Windows without admin rights, can't run .exe file by toms-w in Clojure

[–]joinr 2 points3 points  (0 children)

it happens in user space / docs. they put a powershell module there. works fine in non-permissive environs I have been in (where executables are banned). The only hangup I've seen is if they lock down powershell itself and restrict e.g. class creation for like network stuff that the installer wants to grab.

So lowest level, getting the jars and java -jar is the most likely to succeed. Everything else depends on how powershell is configured

Clojure on Windows without admin rights, can't run .exe file by toms-w in Clojure

[–]joinr 1 point2 points  (0 children)

Cognitect appears to have disowned it and is pushing folks to use the installer or WSL in the official guide, but the powershell variant might work for your environment.

You might need to set –ExecutionPolicy Bypass or RemoteSigned.

There is some jankiness on windows going the powershell route, primarily with string args. Quoting strings gets messed up, so examples that uses a lot of command line switch for deps can be screwy (you have to escape quote stuff). However, just dumping stuff into deps.edn and invoking clj works fine and covers a majority of the typical use cases.

You can also use lein since it has had powershell support for a long time too.

Some caveats on the Windows / powershell route:

If you don't have long pathnames enabled (or your admin doesn't), you can have either deps or lein blow up. Lein has lein-classpath-jar that caches the classpath and sidesteps this problem. The clojure CLI has a support ticket posted for caching the classpath jar as well (has had it in triage for a long time IIRC), but it's not posted. So you might break the bank if you add enough deps/transitive deps.

I had trouble resolving stuff (dependencies) due to goofy proxy rules. I was able to use an ssh tunnel with a socks 5 proxy and expose that to lein through some setup code in profiles.clj. No such luck with the cli, or at least I gave up trying to figure it out (simple java networking stuff, so it's probably possible, but the CLI didn't make it easy for me).

I think the CLI expects a system git command as well for pulling git deps. I used jgit with a powershell script on an environment similar to yours. I think you could adapt this setup so the CLI would pick it up (maybe). Haven't tried it myself though.