/tech/ - Tech


Mode: Reply

Max message length: 8192


Max file size: 20.00 MB

Max files: 3


(used to delete files and postings)


Remember to follow the rules

clojure Comrade 08/06/2019 (Tue) 04:54:14 No. 2638
what does bunkerchan think of clojure?

its a lisp that actually works for web dev and other SW dev in the modern day.

never seriously tried lisp. might have a go at it soon. I'm currently sinking all my free time on haskell though. fantastic language, shame it's also extremely shit.
what lisp do you use for front end? what's it like?
(9.04 KB 205x246 webdev.jpeg)
I am reading pdf attached to OP at moment, liking it so far.

its the simplest/easiest version of a 'functional' language IMO, not sure why its not more popular other than the lisp purists hate it for being jvm based and deviating from common lisp syntax, and the rest of the programming community considers it just another language like scala, etc. Plus static languages are really hot now.

pic related on libgen.is

also is a book i have a hard copy of. gonna read it after finishing the basic clojure book.

>what lisp do you use for front end? what's it like?

you can use clojure on the front end as well with 'clojurescript' which basically allows you to use clojure for node.

So you have full stack clojure (clojurescript mainly is used with react bindings because react is a 'function' flavored front end framework'. Or you can do traditional server side html templating either using hiccup, which is the pure lisp templating framework, or selmer which is moustache style dsl/templating language, similar to those in python/django

can read about it here as well:

just a warning if you do the emacs tutorial in clojure for the brave and true (pdf in op) its a bit outdated in that CIDER (emacs clojure plugin) doesnt work unless you also update all your emacs packages

(M-x list-packages will list all packages
U will mark all packages to be updated
x will perform all the updates. You need to confirm the prompt with y that you want those packages updated.)
Had a paid job for approx 2 years working in clj. Better than java. Mostly you just write functions that take and return immutable data. It makes your code way easier to test & debug in some aspects. To actually do something you have to code in a way where you try things live, as in a REPL or evaluate from your IDE (preferably Emacs/CIDER); all the while inspecting the inputs and outputs from your functions. You have to do this live coding thing as there is no type checking and by looking at the code its impossible to see the types. Its not a silver bullet though, I see too many people over-hyping it.
Interesting. In my experience, runtime type errors are hard to trace and debug. I like the composability of lisp and the supposed big brained macro system.
On the other hand, Haskell has static types and a very able type checker which tells you when you fuck up. It also has ADTs, which are very nice to model problems that come up frequently. I'm working on something in kotlin and had to do something like:
(don't know how to format code here yet)
if (!variable.isSpecialType) {
//do something
while in haskell:
data VariableType =
uniqueness :: Uniqueness
data Uniqueness = SpecialType | NormalType
-- then using in a function just check that the type is what you want and act accordingly
case x of uniqueness
SpecialType -> doSomething
NormalType -> doAnotherThing
what I wanted to show was that ADTs sometimes make logic easier to read, especially when dealing with boolean-like values, and enum more generally.
Sublime text has some decent clojure plugins and autofill utilities:
> proprietary shit
No thank gnu
emacs + cider is the preferred editor of 70%+ of the clojure community, once you get used to the weird keybinds it actually becomes a great editor. plus you can remap them if you want
yeah but haskells ornate type system *as well as the dreaded MONAD** makes it less accessible to beginners. the extreme simple syntax of lisp (everything is prefix plus parens) makes it way easier for beginners IMO.
true, haskell is less accessible. I've been struggling with it for a while. There have already been payoffs though, I find myself thinking more functionally in other languages, which is nice. Not that that wouldn't come from other functional languages like lisp or prolog (or even forth).

WARNING, below is a monad tutorial written by a noob. Probably wrong, and 100% certain: confusing.
Monads have an almost "impenetrable" reputation, which is IMO unmerited. They take some time to "get" but the concept itself is not "hard"
Monads are (most of the time) a generic (as in Java generics) container-like data types, like List<T> in Java or Nullable<T> in C#. They're just a data type that implements several functions, similar to how a class can implement an interface in Java. And, added to that, the language has syntax sugar to make working with monads easier, since they're so ubiquitous.
For example, in C# and kotlin, you have the "safe accesor", where a variable accesor might be null.

User? user = getUserFromDB(id)
// If at any point in the `?.` chain, a null is encountered, all the expression becomes null and stops evaluating the rest.

this is syntax sugar for a very specific data type in that languge. Haksell has a similar operator but it works on a lot of types, basically. The `?.` is the >>= operator.
the equivalent for a similar situation would be something like this, where at any step of the way, if a null is encountered in the chain, the chain stops the rest and just returns null. (I'm taking huge liberties, to not get too hung up on how the syntax works, immutability, purity, etc.)

user >>= getCreditCard >>= chargeAccount

The only missing part to fully define a monad is that you need a function that can "wrap" normal types into this "container type".
C#: string? name = Nullable<String>("dog")
haskell (return means "wrap"): return "dog" =gives> Container("dog")
In summary, Monads define behavior as to how to chain (aka compose) functions that deal with said Monads, and how to turn a value into a container that has a value.
(243.06 KB 822x1024 Untitled.png)
never really understood whats so great about lisp macros. mind explaining a little bit why they make programming easier?
If you have read Agamben's essay on profanation, it's like that for programming languages. Attacked PDF is an example of nice macro use.

It's not about making things easier per se, it is strong concept.

I don't write common lisp code that much anymore but to me it was weird sweet spot between unhygienic string manipulating macro of C/C++ and generic/template code of Java/C++.
You can think of macros as basically extensions to the compiler that your write inline.

you can make your own little DSL if you want
with lisp macros, code is data
Clojure has some interesting features, I really like the innovation with Edn, the implementations of some of the abstract data types are very interesting, and the focus on ergonomics is pleasant. It's of course only useful for a very small number of applications though. Being on the JVM user applications are mostly ruled out due to start up time, the garbage collection rules out real time systems, boxed arrays along with other issues also make it unrealistic for strictly maximum performance computing, and not being on BEAM rules out anything where down time is life or death. What's left is effectively threaded non-critical (as in non-life or death) servers, which is a big part of software development.

Beyond this my understanding is that there is some difficulty with error messages, and some difficulty with a occasionally having to get "low-level" and step into Java.
>threaded non-critical (as in non-life or death) servers, which is a big part of software development.
uh yeah, thats 90% of development... its performance is good enough
>uh yeah, thats 90% of development... its performance is good enough
Yep, for better or worse, basically all of it. It might seem like I was being overly critical there, but I was just trying to honestly point to the limitations. I think Clojure is a interesting language, with many positive innovations. Not sure why I said "very small number of applications", it's only sort of true.
>muh async-io
uh, Clojure DOES have an async-io web server/nodejs/go equivalent.
Its called Aleph
based on java netty server.
So you can go with the standard ring/jetty server or aleph as a drop in replacement that allows you to do async programming.
>muh embedded programming
thats like 1% of programming, no one was using any JVM or gc'd languages for embedded since that will always be in the realm of C/C++ or maybe rust in the future. (hopefully rust replaces those crap languages).
As for JVM startup time thats only a big deal with the whole function as a service thing, with traditional app servers running nonstop you only have to start the jvm once anyway. Plus theyve been optimizing jvm startup time to a fraction of a second anyway
I was saying that Clojure is a great fit for threaded non-critical (as in non-life or death) web development, but that this was basically its only problem domain.

>Embedded program is like 1% of programming
I said as much, as I said "I was just trying to honestly point to the limitations"

>JVM startup time doesn't matter in many server situations. Plus theyve been optimizing jvm startup time to a fraction of a second anyway
Start-up time is relevant for all user applications which was my point. I don't think I've ever programmed a plain Java program but for Clojure even on a performant modern system it takes roughly one second, independent of whatever you're trying to run for it to start. On slower systems like mine it's even worse.
>for all user applications which was my point
I'm sorry by user applications do you mean desktop applications?
>I'm sorry by user applications do you mean desktop applications?
Maybe that's the official terminology, desktop applications, mobile applications, applications for game systems, etc. anything that runs locally on a users system was what I was thinking.
then yes i agree, clojure is fucking horrible for desktop, as is anything jvm based tbh including java. They even rewrote minecraft from java to C++. All desktop apps should be written in C++/Vala and/or Python at worst.
Maybe if ORBTK
comes along we will see rust desktop apps.

Yes for clojure i am primarily talking about web dev backends
>Yes for clojure i am primarily talking about web dev backends
Cool, yah it's great for that.

Rich hickey gives some incredibly interesting arguments for dynamic over static languages in the latter half of the talk, such as that modelling things as objects or types (i.e. haskell/F# types/typeclasses) is not valuable because real world data is sparse and doesn't fit into the straightjackets of a defined ADT

clojure benchmarks second only to c++ and raw java in speed, beating out Python, Ruby, Lua and Javascript V8 in most categories.
Most, if not all, of the work that I've done has been well defined, structured, and schema-full.
I once worked at a big big tech company. My team decided to use NoSQL, seriously the worst decision I've seen taken by senior engineers. The project was basically a failure since the cost of going NoSQL would cost the company tens of millions (not a lot, but seriously unnecessary).
It's really hard to model schema-less data, much harder if you're doing it in dynamic languages IMO. There's no feedback on what info could exist, and when things invariably change, there's no safety net to alert you of stale code.
did you even watch the talk? hickey gets into the arguments in the second half
His main complaint seems to be coupling? And difficulty pushing data types over the internet? I just don't see how this is an issue with Haskell or other langs with strong type systems. You're not doing OOP so there goes one source of coupling. You have nice macros that can serialize data types to whatever you want (such as Serde in Rust). If you normalize your data structures (same as in SQL, see Data Oriented Design) you get perf benefits and reduction in coupling. If you need to combine a bunch of stuff you can always just make a few new types for the local problem. Or use a map or whatever.
He admits types help with refactoring, catching errors (ones that are not trivial, counter to what he argues), performance (performance really matters! We should not be running slow programs! It wastes time and electricity!)...
He compares types to UML but that's stupid. Some forms of documentation are good and some are bad. Types greatly enhance documentation.
Finally a lot of what he is saying is basically academic, which seems to run counter to his claims of how simple it all is. Why can't he put this all into plainer language and explain the practical significance?
That is a really old benchmark. Clojure frameworks are nowhere near the top now:
And I think some of them are even async. Now this doesn't say a huge amount about the language perf itself, but there is a definite trend in these recent benchmarks where the dynamic languages have a poor showing.
>clojure frameworks are nowhere near the top now

They don't look like theyre testing any new ones, they're still testing httpkit for example which has been abandonware, and replaced by immutant in the only major clojure web framwork (luminus). Also they're still testing compojure which again hasn't been significantly updated in years and has been replaced by reitit as the routing lib in most modern clojure webdev.

Obv java isn't going to be as fast as rust for example but their standards for clojure libraries are still stuck in 2015.

You can see even in that test, reitit is coming in at #23, surpassing basically every Scala, Go, and python framework, and half the java ones.

its well within the java range, the only ones above are written in rust, c/c++
clojure may be dynamic but its compiled to java bytecode which means its going to have roughly the same perf as java (with slightly more memory for immutable data structures)
i take it back, they are using pretty new libs for the reitit benchmark:

reitit for routing
jsonista for handling JSON
porsas for JDBC & Async SQL
hikari-cp for JDBC pooling
immutant-nio (a perf fork of immutant) as web server

which is pretty up to date and it actually did quite good.
look under json serialization tab
Yes rationally speaking, clojure should be pretty fast. Common Lisp is insanely fast for what it is. However, the vert.x frameworks for Java and co. are leaving the Clojure frameworks in the dust. I imagine this could be fixed by imitating vert.x in clojure.
in the json serialization benchmark, reitit/immutant is only 1 place behind vert.x ...
Speaking of Common Lisp, does Clojure actually offer anything significant over Common Lisp? The only thing I can think of is that persistent data-structures and threading are provided by default rather than in a library like FSet and Bordeaux-Threads respectively, and that it has some sugary syntactic innovations.
basically, it is simplified and runs on jvm I think.
>basically, it is simplified and runs on jvm I think.
Running on the JVM doesn't seem like much of a advantage. Also Clojure doesn't seem that much simpler, the complexity seems sort of just shuffled around in the language in contrast to Scheme for example.
>clojure vs scheme/common lisp
RH goes over that in this talk:

TLDR: rich hickley was a professional programmer who wrote java, c++, and common lisp.

Part of the reason he wrote clojure was because he kept trying to sell his corporate clients on common lisp programs and they absolutely refused to accept it because it wasn't on a 'blessed corporate' platform. So he wrote it on the JVM to both have access to the huge amount of Java libs (clojure has the most libraries of any language because it has all of javas + its own) as well as be more accepted in the mainstream world of corporate programming.

Another difference between something like common lisp/scheme and clojure is that CL/S are multi paradigm. Clojure is a much smaller language because its mainly functional/FP, with immutable (and sometimes lazy) data/structures by default.

Another difference is that clojure uses different data structures underneath the hood, a lot of practical day to day clojure is based on assoc-ing and dissoc-ing things in and out of hash maps rather than consing stuff. Hickley's data structures for clojure are slight modifications of those of the late computer scientist and functional programming researcher Phil Bagwell:

CL uses alot more lists comparatively and in RH's opinion lists are bad data structures because they're slow / O(n) [i agree on this part]

almost everything in clojure is a map, sequence, vector or lazy sequence, all immutable for the most part

Clojure's concurrent programming support is where it really shines though, with stuff like core.async. RH is someone who spent his career writing tons of concurrent systems in C++, so his concurrency primitives are top notch and baked into the language at a core level

The disadvantages compared to for example common lisp?

Debugging is not as good, instead you get a jvm stack trace
if you want OOP you have to really hack it together since clojure really steers you hard into FP only paradigm
No tail call optimization -> this is the fault of the JVM not RH, the jvm does not support optimized tail calls but you can still do it explicitly using loop/recur, however its not just built into functions normally
Broadly, dependence on hosted platforms. For example in clojure you get the jvm's math but if you use clojurescript for example you get javascript's integer math and types. Clojure is hosted on java, javascript, and the CLR (.net) and its implementation varies depending on that platforms restrictions.

Finally, common lisp is an open standard (like the C++ of lisps), while Clojure is like the java of lisps, having not a standard but a reference implementation on the jvm with Rich Hickley as the "benevolent dictator for life"


This is kindof overlooked a lot but clojure has something like 14 primitives -> its an extremely simple language to learn and start writing, and a way more accessible intro to functional programming than something like Haskell for example with its ornate type system. It's the python of functional programming. its also fun to write
I actually know a bit of Clojure, and the backstory. I agree with what you mention about the persistent data-structures and concurrency being built-in rather than in libraries is a advantage, all be it a rather minor one to me. I disagree with the idea that Common Lisp having Lists makes it slow, in practice Common Lisp programmers use whatever data-structures are most performant for their applications, including using mutability to increase performance when applicable. Also it's possible that Clojure is simpler than Common Lisp, but it's not simpler than Scheme. You can (and I have) literally read the Scheme specification in a few hours, and understand the guarantees and primitives of the whole language across implementations. Trading the Common Lisp ecosystem for Java's might be advantageous depending on the application though.
>You can (and I have) literally read the Scheme specification in a few hours

including all the SRFI? If your argument is that you can write a basic lisp interpreter as a side project or for a class then yes scheme is simpler but in addition to the SRFI to make scheme usable you have things like for example in Racket Scheme which have to implement lots of additional stuff to make scheme into a practically usable language (for web dev).

Scheme is like the C of lisps
Common Lisp is like the C++ of lisps
Clojure is like the Java of lisps

If you had to choose for example an embedded language for scripting a video game, scheme or lua might be good.

I probably wouldn't use scheme for doing modern web dev, because there are myriad of toy implementations. When you try to sell jim the JS developer on lisp, hes gonna flip his shit when he can't find the GraphQL library

>in practice Common Lisp programmers use whatever data-structures are most performant for their applications

sure but all good programmers choose whatever data structures are the most performant for their task. Its not just about what a language allows but what it steers average coders into in. rockstars can write good code in any language

>using mutability to increase performance when applicable.

theres a lot of strategies that let you rewrite functional code into mutable efficient code under the hood and most functional languages use these

Common lisp is a more complete overall language (other than concurrency) and Scheme is easier to understand, but as far as tooling, practicality, ease of use, and popularity Clojure definitely wins hands down. Other than emacs lisp Clojure probably has the most lines of code written of any of the lisps today.
>The SRFI to make scheme usable you have things like for example in Racket Scheme which have to implement lots of additional stuff to make scheme into a practically usable language (for web dev).
The SRFI's are just libraries, Racket isn't a Scheme anymore, and really the only extensions you need to RnRS to have a language quite capable of web development is POSIX support, threads, and probably a FFI. Many Scheme implementations have these things. Regarding Libraries you should look at Chicken Scheme: http://eggs.call-cc.org/5/#lang-exts https://github.com/lassik/graphql-chicken Not that this isn't all besides the point because your claim was that Scheme was more complex than Clojure which is simply not true.

>Its not just about what a language allows but what it steers average coders into in. rockstars can write good code in any language
I don't think as a programmer you should care about how a language steers average developers. Ease of doing something does matter, and you're going to have a slight cost by going into quicklisp and installing a library for some of the things Clojure has built in but it's not significant. Regardless the average Common Lisp programmer cares a great deal about performance, and they tend to write very fast applications.

>theres a lot of strategies that let you rewrite functional code into mutable efficient code under the hood and most functional languages use these
I don't think this is true, you can do this if you have Linear/Quantitative types but otherwise you're going to be giving up any concurrency guarantees you have, if you do this behind the back of the programmer (which is sort of the main point of writing in a functional style at this point).

>Common lisp is a more complete overall language (other than concurrency) and Scheme is easier to understand, but as far as tooling, practicality, ease of use, and popularity Clojure definitely wins hands down.
I think this is probably a fair assessment so long as you recognize that Clojure has these advantages only for a single problem domain. It has better tooling, practicality, and ease of use for web development and nothing else. Additionally I don't think the advantages it has in this department are that significant.
(82.73 KB 1280x719 rh.jpg)

RH'S epic talk on clojure vs common lisp (2 parts)

>Common Lisp btfo
Not really, it was mostly just a overview, and as I said I already knew a good bit of Clojure. Pretty much all his arguments are rendered null by (ql:quickload "fset") or are insignificant to the point of not mattering. Porky likes JVM is another part of his reasoning. Some of the abstractions mentioned are cool, but don't really matter, it's basically just sugar. Not particularly interesting to me. I can't be bothered to watch the second video provided. Anyway I'm getting pretty bored talking about this, I feel I've made a quite solid case, so I'll probably stop now.


no cookies?