Did you have prior experience with dynamic languages? If so, how much?
Did you have prior experience with statically typed languages? If so, how much?
I'm trying to see if Clojure requires more fundamental programming intuition and experience to sustain in large projects. I work with tens of thousands of Clojure LOC, I don't feel these issues and can't relate, and love Clojure, so I'm curious to understand what context it best applies too. I wouldn't want to force it on a team that wouldn't benefit from it, so I'm interested about learning these aspects, so I'm able to recognize in what context it would make sense for me to influence a team to adopt it or not.
Thanks.
In Erlang/Elixir, you have patterns, and interfaces which are fairly low level, but provide meaningful abstractions over common goals... I.e. we have OTP. OTP is fairly simple, and that doesn't mean it's easy, it's really not, but it can be simple once you're familiar with it.
Rust, on the other hand, is easy to get started with, the core of the language is fairly small (and relatively simple) but that's where the complexity starts to creep in.
It's so small, I have to constantly reach for a crate for common goals... There are tons, and they're fucking awesome, BUT they're easy, not simple, and my application's complexity grows exponentially relative to my familiarity each time I grab another crate.
I think it's easy ;) to say the Rust ecosystem has to contain the complexity it does, and making it easy is the best we can do, but with great challenges comes great reward... Batteries not included, yes, but at least you could know the size (spec) required for the ones you need? That's probably a shitty metaphor but I tried...
...
One more thought on this tirade, when Rich Hickey casually says that engineers should be working to remove complexity from the business... That hit me right in the feels. Too often do we get complex business decisions/goals and just accept them. We need to push back and help them simplify their goals... too often I've gotten some crazy request, where instead of implementing it, I pushed back to get to the root of the problem and ended up with something wildly simpler and better for both parties. When we push back, it shouldn't be to make something easy, it should be to make something simple. You can scale simplicity almost infinitely, but complexity will eventually come crashing down.
More on topic... Thanks for posting this talk, it and the article have inspired me, I'm gonna go try to write a bit of Clojure today. You should write some Elixir, or maybe LFE (Lisp Flavored Erlang), I think you'd quite like BEAM :)
At my last job the client reps were notorious for saying “yes” to every client request and other devs were notorious for implementing those requests without question. I really tried hard to push back and find out what the client was trying to achieve. So many times after a brief discussion I would be able to inform them that what they wanted was already possible or doable with way less effort and expense. Sure, we didn’t get to bill them as much, but I’d much rather solve their pain points without adding code (especially when the code has already been written) than needlessly charging them.
Would love to hear why? What is that make Clojure such a good experience for you?
What's made clojure so great, imo, is its unicorn status as a principled-yet-practical language. That "principled" part is not worthless---it means that a lot of great minds are drawn to it. Before react took over the world, clojure folks were already taking steps in that direction.
A lot of other things. The "sequence" as a core abstraction is very powerful. Immutable data structures by default make functional programming perfomant and efficient.
Speaking of data structures, data structure literals have spoiled me for other languages. After Java, especially.
And none of this mentions clojure's lispiness. The ease of metaprogramming has allowed the community to build some of the best tooling out there, between CIDER for emacs, and Figwheel for the browser---oh, did I forget to mention clojurescript? Being able to reuse code on the front and backend is great for web applications.
Clojure isn't "everything." I think I'd still benefit from learning Haskell, APL, and Forth, and I wouldn't mind knowing Ruby and js a bit better. And I'll probably be dragged back to Python and R if I keep doing maths.
But if someone asked me which single language would probably do the most for them professionally, I'd say clojure. It's the language people start startups so they can use it.
- Immutable data-structures with concise literals for lists, vectors, maps, and sets. Having pure functions and immutable data-structures makes code easier to reason about, easier to test, and thread-safe.
(But clojure doesn't "force" you to be pure. The idea is that you write as much of your code in pure functions as you can, and push the IO and impure parts to the extremities. It's very pragmatic in this way, and you can get real work done.)
- Simple syntax:
While the syntax may be intimidating at first and arithmetic looks weird to untrained eye, once you realize that everything is a function (or a special form that also looks just like a function), the very light syntax and consistency feels amazing/refreshing.
- Macro system:
This is tied to the previous point. Since all your code is technically a "list", and you have something akin to a pre-processor where you have the full library of clojure functions to manipulate data. But in this pre-processing phase, your data is the code. (the code is a list). Now you can dynamically re-arrange or re-write code. Lookup homoiconicty and learn about the kinds of things you can do in macros that can't be done in other languages.
- Capabilitis for general programming, abstractions, code re-use etc.
- Performance is quite good. It's often nearly as fast as java, yet your codebase might be 10x smaller because the language is so expressive.
- Concise/expressiveness. Clojure comes with a nice built-in library with generic functions that you re-use again and again. Give a programmer a few dozen of these functions and it's amazing what can be composed to solve many problems succinctly and elegantly.
- There are surely other benefits, but the last one I'll leave with is hard to explain unless you have felt it before. It's REPL driven development.
Clojure comes with some seriously awesome REPLs (i.e. a shell for interactive tinkering with the language). Other languages may have some form of REPL, but no other language in my experience has come close to the feel you get in a clojure REPL. I can best explain it as a freedom of very light-weight experimentation that you use to write your code. It's a playground for writing functions with very quick feedback to see if your code will work or not. One factor that makes the clojure repl experience so nice ties back again to the succinctness and expressiveness of the language. Typing commands in the repl is painless because it's concise, not a lot to type, and then the feedback is so instant.
Somehow when I write code in python, java, javascript, or other languages, I just don't use their REPL or shell as often. It's just not quite the same as the clojure repl experience.
Then, when I learned about Elixir's macro system, I thought, "wait a minute, this is LISP! This is just a LISP in Ruby's clothing in Erlang's pasture!"
That was a delight. :) My heart still belongs to the LISP family, but right now I'm working as an Elixir developer.
One of the general arguments in Lisp vs the world is that lisp is more concise. F# is really concise. It has datastructures as intrinsic part of the language syntax (just like Clojure, i.e in F# [|,,,|] is an array and in Clojure [...] is a vector, so more or less the same thing). Furthermore, the type inferences concierges the developer through the regular bureaucracy involved with strong type systems so effortlessly that you seldom notice it ... unless your code does not compile, in which case it's wrong somewhere and you need to fix it (which you needed to do anyway).
Ok, so for the sake of the argument, let's say the syntax is equally light for F# and Clojure, and their support for immutability is in the same ballpark. And let's remove the argument "a type system is an encumbrance" because that will only lead to situation specific debates - one side will say that massive refactorings are a pita without types, and the other side responds that in Clojure you can use data schemas and should have unit tests anyway. And those discussions never lead anywhere conclusive.
So, besides the above mentioned topics, is there anything general one can say of the distinctive advantages of these two languages in specific situations, including how their two different ecosystems and runtimes affect the calculus?
I suppose it's extremely rare to have experts who have participated in any large scale industrial developments with both of the languages, but if there are, it would be really nice to hear their opinion. And the things I listed as "outside of the discussion" might actually be critical, who knows...
OCaml certainly has a lot of flaws, and is not nearly as "nice" a language as clojure, but the productivity of static typing (in the statically typed functional language sense, not the C++/Java sense) is huge. Knowing you can do a big refactor and the type system has your back is massive.
We sponsored core.typed to add types to Clojure, but there were flaws at the time (they have have been fixed since), and we didn't end up sticking with it.
So Clojure I wouldn't use again. OCaml I would, despite having significant flaws (every language has significant flaws).
Am I correct in summarizing your experience as:
The possible encumbrance caused by types at prototyping phase is paid back several times when refactoring a production codebase?
It also intigrates Shaun's awesome Parinfer parentheses management system, which adjusts your parentheses according to your indentation. Think Python rules: Put a thing inside another thing by just tabbing it over.
So I think it does come down to if you like static types or not.
> No. Clojure is not slow. Oh, look, it’s not C. It’s not assembler. If nanoseconds are your concern than you probably don’t want Clojure in your innermost loops. You also probably don’t want Java, or C#. But 99.9% of the software we write nowadays has no need of nanosecond performance. I’ve built a real time, GUI based, animated space war game using Clojure. I could keep the frame rates up in the high 20s even with hundreds of objects on the screen. Clojure is not slow.
If you're going to respond to this question at least provide some comparison maybe.
But otherwise that anecdote of "I could keep the frame rates up in the high 20s even with hundreds of objects on the screen." absolutely screams extremely slow. High 20s FPS with hundreds of objects is incredibly bad on the surface of things. Maybe it's closures fault, maybe it isn't and is instead the fault of whatever was doing the drawing. But it's not a good look either way if that's the only data point that can be provided.
Similarly the IDE/dynamic type question seems to have missed the main downside of dynamic languages - lack of good IDE & other tooling support. How well are things auto-completed for me? How well does the IDE warn I've made a type error before I've gone through a long compile & test iteration loop? How well do linters or other things work, or is there some aspect of LISP that means this is just not an issue like it is in other languages?
For scripting, there's a lot of ways to script efficiently with Clojure, it's actually great for it as well. So, for most my scripts, I don't really mind waiting 1 second for them to start. That said, if you wanted them to start faster, using ClojureScript takes you under 100ms. And using Joker (https://github.com/candid82/joker) takes you under 50ms.
When I need even faster startup for scripts and also need performant runtime, I've been using GraalVM to compile to native binaries, those start in under 10ms, and execute much faster than ClojureScript and Joker. That's a good strategy if you want to write things like a grep tool, or ls, or a linter, code formater, etc.
https://www.innoq.com/en/blog/native-clojure-and-graalvm/
Sometimes the trade-off of slow startup vs. having a JIT'ed VM is better, since you get a lot more performance, if you're working w/ long-lived processes.
Of all the things I’m unfortunate enough to have to manage in production, the JVM has never caused me any problems.
I mean, yeah, I’d like static binaries too (graal is promising but not quite there yet), but managing the JVM has nothing to do with it (footprint and startup time are my primary reasons)
This doesn't really exist in a lot of dynamic languages and especially in Common Lisp, Clojure, APL, Forth, Smalltalk...etc. You write a small piece of code and interactively run it with some data...test if for some scenarios or build actual tests if you want. When it is good, add it to your actual code and you're done. You interactively test everything. Once you get used to it, anything without a REPL is like wading through quicksand. The type error would probably be caught quickly when using the REPL. In Common Lisp, when your code errors out, it drops you into the REPL and you can patch your code while it is running. Smalltalk also has this. Again, when you've seen this, a Java app crashing seems hokey.
Otherwise the speed is almost identical to the speed of native Java and native Javascript. Except when you experience the power of lazy structures, then Clojure is faster than native code.
Yes, Lisp makes this a non issue for the most part, because the compile and test iteration loop is instantaneous and integrated fully within your IDE/Editor
Still, you get pretty decent auto-complete and static linting warns on quite a few things. For that though you'll want to use IntelliJ with Cursive or Emacs with Cider and clj-kondo + joker flywheel linters.
Edit: Let me address the performance part of your comment as well. I think using a game with 20fps as an example was to show that it could even achieve such performance. Languages like Java, C#, Clojure, Python, Ruby are normally bad choices for games as they are not performant enough. So most games are implemented in C++ with an embedded scripting language on top. So the fact a pure Clojure game can hit 20fps with lots of on screen object is actually pretty good in this case.
In general, for idiomatic Clojure code, you should expect to be within 10% the performance of pure Java. Non idiomatic Clojure can often match Java's performance, and when it can not, you can implement the hot paths in Java and use interop very easily.
For ClojureScript, performance is pretty on par with JavaScript.
Startup times are the biggest issue, if pure Java takes 80ms, Clojure will take more around 500ms to start. The issue is that each Clojure function is a Java class needing to be loaded at startup, and the JVM is very slow at loading classes. GraalVM can be used to make native images, and those will start in around 10ms, but your code might need to be adjusted a little as the native images don't yet support all runtime features.
ClojureScript startup times are pretty on par with pure JS running on Node.
What? A hundred on screen objects is not a lot, and 20fps is a slideshow. Pure Java games regularly do 10x that (Minecraft says hello as a simple example, and it's considered badly optimized)
A "proper" C/C++ engine you'd expect 100x (thousand objects at hundreds of FPS, or things like Factorio which are 10s of thousands of objects at 60 fps).
The anecdote performance is what I'd expect from a joke language like Rockstar. I'm sure the poor performance is not Closure's fault necessarily, and it probably can fly in the right circumstances (or maybe even in a lot of circumstances). Just the anecdote's description makes Closure sound horrifically slow.
Funny, this list is the same one I use as to why I'm so annoyed with Clojure right now.
I inherited a mission-critical Clojure ML library my team uses for it's primary business goals. It was written 4 years ago by a research scientist- who quit 3 years ago. We know what it's supposed to do. We know that it seems to do the job well. We just can't understand the code well enough to be certain of what it's doing or how it's doing it. If this thing breaks or stops working, we're screwed.
The problem is that the author, like most of us, found great joy in writing very few characters to express very big ideas. Clojure let him do that to an extreme degree. And I'm sure if you were sitting beside the author, with him explaining these dense expressions, you would be enlightened at the elegance and beauty of this language.
Sadly, I was not.
I'm sure Clojure is a lovely language. But it lets you write a Voynich manuscript that compiles.
It's not the job of the language, but rather that of the developer to write clear and readable code.
This problem is addressed by using good design practices, code reviews, testing, and documentation.
But at least the Java is overly verbose. It takes a while to read all that code. With the clojure stuff, I'm staring at the same line for just as long and getting no where.
I've inherited code bases in different languages in the past, and generally, it's the unfamiliarity to the language that makes it harder. Especially Clojure, being so different, the unfamiliarity is even stronger.
For example, if you read the Clojure source code (https://github.com/clojure/clojure) are you similarly lost? Or when reading any random Clojure github project?
Also, is this the first time you inherit software like that? Like have you ever inherited other similarly complex piece of code in your main language? Because I have as well, and it is never easy, no matter the language and familiarity.
Not trying to attack you by the way, it may be true, but I'm trying to isolate the variable of it being written in Clojure against the rest to really get a feel of the effect Clojure has over what you are experiencing.
All the rest, my team has managed to decode the intent and flow.
Do you believe the language is the issue, been written by someone not trained on software engineering practices?
Would you find untested (I'm betting this code you inherited lacks tests, from experience working w/ ML research code artifacts) verbose Algol-family code any easier to understand?
But we own lots of legacy stuff. It's only this one that gives me a headache.
Honestly, I wish it had bugs or failed occasionally so I could justify replacing it!
The names of complex functions, even with documentation, tends to be a bigger problem with scale than local variables and functions or utility functions.
Language design stuff like namespacing/modules helps provide a balance between short/descriptive and so does documentation of key/complex parts as well as how you architect the larger pieces and organize code in directories.
Additionally there's type systems, IDEs with docs/function + type signature integration, standards like JSDoc, etc that help. So it's a mix of a lot of things besides the human.
It is a very different approach and takes time to get used to.
I'm stuck on the other side: I have millions of lines of legacy Java code with high complexity. Even with all the types and very long names, understanding the code is not easy either and the 'step into/step over' buttons in the debugger are seared into my brain. Luckily IDEA can run arbitrary Java expressions during debugging, which gives you some interactivity back.
With Python, I find it's easy to understand what individual lines are doing, but really hard to understand what the codebase is attempting to do as a whole.
For me, Clojure and JavaScript (at least for modern React community) are similar when it comes to usage: Dynamic typing with Hash-map centric modeling, use functions to compose thing but mostly without monadic patterns. The methodology in the Clojure community has an official name: "It's just data". This methodology works, and have it's own pros and cons. The obvious pro is people can write generic functions without poking hundreds of nominal types, interfaces and type classes.
The only big difference I see is macro, but Clojure community also doesn't recommend writing macros unless you have to. There are also protocols and types, but they're not encouraged to poke around, it's still map-first recommended across the community.
There are very few language communities follow the "It's just data patterns". From Java to Python to ML, people mostly modeling things with fixed-property model, instead of just untyped maps, unless they have to.
For Lisps, I don't see map-centric approach is that stressed. Scheme might be still list-centric, Common Lisp is more diversed when it comes to approaches.
Why people hate JavaScript so much? And why people speak highly of Clojure? It's just about inconsistent details, or about the whole design itself? Is there any important point I missed?
Some people also find the lack of random syntactical noise in Lisp style syntax preferable.
It could be vastly improved with a proper REPL-based development (i.e. think developing within the browser dev tools, kinda, sorta), but instead we are now going the other way: Adding types and a compiler and making it harder to mis-type things, but also harder to work as productively.
I guess overall it has a few more ways on how you can shoot yourself in the foot compared to cljs ;)
I need to learn Web, as mucj as I don't want to, and love clojure and fp. Also figwheel looks awesome, but how hard is it to setup.
I also think maybe to really get the best out of clojure script you also need to learn react??
I'm not sure this is the case with elm.
Any other non js alternatives?
There’s almost no comparison.
Elm compiles much more quickly.
Elm produces much more performant code.
Elm enables you to write software that works reliably much more quickly because type errors happen at compile time, rather than at runtime like in ClojureScript.
ClojureScript’s error messages are at times incomprehensible. Elm’s error messages are best in class.
Elm is far easier to learn than ClojureScript, and you’re right — you do need to know React if you’re writing a non-trivial ClojureScript application.
Elm is criticised for not allowing a synchronous IO escape hatch. This is a pretty bad criticism I think. Being able to guarantee where effects won’t happen is a pretty great thing. Any effects work and/or JS interop can be done with ports. Ports work just fine.
Elm is also criticised for denying the user a lot of “power features” like typeclasses. I find it mildly annoying sometimes that I don’t have everything I want, but I understand the trade-off. This is to make the language more accessible to your average JavaScript developer who has never tried anything from this family of languages. And I sure as hell don’t find it annoying enough to want to drop the type-checking compiler.
You don't need to learn React to start using Re-agent or Re-frame.
IMO among all alt-js languages, Clojurescript is the most practical and production-ready.
I'm a desktop application programmer, not a mathematician. I don't need to print the first 25 squares of integers or Fibonacci whatever. In fact I think the hardest math I did at work was using modulo to get even and odd numbers ...
Show me how you parse a csv file, how do you connect to webservices or retrieve data from a database, show me how to do a simple GUI, show me something useful for the common dev.
I'll judge your ultimate programming language on these menial tasks that comprise 99.9% of my programming time.
(->> (d/load-workbook file "Questionnaire.xlsx")
(d/select-sheet "Sheet1")
(d/select-columns {:A :item :B :price}))How do you manage errors? What happens if Questionnaire.xlsx or Sheet1 doesn't exist ?
But here's CLojres read a file line by line and print it out:
C:\\foo.txt
"THis is line 1
This is line 2
This is line 3"
(with-open [rdr (io/reader "C:\\foo.txt")]
(doall (map println (line-seq rdr))))
=>THis is line 1
This is line 2
This is line 3
A simple function to read a specified file line by line (defn read-file-line-by-line [file-path]
(with-open [rdr (io/reader file-path)]
(doall (line-seq rdr))))
(read-file-line-by-line "C:\\foo.txt")
=> ("THis is line 1" "This is line 2" "This is line 3")
To read the line by line and convert them to upper case (map clojure.string/upper-case (read-file-line-by-line "C:\\foo.txt"))
=> ("THIS IS LINE 1" "THIS IS LINE 2" "THIS IS LINE 3")Stolen from the README page for a clojure CSV parsing library (https://github.com/clojure/data.csv)
(defn read-column [reader column-index]
(let [data (read-csv reader)]
(map #(nth % column-index) data)))
(defn sum-second-column [filename]
(with-open [reader (io/reader filename)] ; Read in the CSV file (streaming / lazily)
(->> (read-column reader 1) ; Convert to just the first column of data.
(drop 1) ; Drop the first row (the CSV header)
(map #(Double/parseDouble %)) ; convert each string in this column into double
(reduce + 0)))) ; sum the result
Because it's lazy, this code should work regardless of how large the CSV file. (client/get "http://example.com/resources/3" {:accept :json :query-params {"q" "foo, bar"}})
With the response, you can examine response headers, the body, etc.It's a wiki, not a blog, but I've lost countless hours browsing through it and trying stuff out for myself.
The rub however is that GHC can check the consistency of my software faster than I or my colleagues will ever be able to, and programmer time is expensive.
So that's why not Clojure.
That's why you need to spend 3 years learning Haskell? I feel that's the right amount of years for an average Joe programmer to reach meaningful productivity with the language. Well, maybe I'm exaggerating, maybe it's just two years. Plus/minus another year to learn and understand compiler pragmas.
I’m not sure how that’s a rebuttal to my point though.
I run a startup. I’ve already put the time in to learn the technology. I’ve learned other technologies too. This one happens to be the one I find the cheapest (now) to write. Did it take my employees a long time to learn Haskell? Maybe! But I didn’t pay for that. They learned the technology for whatever reason, and I’m seeing far better returns on my investment than I think I would have if I hired a bunch of Clojure developers. My previous full-time gig was at a Clojure startup. Their pace is pretty atrocious compared to the pace of my current team.
At least for OCaml/ReasonML it was "less than a week" for me and Haskell is probably not that much harder than another ML.
For one thing, Clojure has type analysis: spec. Also, as pointed out in the article, you can also write tests.
+----------+-------+-------+
| Language | Tests | Types |
+----------+-------+-------+
| Haskell | Yes | Yes |
| Clojure | Yes | No |
+----------+-------+-------+What makes clojure exciting [for me] isn't the ability to build efficient transducers or create powerful custom syntax or build complicated value-level dispatch hierarchies (and in my experience, although they are cool and fun to use, all of these things certainly do make for code which is hard to understand and harder to debug), it's the comprehensive and easily-composable functional programming primitives, excellent built-in immutable data structures with intuitive shared interfaces, practical and (for the most part) straightforward approach to polymorphism, and sane approach to concurrency.
pure functions are completely separate to every other parts of your software, they are very readable and easy to debug
* edit: don't write functions longer than a few lines
I can't think of two more opposed camps in programming.
Edit: Joking aside, I do think you're right in terms of the ideological foundations and organizational structures of the two languages (clojure's emphasis on practicality, curation and evolution of the core library+language by a single BDFL, compared to haskell's origins in PL research and democratic design/maintainence), but in practice I think a lot of that comes out in the wash--dynamicism vs. static typing is definitely a huge difference, but there's a lot more to language design and the material practice of building software than whether your compiler reads type signatures, and I think that along those axes, especially when compared to other mainstream programing languages/ecosystems, clojure and haskell end up being pretty close.
One of my teammates also has production ClojureScript experience, and called it the worst of both worlds (Clojure and JavaScript). The primary problem is it doesn't try to abstract away the DOM, the most typically problematic part of working with JS.
Just my own encounter with it so far - I haven't had the experience of writing production Clojure myself, but from what I've seen with the syntax, I'm still happily primarily writing JS so far when I'm not writing Python/Scala/etc.
It does require a different way of thinking. I was lucky in that I had very little experience, academic or professional, when I picked it up. I had a lot less to unlearn.
But that doesn't mean it's limited to ultra-brainy lisp weenies. We have undergrads writing clojure, never having written clojure before, in their first programming job. They do just fine.
Clojurescript has heavily bought into React. No cljs programmer I know deals with the DOM, but rather uses a React-based library to do it. Personally, I use re-frame and reagent and haven’t needed to interact with the DOM myself in years. I find working in cljs a LOT more productive and pleasant than working in Javascript (which I also use a lot, although if given the chouce I’d use cljs instead).
car and cdr are accessors for the fields of a basic data-structure; nothing academic about that. The very origin of the names is rooted in systems work, not academics.
(caddr x) provides a shorthand for (car (cdr (cdr x))), which is a pragmatic thing.
You know, like #(* % %) instead of (lambda (x) (* x x)).
The lines are more concise. That also means you will need more time per line to read the code.
Especially in Java, you can skip over so much boiler plate code, you kinda feel you are reading code fast.
Not so with Lisp. You need some familiarity with it and you will need to adapt to a line just having more stuff to understand in it.
Also, you can tune this using libraries as many things are a la carte.
So it's ok to say #(25 % %) because we both speak the same language and we know what it means, the intent is clear.
But it's not okay to call your variables a, b, c, because that's meaning, not syntax, and I can't understand your intent from those variables.
Massive one-liners probably fall into the latter, but I don't think he's advocating those.
(println (take 25 (map #(* % %) (range))))
And in APL[1], iota 25 is the first 25 integers, and feeding the same list into both sides of multiply squares the list, then turning it from a row to a column is tabling it. "Table the multiply-commute of the first 25 integers": ⍪×⍨⍳25
It's fewer lines, fewer characters, fewer hours, less syntax, less grammar, fewer symbols, fewer functions, less nesting, fewer mental gymnastics. Yet .. worse? Because those things you say both lead you towards codegolf, and implicitly have "fewer mental gymnastics" mean "I'm familiar with it already".Where is the evidence?
Back in the 1990's IBM taught many of their consultants Smalltalk, and researched what made learning Smalltalk difficult —
Smalltalk, although recognized as a good platform for rapid prototyping and software reuse, is widely regarded as difficult to learn. Unlike learning a procedural language like Pascal or C, learning Smalltalk is dominated by browsing and code comprehension. Learners of Smalltalk typically experience a long, slow start-up phase in which they become familiar with the class hierarchy and object-oriented computational model but do little meaningful work (our colleague Dave Smith calls this "climbing the Smalltalk mountain").
Programmers having to wrap their minds around the class hierarchy and OO was seen to be the problem.
public class SquaresOfIntegers {
public static void main(String[] args) {
for (int i=0; i<25; i++)
System.out.println(i*i);
}
}
> This is considerably more wordy, even if you don’t count the enclosing class.First of all, Java is famously verbose. Nobody is impressed when a language is more concise than Java.
But even ignoring that, the comparison isn't representative. The enclosing class and 'main' function aren't needed for every additional fragment of code, so it probably shouldn't be counted here.
I guess he's happy. At least he isn't touting Haskell. Bon Voyage, Bob!
But somebody needs to break it to him that Lisp is not a functional language. Or, if it is, so is C++.
You're missing the point. Everybody can write Fortran in any language.
Lisp is not a language at all. It's an idea. And if you grok the awesomeness of that idea you can make any kind of language using it: functional, OOP, relational, whatever.
Bob is talking about Clojure. Clojure is a functional Lisp.
I also disagree with you on C++. Cc+11 was a fantastic improvement, C++14 added some missing stuff — at this point I was sold and eagerly awaiting C++17 — but when 17 arrivd and when I saw what 20 adds... it has become so complex that I don’t understand it at all anymore. I used to scoff at the people who said C++ was too complex, but after ~18 years of using the language its now reached a point where I am no longer comfortable using it. I see code that uses C++17 and recently 20 and I have no idea what its doing anymore. I am no longer confident that I can write safe, non bug-ridden code in C++.