Why I Switched from Python to Clojure (2016)
bradcypert.com
bradcypert.com
I enjoyed the syntax. Loved the immutability. However, I wasn't able to understand the structure of program data at a glance even when reading my own code. The reliance on lists and maps everywhere meant that the structure of data was encoded in the code of the functions that created it and sometimes you had to go several functions deep just to understand the bit you wanted.
In Python if I'm returning a tuple that's more than 2 or 3 elements long, I know that it's time for, at the very least, a namedtuple because I've had to deal with code in the past that has mysterious 5-tuples etc that just becomes too tiring to deal with.
To be clear, big collections in Python aren't a problem as long as the type of the contained data remains uniform.
<DashboardUnit data-index="2">
<h1>Scores</h1>
<Scoreboard className="results" scores={gameScores} />
</DashboardUnit>;
is more readable than this: [dashboard-unit {:data-index 2}
[:h1 "Scores"]
[scoreboard {:class-name "results"
:scores game-scores]]
Please tell me more about Lisp readability.Disregarding that, and in my opinion, properly formatted JSX might be a bit worse then s-expr for shorter stretches of code, but if/when you have a longer stretch, the visual symmetry in JSX would seem to tip the scale the other way. If there is a point to JSX, I would claim it's mostly that it looks different than the surrounding code that is the point, as it potentially makes it easier to parse and to clearly separate roles between code and design.
While I'm frankly not a fan of either of the above-mentioned, I do find some of the arguments around the brilliance of s-expr to be perplexing. The most confusing argument is the one that s-expressions are good because everything looks the same, which to me sound like arguing that the best way to paint is to only use one color, which I vehemently disagree with.
I think the easiest explanation of this conundrum boils down to a rather simple fact. Visual regularity is as confusing to some, as the lack of it is to others. People are different, sometimes shockingly so.
The point of the syntax isn't necessarily that everything looks the same, it's more around why that's the case and what other properties it enables. In other words, if a homogeneous (and arguably less convenient) syntax is the downside, it's important to consider the upside too. This still not make it 'better' enough for to want to use, but maybe will shed some light on why reasonable people might think differently.
The core concept behind Lisp syntax is that Lisp has a handful of core data structures, and the user syntax of the language is defined directly in terms of those structures. Clojure uses sequences, vectors, hashes to do things like represent blocks of code, argument lists, and type declarations. The structures used for this are the same as the structures uses in user code, and what you type in to the keyboard when you program are the normal textual serializations of these structures.
So this gives a couple of benefits:
1) The character sequences used to represent the language are easy to parse in a structural way without a whole bunch of parsing logic. A structural editor for Lisp doesn't necessarily need as complete a grammar or parser to enable the structural features as does a language like Java, Scala, C, etc.
2) It's easier to generate or manipulate code. Most famously, this enables things like macros. Macros and code transformations are absolutely possible in languages like Java and the JS ecosystem, but less commonly used and more expensive to develop.
There are many other examples of where these properties come in handy, but JSX turns out to be a reasonable illustration of why these are useful. Adding something like JSX to Javascript requires an explicit preprocessing state. Then, it also requires specific editor support to deal with the modified syntax. Once all that's done, what you have is a wrapper around 'React.createElement'.
It says a lot about the value of application-specific syntax that people are willing to pay those costs to get a certain syntax, but the Clojure/Lisp approach (hiccup for markup) reduces the costs and makes that kind of thing significantly easier to do. Whether or not that's the tradeoff you choose to make is one thing, but there are reasons to make it.
I like the ideas behind clojure, I really do. I even wrote a non-trivial personal project with it. However, coming back to that code after two months was basically like the plot of Memento. I ended up rewriting it in JavaScript instead.
Some prefer semicolons and other "visual garbage" in their code, I like minimalism and structure.
No other language can retain readability on different screens like Clojure can. Even reading it in a narrow screen of a mobile phone - it would wrap, but still retain its readability. Good luck trying that with literally any other (non-lispy) language.
Comparing that to your 30 years practice of XML is not at all useful.
As to your other point - maybe. I'm not seeing anywhere near enough potential payoff to invest years into it, though. Also, I'd argue that makes it a terribly impractical language if you're interested in getting work done.
To clarify, I don't agree one needs years to become competent in clojure. But if one did, that just makes it a worse value proposition.
Sure you can get things done and ignore the maintenance horror later.
Anyways, in the 30 years we at least steadily transfer features from Lisp.
This is not a snarky question, I'm genuinely curious since I personally have no problem coming back to old clojure code.
The other factors are cultural - so much of the clojure ecosystem is badly documented, or not at all. Sure, I can go and read your code to figure out what it does. But that comes back to the limited time argument, unless I'm paid for it, I'd rather write stuff in a language with a culture of proper documentation. For a recent example that does an outstanding job, see Elixir.
Finally, the ecosystem just feels... abandoned? Like walking through a ghost town. A lot of things on GitHub look incredible, but if there's no commits in the past 3 years I'm not inclined to invest time in it. I know the common argument about them being finished, and I don't buy it - non-trivial code rarely is.
The JSX looks immediately intelligible to me because I'm used to looking at HTML. The Clojure looks unfamiliar but it's not so strange that I can't imagine it feeling just as natural a way to represent the same data structure. It would just take a little while to get used to.
The major issue I suppose is that this example is supposed to render to XML, which is closer to JSX than Clojure. But by that standard Vue (or XSLT) is even closer.
I've done a little professional work in Clojure and wasn't a huge fan, but it didn't seem particularly bad (syntactically). It just seemed like something you had to get used to.
That's my point. It is simply "unfamiliar" to majority of developers who have never tried Lisps. And a lot of people throw baseless claims it to be "less readable" without even given it a try.
A few years ago plain English to me was "unreadable". But I have learned the language. And look, today I can even make comments on HN. I guess it's a good thing I haven't dismissed the language because I was unfamiliar with it.
My conclusion is that those languages which incorporate S-exps become identified as some kind of Lisp. This is the case even when it's a misidentification; i.e. little else is there of any Lisp "DNA" other than the parentheses.
Or else, those languages become identified as something that is not modern.
Thus, no modern, non-Lisp language has S-exps.
This is, of course, mostly a matter of opinion and experience, but I find S-expressions highly readable and LISP syntax superior in readability to every other syntax I've seen, as long as different parentheses are allowed like in all modern LISP dialects.
There are two other problems with LISP. First, it's so powerful that the semantics gets too rich, every author creates a DSL of its own with tons of macros and functions for every data structure. That makes code unreadable and difficult to maintain in the long run. At some point, every LISP program starts to look like a hack and you start spending most of your time transforming one data structure to another to interface with various packages.
The second problem is the focus on dynamic typing. I've found strictly static compilation better for debugging. Racket is particularly bad in that respect, as it tends to use ad hoc symbols with contracts everywhere. Static enumeration types are just way better for that purpose. Ideally, they should even be tied to the functions they are used in (e.g. a "function parameter type" with appropriate scoping).
These are the main drawbacks of LISP, maintainability and readability of code written by others is too low, because of a tendency to encourage hacks and DSLs.
If I can get one thing, I'd probably say practice in immutability. This simplifies a lot of things, even in java. In Clojure, immutability is first-class.
If you have entities in your domain, presenting clean and encapsulated ways of interacting with them is a separate concern from navigating and modifying their underlying datastructure, which is an implementation detail.
IMO the "it's just data" benefits of Clojure are that a lot of the common patterns which might have felt like being macro-worthy in CL/Scheme are achievable using things like keywords, which leads to more uniform code (rather than ad-hoc project-specific macros).
In other situations, this approach would work well as long as what I was working on was fresh in my mind. However, when I had to come back to some code and extend its behaviour it would be back to digging through it to either understand the structure of the data... or understand the structure of the fancy abstraction I had built up on top of the data. It just didn't seem to be very time efficient in practice for the things I was trying to build.
I feel the heart of the issue is surrounding a similar problem that message-passing set out to solve, perhaps encapsulation? You set up some boundaries to a thing and define some contracts for interacting with it, and in return you are free to separate the implementation of that from the consumer of that data.
I worry that when people program in Clojure, they forget all the discipline that was embedded in some of the better parts of the previous language/paradigms they came from and mistake that as liberation.
It's a very simple language. Literally when things get made to be complex Guido says do it the simple way, because when unbreakable things break it's just that much harder to fix. This makes it very easy to debug, very easy to fix/patch, very easy to onboard new/junior developers in, and very easy to start using in production. It's literally a baby.
But man, you can do some crazy things in Python if you want. You can write C/C++ extensions sure. You can also use things like orchestration with `py4j` and `jpype` in order to execute IPC with a JVM dedicated to the Python process. In that sense all Python in your application becomes a request layer with the JVM or a binary acting as the data layer, and request layers don't require as much in performance because you only need to issue so many requests. Request layers may also need to change faster than data layers/pipelines, and in that Python's great because it's so flexible. Based on some performance testing our team did there's absolutely no reason to simply switch away from Python, though that may also be due to legacy reasons.
I'd like to stick to Python and maintain my Python proficiency going forward (though with Guido out as BFDL we'll have to see how the language evolves). I'd like to maybe add Rust or Elixir to my repertoire and see how they extend my capabilities in ways Python/C/C++ may not. But Python will always be my Swiss Army knife turned combat shovel. It gets the job done.
This is more speculation, but I do hope it gives some insights into why you may choose one paradigm for a problem over another. Overall I’d say break your problem domain into subdomains and choose the best paradigm for each.
Clojure it's not (just about) beautiful and concise code. There's a lot more to it. And JVM in my experience is not a problem. I was skeptical at first, but as it turned out - JVM is pretty stable and solid piece of tech. Besides - there's also Clojurescript (and less popular Clojure CLR). Depending of what you are trying to solve, you can go that route too. I may not convince you to give Clojure a try, but please do yourself a favor and watch/read Rich Hickey's talks. https://changelog.com/posts/rich-hickeys-greatest-hits They are perfectly applicable and do make sense even outside of Clojure context. Many developers characterized those talks to be "eye opening".
Switching languages based on a comparison of idiosyncrasies between the two seems like moving to a new city based solely on the weather: a valid consideration, but nowhere near sufficient.
https://github.com/finalfantasia/apache-spark-examples-in-cl...
What happens in my experience is that Clojure programs do tend to encapsulate more extensive use of Java interop into their own modules. For more standard or commonly used packages, this means a canned library or similar. (But this notion of abstracting out APIs is just good software engineering in general, and not really specific to Clojure or anything else.)
1. If you need it, and there's not a Clojure alternative, you don't have to write your own. 2. If you have any proprietary .jars or anything like that, you can leverage those services, models, etc when building an existing Clojure app. This is mainly a transition-type thing, in my experience. "Well, we could try Clojure but then we cant reuse any of our existing models." Not entirely true. However, you probably will want to change those from mutable classes pretty quickly :)
Don't get me wrong, Clojure is a great language in itself, but the lack of libs make you spent 90% of your time writing interop, you start to ask yourself if it's worth the trouble.
I know choosing the right tools for the task can have serious long-term implications on the project, team, or organization level, but individually I get the impression that people worry too much about which language is best when, in reality, many of them are perfectly suitable and appropriate.
From the Spark website: "Write applications quickly in Java, Scala, Python, R, and SQL".
There's limited interaction with pandas but that's about it - you don't get R statistical algoritms for example.
Yes I agree with your points, what I was trying to convey in my comment is that, since Spark is not a programming language, I think that comparing it to Python or R is a bit of an apples to oranges comparison. The other point that I was trying to make is that both of those languages could be described as first-class citizens within the Spark ecosystem.
Flask -> pedestal/clojupture
Relay -> fulcro
Pandas -> clojure.core, specter
Keras -> mxnext/neanderthal
Basead on it's shape, you can extend and create many views.
Similarly, when connecting to a database like Oracle, it's trivial to just use JDBC/etc. while, for example, my coworkers who are using Haskell generally have to write a Java gateway because there aren't well-tested clients for Haskell.
Also curious how your Haskellers and Clojurers are peaceably coexisting? (I ask this lightly but still curious :)
There's a metric ton of libraries for Java and Scala out there, and as a consequence of Clojure's ability to use Java stuff, you have access to all of it. I admit I've not done a ton of machine-learning stuff, but I've used Spark ML, which works well.
Total number of artifacts indexed (GAV): 3,566,566
Total number of unique artifacts indexed (GA): 272,507
0 - https://search.maven.org/statsI do agree the language is part of the battle. The other is tooling, and libraries. F#/dotnet was painful as a linux dev. The JVM works on almost any platform with great tooling.
For Libraries. I haven't found anything akin to django admin, but I don't really miss it. For me
SQLAlchemy -> Jooq
Flask -> Spark/Vertx
Which part made made it painful the most?
Personal Opinion: Django is a nightmare to work with. It's too opinionated and a pain in the ass. However, I love Flask. I wouldn't be where I am today had I not found Flask in 2012/2013.
If you're looking for web technologies in Clojure, you'll find quite a few good ones. However, I say web technologies instead of frameworks because generally, the Clojure community prefers to compose libraries to suit their needs and not leverage an opinionated framework. However, if you'd like someone to do that composing for you, the Luminus web template is fantastic.
The clojure service was in 13 files with a total of 710 Lines of Code. The python service was in 33 files with a total of 1561 LoC.
I also have published load test results of these microservices at http://glennengstrand.info/software/performance/eks/gke where you will find the per minute average throughput for these two microservices to be about the same but the clojure version was about twice as slow as the python version.
You're definitely right. I had a run in with PolyML in College and I was absolutely terrified of any functional language (nearly failed the class, in fact). Before deciding to switch from Python to Clojure, I had used Clojure briefly a few years before and hated it (was writing mostly Groovy at the time).
After some time to grow, I had started caring about different principles in the languages that I used. I had been ruined by mutable state too many times; I got tired of not knowing how to get the number of wheels on your instance of the car class, I got tired of so many things. Clojure was/is a wonderful reprieve from all of these things, but truth be told, I do still struggle with it from time to time. Or at least, it feels like I do.
Can't or won't?
I'm not being facetious, here. I just can't imagine any reason one _couldn't_ work with it, once the syntax is learnt. There's nothing about lisp-like syntax that's inherently hard to learn.
Why is lisp special?
Once the brain grasps this, a whole layer of complexity just vanishes. Furthermore, not having to use punctuation between items is just heavenly. There's so much less noise compared to Python, and Python isn't even a particularly noisy language.
I studied Lisp and Scheme at university and that’s where it had to remain for me: academically entertaining mind puzzles in data structures and algorithms. It’s just not productive or easily graspable from one coder to another.
The following does exactly what you'd expect, and there are even cooler ones like `some->` or `as->`.
(->> some-nums
(map square-root)
(filter even?)
set
count)
This is what lisp buys you, dead simple rules for syntax, with the option to add syntax with macros. If you made a mistake in syntax design, deprecate the lib and make a new macro, it need not be a feature of core language for all eternity.There's a reason for it, for sure, but it's surely a part of the learning curve.
Remember that what is being passed through the threading macro is not the request, but the handler function itself. Each middleware takes the old handler, wraps itself over it to do things before and after the old handler. The threading macro is not a representation of the path your request will take, it is a way to build up a chained function that represents your final handler, which will then receive the request. Suddenly the ordering makes perfect sense :P
(But whitespace sensitivity has always struck me more as a way to enforce specific whitespace conventions than anything else, and even as far back as Pascal I've been religious about maintaining indention in code. It's easy to do with a decent editor (or not) and helps the readability immeasurably.)
Indeed, if you really want fun, try Hackett: a Haskell variant implemented in and for Scheme.
You still get the great “execute this block of code in the repl” with the parens too.
Plus, many editors without any plugins can jump between matching braces; so moving around the code is very quick compared to Python (unless you have a Python plugin that has block movement shortcuts).
I'm not letting that stand ;-)
In my experience Python's whitespace generally removes sources of scope/block errors compared to parenthesis and curly-based languages
> unless you have a Python plugin that has block movement shortcuts
Not sure what this means. The only support I need in an editor is the ability to use tab and shift tab on blocks of text to change the indentation level. It's visually obvious when code is correctly indented.
Not when the beginning of the code block isn't on screen.
And more to the earlier point, configuring your editor to jump to the beginning from the end or the end from the beginning of a particular block of code going to be trickier than the equivalent in even vim for lisp, which is simply %
(And vim isn't even a particularly good editor for lisp, but out of the box unconfigured, it's better at lisp than it is at python.. % isn't even lisp specific functionality, lisp just happens to use balanced parenthesis which is something nearly every serious text editor happens to handle in a reasonably robust way, because balanced parens are generally useful in many languages, including python!)
The length of your code blocks terrify me. :)
If you want scary, check out GNU's implementation of `cat`. I think they hit ten nested indentation levels. Though, because that's C, you can at least jump between the beginning and end of each level by having your editor jump to the matching {}.
In Emacs you can use C-M-f and C-M-b to move back and forth over / select paren/bracket/brace delimited blocks, or in vi you can use %, both with 0 configuration in a language-unaware state. If you're editing C or Lisp or whatever, these generic commands are useful. Editors don't tend to have move-to-next-less-indented-line (and similar) commands outside of Python modes or similar, in my experience, and even if they did, they'd need a bit more work than that to work properly because of indenting subexpressions.
I almost buy that it encourages simpler blocks, since complicated ones are impossible to parse out rather quickly. But my later reviews shows it doesn't remove them.
Not always, in my experience. I’ve lost many hours to debugging only to realise some piece of code was misindented. It doesn’t happen often and usually when code is being moved around, but when it does, its been painful.
I feel the opposite. I avoid any language without a Lisp-like syntax, since its absence is a serious handicap which unnecessarily complicates code and makes it less readable.
I also much prefer the Lisp idiom of using meaningful function and variable names, vs the one-letter names and crypitic operators that are so common in Haskell, OCaml, and SML.
As for the operators: they are a visual language. We do not speak our punctuation aloud in English, and we use small marks to guide the reader's eye. Often, Haskell operators as similar, and there is a definite pattern.
f $ x means "f applied to x"
f <$> x means "map f over x"
In general, the <> around an operator lifts it to work over a structure. Similarly:
x & f means "f applied to x"
x <&> f means "map f over x"
For the applicative operators like <star>, star> and <star (where "star" should be an asterisk but I can never work out the formatting on this forum), the operators "point" at the values being retained. And so on.
Macros, while easy to abuse, are kind of a game-changer; the ability to add new semantics to a language make it borderline impossible for me to go to any language that doesn't have a good macro system.
I started with Clojure, which I still really enjoy, but due to how much I grew to love the `define-syntax` system in Chicken Scheme, that's become my latest weapon of choice.
The parallelism isn't actually that powerful, and in 2019 there's very little to set it apart. The building blocks are great, e.g. immutability everywhere, but few of the built-in primitives are actually usable (hidden unconfigurable thread pools etc). Stack traces still regularly horrible. Libraries are regularly abandoned. ClojureScript integrating with npm etc is more stress than you'd like. Core development is haphazard and proudly so. Types are nice, and spec is still up in the air, and slow, and not widely implemented, and will probably be rewritten several more times before being abandoned. Hiring is harder than a dozen other languages.
All that said, there is still amazing stuff happening. I hold out some hope that Dragan's work might spark a bigger stats/ML community on top of Clojure, for example:
Every day I can still write code and think "yay, that's cute", and be thankful for the dynamism and clarity it can enable. But I wouldn't recommend it to anybody, for anything really, and I feel sad realising that.
As far as the stack traces go, I have a hard time understanding why tooling like Cider's stacktrace filtering isn't wider spread: in Cider, when a stack trace pops up, it's one or two clicks to hide most of the things I don't care about and, yet, that information is still available for people working on the compiler or with Java interop.
In terms of stack traces, it's not just the location in your code that you care about, it's the nature of the error. In lieu of spec being ubiquitous or anybody really checking their arguments ever, you're still left looking at 20 lines of stack beyond your own code to realise you've passed the incorrect type or structure somewhere. And even with spec you need additional libraries to actually yield human error messages in a lot of cases.
I've gone through several period of straight Lisp parens, and several periods of using a preprocessor. I believe in committing to muscle memory before deciding; I've oscillated back and forth between Querty and Dvorak, for example. I'm more committed to psychological experiments than anyone who claims the parentheses haters are newbies who haven't tried.
Study counting in higher mammals: One finds that "one, two, three, many" is core to all of us, and higher systems are strapped on like the multiple layers of vision mechanisms. Humans can't deal with the tiger tails at the end of lisp expressions. But machines can? Yes, but machines can also handle inferred parentheses. The complainers about parentheses complainers want off-the-shelf support. Real programmers write their own support.
Lisp looks best with indentation to help infer parentheses. Use a pipe "|" to open a parenthesis that auto-closes at the next ")" or the end of the line. Use a dollar "$" (borrowed from Haskell) to open a parenthesis that auto-closes when the indentation returns. Lisp written this way is stunningly beautiful poetry, cleaner than any of the dozens of languages I've programmed in. The remaining parentheses actually matter, so one pays attention to them.
I've spent years each way, back and forth. Inferring parentheses is better, and one can write any tool to follow this syntax.
Lisp parentheses are the exact same way, in my experience. You hate them until you spend a few weeks writing a Lisp and then they just fade into the background, never to bother you again. Then once you learn paredit, it becomes painful to use other languages again! (And now with parinfer, I think about them even less still) Incidentally, in my experience, Clojure typically has the same amount of parentheses as typical OO languages, in some cases fewer, its just that the opening paren is moved one word to the left.
Also, to anybody new to Lisp: try an editor with rainbow parentheses.
Indentation is significant.
Just replace '(' with space/tab and ')' with "deindent". Done.
I prefer to let this idea of required indentation to FORTRAN.
It's really not that bad! Here are some insights into the parens!
1. I've converted Java code over to Clojure and found that it has less parens per file.
2. They're still there, they're just in a different place. `System.out.println("")` vs `(println "")`
3. There are some great tools to help with the Parens. If you're using Intellij, Pareninfer and Rainbow parens are two extremely helpful tools.
The syntax makes blending sync and async easy. And the cooperative multitasking paradigm is very easy to reason about. No locks!
Big fan of Python and am heavily invested in its ecosystem, but I currently prefer async programming in modern JavaScript compared to Python.
Did you make use of third-party async libraries?
I do not agree with you. Scala is a mostly functional language, and Kotlin is mostly imperative. How is that fixing Scala? They are two different languages, and Kotlin being newer, is inspired by, among others, Scala.
That's correct! I did not want to give up Clojure or Scala for Android however! I tried writing an app in both and it was miserable, so I went back to Java. And then I thought -- well, hang on, I'm definitely not going to write this in Java if there's a less-verbose alternative. So I forced myself to learn Kotlin and actually like it quite a bit. In a few ways, it reminds me of when I first worked with Groovy.
I write Clojure, Kotlin, and Scala all on a pretty regular basis. Truthfully, I do write less Clojure now than at the time I wrote this post, but that's predominantly because my current interest (and salary) are centered around Kotlin + Android.
I still write Clojure quite a far amount, but I don't blog about it as much as I'm not "exploring" the language as much. Sometimes, I'll find or create something cool and share it, but most likely that'll be Kotlin/Android related right now.
My opinion has not change as I've never looked back ;)
I've found a fun little home in the JVM, but I'll definitely check out data classes in Python! That seems pretty cool :)
... I would say writing programs in Clojure leads me to writing 10 to 20 times less code on average.
I recently rewrote 15000 lines of Java (several weeks worth of effort split in several dozen files) down to 500 Clojure lines (in one weekend and one single file).
Anyone else with that kind of experience ? To me this is a tremendous advantage and any argument for code readability is really just argumentation about reading code at a small scale (say one file) that unknowingly makes trade off about reading code at bigger scales (say the readability of a whole project).
If I had a nickel for every time I got the "TypeError: random_function() takes 1 positional argument but 2 were given" because I forget the "self" parameter I could buy myself a coffee. Probably a fancy one from the Starbucks even!
Yegge thinks that "self" is a wart and I agree. The article is a fun read but it's showing its age. I suspect Python might just have beaten Perl by now.
https://sites.google.com/site/steveyegge2/tour-de-babel#TOC-...
I suppose Python's way there's one less reserved word. Are there any other advantages?
class Foo:
b = 4
def foo(self, a):
return a + self.b
inst = Foo()
inst.foo(3)
Foo.foo(inst, 3)
I haven't written python in a while, but I really like that python makes this possible and obvious and I've found this behavior pretty handy when working in a more functional style.These days, however, I mostly write Common Lisp and Clojure which, each in their own way, have explicit selfs: Common Lisp because it uses multiple dispatch and, consequently, there isn't one "self" and Clojure's protocols are designed to dispatch on the first argument, which is always passed explicitly.
Other languages have implied "this" or "self".
class LiterallyThere:
def method(self, foo):
"Literally explicit, self"
Dot operator means apply this method to thing left of dot by executing method with thing on left as first arg.LiterallyThere.method('foo')
passes the class object LitterallyThere as the first arg
lt = LiterallyThere()
lt.method('foo')
passes the instance of the class object represented by lt as the first argument.
method(something, 'foo')
If you were able to reference method without a dot, you would have to supply two arguments cause method takes two arguments.
You literally, explicitly have to tell the interpreter what you are passing as first parameter and you method signature has to literally, explicitly accept that parameter.
¯\_(ツ)_/¯
The high probability that clojure was someone's first functional language could also contribute to the problem.
Your thoughts?
Writing Javaonic Clojure vs Clojuronic Clojure. So, trying to replicate the style/structure/paradigms of Java rather than learning and using the Clojure styles, structures and paradigms.
Powerful abstractions are... powerful. They're more difficult to use correctly, and take longer to learn.
The conclusion shouldn't (always) be to avoid them entirely.
https://en.m.wikipedia.org/wiki/Rule_of_least_power
LISP is, of course, way more powerful than most languages so it is more susceptible to technical debt.
We want to choose the least powerful language for the job, but the least powerful language is frequently domain specific. Ideally you'd want to develop within a framework that makes it easy to develop restrictive, domain-specific languages.
I'd suggest that Lisp is actually a good basis for this, as S-expressions make it easier to build smaller languages. Clojure in particular seems to be heading in this direction. Cognitect has spec and datomic, and there's been some interesting ideas from Christophe Grand (IIRC) about using relational programming outside the database.
Big factories should be better regulated and more professional leading to less accidents. It's the weekend dad with a beer in his hand trying to get something done quickly that saws through their tendon and fucks up their wrist.
Also python is definitely not as simple as a hammer and hand-saw.
https://www.youtube.com/user/USCSB/videos?view=0&sort=p&flow...
Beyond that, these metaphors have gotten too out of hand to have a meaningful conversation :)
Of course no company would ever let a newbie loose on a multi million pound CNC machine without a battery of training.
And this is where the engineering part of "software engineering" falls down. Companies rarely provide training, documentation or audit trail for junior devs.
All something required if you were doing real engineering.
> At least at face value
Implying that in actually they are what a bunch of incompetent hacks?
>I don't have a horse in this race but
This is like someone saying I'm not racist but... After which they tell you why they really hate black people. You clearly do have an opinion your statement is a plea for imaginary objectivity.
You follow it up by elevating anecdote to analysis without the work required for real insight. The crack about at least on its face is just designed to offend. The silly emoji after doesn't soften what is basically trolling. If you want to seriously discuss you should start by making substantial points.
Again, you're completely missing the point: I don't have to "prove" anything to you. I don't even code anymore for that matter, and I can't give two shits if you prefer to write Clojure, Typescript or whatever rocks your boat, that's something that matters to you and not to me.
I simply observed that for a community that spends so much time talking about craftmanship and clean code, the worst messes I witnessed were all Clojure codebases and that's it. If you feel attacked... that's your own insecurity speaking.
Making a drive by comment and the copping out isn't much of a contribution to the conversation.
Furthermore look at this comment.
> I admire your restraint, you stopped short of calling me a nazi at least.
Some time in your life you should try actually try being an asshole instead of playing one on tv. It would be more honest and satisfying and people that aren't thin skinned can take a little civil disagreement.
All things suck to some degree. You might have an interesting perspective to share on situations where clojure sucks but you wouldn't know it because you are happy to stir up discussion but disinterested in any actual substantial disagreement. Guess that is done then.
Clojure has yet to impress me, but most of the poor code in any language I have dealt with stemmed from people trying to redefine the norms of the language they were using. And attempting to solve problems they would be lucky to grow into.
- Clojure has been noted as the most payed language in dev surveys of the past few years
- Again, different surveys (e.g.: stackoverflow, state of javascript) shown that Clojurists overall are more experienced devs. This kinda makes sense - usually people try Clojure out of curiosity and not for dogmatic reasons and not for the points in the resume.
- Someone did a data analysis of github repos for bug density and Clojure was at the top. https://dev.to/danlebrero/the-broken-promise-of-static-typin...
However, I can say the similar thing: I have seen many clusterfucks in my career. And the worst of them I've seen in C#. Why C#? I don't know, probably because I was inexperienced, young and stupid, and anything (even slightly outside of norm) could've interpreted by me as a clusterfuck. I have no reasons to go back to C# and re-evaluate my opinions about it, I'm sure part of me will be forever biased about it.
At $financial-news company, someone decided that they should re-write a few critical parts of the system in closure, partly due to boredom, partly due incompetence. They swanned off, along with 90% of the other people who knew how to maintain closure.
This left a bunch of junior java devs to maintain a ill thought out ego piece.
This logically meant that said company had to spend a large amount of money of contractors to maintain the system whilst they re-wrote everything in the same language.
In this case it sorta does:
a) Clojure is known for having a bit of learning curve and being a Lisp, it rarely attracts newbie programmers
b) it is famous for its concise syntax and for being able to build and maintain things with smaller teams. ROI of 3 Clojure devs is almost always can be predicted to be much higher than of 6-7 Java/Javascript/Python/ Ruby/etc. teams. Pick a few successful Clojure(script) projects and see how big the teams are, they are usually not that big
c) Flexibility of Lisp lets you bend your code for different paradigms: functional, OOP, logic, relational, CSP, reactive, declarative. In my experience, when most other (practical) language acolytes simply ignore academia Haskellers and Clojurists tend to be genuinely interested in CS papers. I think that is due to their experience - again these languages usually attract more seasoned developers
it's `setup.py`
I feel like with Haskell I have basically achieved perfection, and I'm more prepared to work on the other languages if the situation calls for it.
I think it’s still interesting to read about people switching. I mean, I’ll never understand why people prefer functional languages to OOP. I think it’s just so much easier to maintain OOP in the long run, and you can frankly build most of the advantages of functional languages within OOP if you need to. But then you read an article like this and you get a reminder that freedom can lead to some really horrible stuff and that is especially true for Python in general.
I don’t see this as “we should all switch from Python” sort of thing, but rather a “don’t do these things with Python”.
I still write Clojure quite a far amount, but I don't blog about it as much as I'm not "exploring" the language as much. Sometimes, I'll find or create something cool and share it, but most likely that'll be Kotlin/Android related right now.