Fork me on GitHub

For writing web-based presentational elements, what does everyone prefer writing in? [html/xml/jsx, hiccup, django/templating type, pug, markdown, org] ?


I'm thinking about putting together a "simple" web framework, where the most common user base could write dynamic pages without ever firing up a repl or having to deal with dependency management etc., by supporting a custom read/evaluator that works on files of this form:

(use 'hiccup.core)

         (defn input [name]
           (html [:label {:class (str name "-label")}
             [:input {:name name :type "text"}]]))

         (def pinput (comp println input))

         <!DOCTYPE html>
             <title>You can freely mix html and hiccup just fine.</title>
             <form name='my-form'>
               (println (format "Hello %s, thanks for visiting!" (:name request)))
               (pinput "username")
               (pinput "password")
             </form name='my-form'>


sort of a callback to the early days of PHP, when things were very easy for new programmers


@m131 It depends. If I want to work closely with front end folks, I like the Django-style HTML templating that yogthos/Selmer offers. If I'm generating HTML from data that doesn't need interaction with frontend folks, then Hiccup is nice.


I want to make a system that doesn't rely on all the busy work of compojure/other routes, that will just leverage the host OS filesystem for that - so, something in /greetings/hello.clj would contain that content up above, and produce the appropriate html


We had one process that used Hiccup extensively and had to switch it to Selmer when our UI/UX czar redesigned the website... that was not actually as painful as I was expecting: instead of using Hiccup to turn data into HTML, we just simplified the data a bit and then transformed it into the raw data needed for Selmer.


in my day job I'm doing a ton of front end react spa stuff, and a variety of php/typescript apis to support it on the backend, and I feel like (even with clojure luminus) 90% of work is busy-work, of writing php symfony type framework code, where a route calls / maps to a controller, which maps to a service, which maps to a repo, which calls to a database and serializes into a model. All for a glorified "custom database skin"


I wrote a small, simple MVC framework (for CFML) that relied on conventions to match /section/item style URLs to handlers and HTML views (and has a cascading layout wrapper based on the same structure). I ported it to Clojure and we used it at work for a while. Feel free to read and steal ideas from it:


nice ty 🙂


I can't remember what state it ended up in before I decided to sunset it but it may give you ideas...


(it was the one of the top two MVC frameworks in CFML back in the day)


cold fusion markup language? (sorry, I probably could have google in the time I asked)


Yeah, CFML = ColdFusion. You'll want to look at the v0.10.2 version of the code I think -- that has the usermanager example that is still FW/1-based and uses conventions. As I was sunsetting the framework, I rewrote it to use Compojure routes (instead of FW/1 conventions).


btw, this is another question in a slightly related domain/thought - I notice a few different attempts at a faster clojure bootup experience, usually by rewriting a subset of clojure (babushka bb, or joker etc.) - while very useful, why isn't there (or perhaps there is) a paradigm out there that just involves running a persistent clojure jvm that imports many many dependencies at once, and then over socket, you tell it a script location on server, like "~/bin/foo.clj", and it just reads and evals the file?


almost as if one big clojure jvm is equivalent to a mini OS


Several people have built such a thing but they've never really caught on.


interesting, I wonder why, as when I was reading some of the various state-of-clojure stuff throughout the years, the most repeated complaint was "slow startup time"


For development, I think most people eventually get to a place where they start a REPL and leave it running for days (or weeks) and just work within that. For production, at least for long-running server processes, again who cares about startup time?


I probably only restart my REPL/REBL combo once a week at most.


yea, this would definitely be a niche for writing local utilities that are primarily used on cli


Even for CLI utilities, I don't find Clojure's startup time too annoying -- assuming I don't have a lot of dependencies...


I recently wrote a C module for the janet language (a close-to-C clojure-like) that involved forking, and obviously a by product of C fork is the entire memory gets copied. Is there a best-way to do similar in clojure? if I wanted to perhaps do a fork() and then an eval, to ensure the eval executes in an isolated env?


Threads are the closest on the JVM I think.



(! 578)-> time bin/
Time is now 2019-09-07T03:23:15.487Z

real	0m1.913s
user	0m5.059s
sys	0m0.218s

Fri Sep 06 20:23:15
(! 579)-> cat bin/ 
#!/usr/bin/env clojure -Sdeps {:deps,{clj-time,{:mvn/version,"0.14.2"}}}
(require '[clj-time.core :as t])
(println (str "Time is now " (t/now)))

Fri Sep 06 20:23:19
(! 580)-> 


I think the "run .clj files as if they were running over mod_php or CGI" and "run .clj files as if they were shell files" has a lot of overlap, but in either case, before I execute the clj, I would want to scoop up the entire existing environment and execute in a new pid that just discards all the stuff after


what was neat in the janet experiment, I was able to use mmap to relay the fork results back to the parent pid


without serializing the entire janet ENV VM stack


Two seconds for a "simple" script... if the script has few dependencies and does a fair bit of heavy lifting, the startup time is not really an issue.


(ultimately it was to implement futures in that lang, since it has no concurrency or parellelism support)


If I want a fast CLI "script", I just write bash 🙂


well, its not terrible, ultimately its a balance of work done vs startup time - if I wanted to reimplement a lot of the shell toolchain (ls, grep etc.) in clojure, each pipe target would add up


"a lot of the shell toolchain" -- then just start a REPL and use it as your "shell"


Don't context shift between bash and the JVM for every command. That makes no sense.


That was one of the intriguing things about Boot, compared to Leiningen. With Boot you could start a REPL in your project and then run all the Boot tasks in your REPL.


You paid the startup time once, and then it was your new "shell".


well, a more seamless integration is my idea - I notice very few clojure apps available in various *nix distro package managers for instance


Very few JVM apps period, I would expect.


and I see a lot of stuff for rust rewriting old tools like grep -> ripgrep with performance boosts - I bet clojure could do better


but, to pull people out of their established environments into brand new ones, lots of people seem to avoid lisps


It's nothing to do with Lisps really, it's about the JVM. If you want fast command-line stuff that gets run a lot, you don't use a JVM language.


Rust, C, C++ -- they all benefit from tightly managing their own memory (and Rust makes that easier/safer because of the borrow checker). If I was writing stuff that targeted native code for speed, and wanted fast startup, I'd write in Rust. I like Rust.


Clojure is designed to be used wherever Java is suitable. Not everywhere. There are places where Java is not suitable 🙂


I'm sure its a compound problem (jvm and lisp) - its funny, those in that space would tend to view both as a positive, those outside it, view both as a negative


I don't think theres many lisp things at all though in *nix land - stumpwm / common lisp, maybe gnu cash with scheme as the scripting engine


emacs obviously


I've been entirely based on the JVM for about 22 years. Beyond my attempts to "learn a new (programming) language every year" I haven't even looked at Lisps elsewhere.


I did learn Go (didn't like it) and Rust (loved it). Also Elm (but I don't do front end work, just like I don't do native/command line work).


nice, I tend to language hop but (despite coworker and community interest) have avoided rust a bit - I've been very down the lisp-hole (basic -> C -> c++/java -> php -> js -> common lisp / emacs lisp -> prolog -> clojure) - very lightly tinkered with scheme dialects and haskell and erlang, but I always settle into the lisp things the most and they hold my interest the best by far


well, I'm not so sure it matters the lisp as much as the tight repl driven development that I enjoy


I wonder if a jvm process calls a C jni / jna / jnr or whatever they're at now, and that calls fork(), if the jvm ends up duplicated or if it generates a nice big segfault


My first Lisp experience was in... 1982 I think?


hah you have some years on me, that was the same year i was born - my light basic tinkering was sometime early 90s I want to say


I'm glad to see a bit of a lisp resurgence though (well, maybe my media bias makes it seem its so)


My final year project at uni was to write an APL interpreter (in Pascal!) and my best friend wrote a Lisp interpreter (also in Pascal). Then I stayed on for a PhD in functional programming (language design and implementation) so I wrote another Lisp interpreter as the basis for that and then built a series of ML-like languages on top of it (so Lisp was my "assembler"). Back then I was doing SASL, Miranda, ML... as well as lots of Pascal and assembler (and some BASIC). When Haskell finally appeared as the culmination of all the university FP language experimentation, I was convinced it was going to take over the world! Hahaha...


Meanwhile I got a job writing assembler and COBOL, then more assembler, and then C, C++, Java, CFML, Groovy, Scala, and finally Clojure (with a bunch of other niche languages along the way -- I worked for an actuarial company for a few months that used Prolog heavily, as well as Parallel C for the Inmos Transputer -- that was fun).


lol - well, maybe in time, functional languages seem to be on a slow upward trend


Yeah, every language is sprouting functional features. I've actually given talks at CFML conferences about functional programming in CFML 🙂


have you ever found yourself using prolog paradigms like logic programming outside of the actual "prolog" space? (with other language prolog implementations etc)


No, I've only really used Prolog for that sort of stuff.


I love the description of Prolog in the Seven Languages book as a two year old child. You ask it a question and you either get the answer or just "no" 🙂


"How old are you?" "no"


so accurate


I did play with core.logic a bit when I was learning Clojure but it just doesn't really fit any of the problems I'm solving. But then I really use Clojure as a general purpose language for mostly boring stuff.


Going back to CFML for a minute... 🙂 🙂


nice! that's pretty slick

ahungry04:09:54 - so, it doesn't seem (at a cursory glance) there is any inherent limitation or blocker at the java/jvm level that explicitly prohibits forking - the toy program seems to show the correct behavior


now to sprinkle on a little clojure


I believe calling fork will break the jvm


I haven't used jni much, but I seem to recall you can end up with a jvm where non-existent threads are holding locks, etc


(if (= 0 (HelloJNI/forkYea)) "child" "parent")
         All done?                                                                                                                                                        
         All done?                                                                                                                                                        


it does seem to be inconsistent/odd when running via lein run, but I think it may have some untapped potential


Fork gives you the same memory, but not the same threads, so for example your child jvm doesn't have a GC thread running


thanks, I definitely appreciate all info regarding this - is what I'm toying with atm - I think if I want to mimic the old mod_php - a lack of GC is just fine, the forked process would be a short-lived eval and die type thing


same for a CLI launcher that I want to avoid having the long-lived host "corrupted" by requesters running against it


When I use lein run, the for-loop doesn't not run unless I will println it. Why is it?


for is lazy


if you want to force evaluation of side effects, use doseq or run!

💯 4

forcing a lazy seq can be done using doall


How to use clojure.spec.alpha/fdef, I define some specs for a function, but when run it, the specs doesn't work:

(defn like [name]
  (println name))

(s/fdef like
        :args int?)
(like "apple")
;; just print apple
And the format works for macro.


have you used instrument to enable the fdefs?


@sogaiu It's a great job. Thank you~


related, if you want to unit test your fdef: 😉