Threads for Yogthos

  1. 3

    I find that Clojure has become an API to a bunch of different platforms for me now. I can leverage the JVM, Js runtimes, Python, and now Dart using the same language. This reduces a lot of cognitive overhead since I don’t have to remember how to juggle a bunch of different syntaxes, semantics, language quirks, and build tools.

    Typically, all the platform interop stuff lives at the edges of the application and most of the interesting stuff happens in the core business logic. So, even though I still have to figure out how to interop with each different platform from Clojure, that effort tends to be front loaded and relatively small when compared to the scope of the overall project.

    1. 2

      Python

      I know there’s an interop library, but have I missed a “Compiles to Python” Clojure dialect?

      Beyond that, I have been feeling the same. Babashka has become my go-to scripting language/platform, and i never want to go back to bash (or perl or python or whatever else I’ve used over the years).

      1. 2

        It seems like babashka is not going to be able to support platforms (eg BSDs) not officially supported by GraalVM

        https://github.com/babashka/babashka/issues/721

        Perhaps initially, the inconveniences are minor, but overtime they could become hinderances for scripts/tools that expect ubiquitous presence of the particular command-line shell

        1. 1

          I use Void Linux as my daily driver with servers on Void or openbsd. If I want babashka, I’ll need to package it. If I want to package it, I’ll need a fully open from source build that works across libcs and in cross building (ideally).

          I have not yet had, nor do I expect, a chance to use this really cool tool.

          1. 1

            Oh yeah, I meant that for my personal/one-off scripts I reach for babashka. I wouldn’t rely on it for anything that would be “production” or more generally open source for those very reasons.

          2. 1

            There’s clj-python for calling out to Python ecosystem from Clojure.

        1. 2

          Honestly I don’t understand this at all. It seems like the point of using Docker is to have a single image that is your unit of deployment but like … you already have that with an uberjar. Your deploy is one file.

          With an uberjar you have to ensure you’ve got a JVM installed on the system before you can deploy but with a docker image you have to ensure you’ve got docker installed, so … what have you gained, exactly? Is it just about uniformity and using tools that are easier to hire for because they also work with non-JVM deployments?

          1. 2

            Both options are certainly viable. If one works for you, it works.

            At 200ok, we deploy our Clojure based micro services with Docker for relatively easy scaling, logging, monitoring. “Relatively easy” because it works the same way in development and production as well as for services written in other languages.

            1. 1

              Java runtimes require Java on the underlying host. It may just be me, but I think the JVM sees more churn that an app would care about (GC, versions, features, flags) than a docker env would. So the point of shoving an Uberjar into a container is to allow getting your app tuned without redeploying the underlying server.

              1. 1

                Based on my usage of docker at work (not my own choice) I see more churn in docker than the JVM, but that’s because staying on an older version of the JVM is an option, and as far as I can tell, staying on an older version of docker isn’t. (or at least not an option for me personally given the decisions other people in my org are making for me). The version of the JVM we use is backwards-compatible with the same stuff I’ve been using since I first started using the JVM in 2008, but yeah the newer ones don’t have the same guarantees. (That’s why I don’t use em! for now anyway)

              2. 1

                You’re right that an uberjar is effectively a container. However, using Docker has become the standard way to manage containers in production nowadays. Packaging apps the same way you package everything else makes sense in this context.

              1. 2

                Despite the real discomfort I feel whenever I try to write Javascript, I can’t deny that it plus the browser environment as a whole DO make for kind of a nice minimalist almost retro gamedev environment.

                This is actually pretty neat and makes nice use of classes.

                1. 2

                  I find nowadays you can just treat js as a compile target. I made a small game with a friend for a hackathon one time in ClojureScript, and it worked out really well.

                  1. 2

                    Yeah I’ve been looking at love2d of late and was surprised it didn’t have this, but it seems it’s being worked on apace.

                1. 3

                  Question: is becoming a niche programmer possible for someone with little to no experience? Is it a good nontraditional route to enter the industry?

                  1. 5

                    I think it depends on the niche? For Clojure, my sense is that you can pick it up with little or no experience, but you have to be intelligent in a particular way

                    e.g. In my experience probably some smart music majors can pick it up, but others might have problems. That is, people “just looking for jobs” will likely have issues with Clojure. There is a tendency to do more from first principles and not follow canned patterns. Also smaller number of StackOverflow answers

                    1. 5

                      Absolutely, my previous job hired lots of interns to work with Clojure who had very little programming experience. The interesting part we found was that people without experience often have an easier time learning Clojure because they don’t have any preconceptions about how code should be written. A few of the students my team hired ended up specializing in Clojure after and haven’t had to work with anything else since.

                      Since Clojure is niche, companies end up having to train most of their devs, so having familiarity with the language is seen as a big plus. Having some small project on GitHub that you can link to in your resume would go a long way here.

                      1. 2

                        I think all this post shows is that it’s possible to do much better than the mainstream in a niche, but it’s also possible to do a lot worse.

                        The thing about a niche is it’s unique, so how can you generalize about it? It completely depends on what niche it is.

                      1. 1

                        I tried this on my M1 Mac & it didn’t work. Is that because the binary code is x86-only?

                        1. 1

                          Yup, only works with x86 instruction set

                        1. 3

                          Congrats on the followup to a popular framework! I think this post has convinced me to start using the alternatives to lein in my projects.

                          Meanwhile I’ve written other code that I use heavily in my own work, my own framework you might say.

                          Could I end up using kit to manage my own modules?

                          1. 3

                            Thanks, and I’ve been putting off learning deps myself and figured might as well dive into using it since that’s where the wind is blowing. And you definitely can make your own modules with Kit. All you need to do is to create a git repo like this one, and then either add your repo under :modules in kit.edn or replace the official one entirely.

                            1. 1

                              Cool!

                              So for deps, how would you replace something like https://github.com/yogthos/lein-asset-minifier in a way that could be seamless for my dep build?

                              1. 2

                                Ah, so this stuff is actually easier to do with this approach. With Leiningen you had to create plugins that work within the context of the build. However, however now all the tasks are tracked in build.clj, which is just a regular program. So now you can add a function that calls the library you want as part of the build. For example, this is what build.clj looks like in the demo app, and you could update the uberjar task to minify assets before the uberjar is created here:

                                (defn uber [_]
                                  (println "Compiling Clojure...")
                                  (b/compile-clj {:basis basis
                                                  :src-dirs ["src/clj" "env/prod/clj"]
                                                  :class-dir class-dir})
                                  (println "Making uberjar...")
                                  (b/uber {:class-dir class-dir
                                           :uber-file uber-file
                                           :main main-cls
                                           :basis basis}))
                                

                                The docs show some examples and how to reference dependencies for the build in deps.edn.

                          1. 2

                            This is very interesting, and that’s a big can of worm as I see it. I don’t see this technology become a new authentication factor, because there’s a lot of way your “behavior” can be altered. Say I cut myself with an envelope, my typing behavior will certainly change a lot. Or if I use my phone rather than laptop, or a keyboard with a foreign layout… Imagine being in a foreign country, and being unable to withdraw some cash because “your typing behavior is unusual” (that would make a cool popup though!). That would suck…

                            Now to push the author’s idea even further, you could probably write a similar “typing delay” code for programmable keyboard firmwares like QMK. Keyboards would then be seen as next-gen privacy devices that work independently of the system you’re typing on. This sounds pretty scary…

                            Edit Just realised that the article is from 2015. I wonder how these companies have been doing for the last 6 years. Did this technologies become more popular ? The fact we don’t hear much about them can be both relieving or plain scary…

                            1. 2

                              I don’t think this is going to replace passwords, where I see the main use for this is user tracking via fingerprinting.

                            1. 1

                              I don’t suppose anyone can link to some material about the community’s inclination away from Leiningen and toward the core language tools?

                              1. 3

                                A few prominent people in the community have been strongly advocating for using deps. Sean Corfield has written a lot about switching to deps. David Nolen and Alex Miller have been big proponents of it as well. I also notice that projects are starting to use deps. For example, Metosin is using deps for Malli now. While I personally like Leiningen, I do see the value of using the official tooling, and I think deps now reached feature parity with what Leiningen offers.

                                1. 1

                                  Remember the Clojure mindset: once it works, it always works.

                                  Lein isn’t going away. I would consider lein going away to be a bad sign for the ecosystem as a whole. Just people are making more modern choices on NEW code, providing no pressure to update OLD code.

                                1. 7

                                  A better syntax (debatable) isn’t worth losing static typing.

                                  1. 1

                                    My experience is that immutability plays a far bigger role than types in addressing this problem. Immutability as the default makes it natural to structure applications using independent components. This indirectly helps with the problem of tracking types in large applications as well. You don’t need to track types across your entire application, and you’re able to do local reasoning within the scope of each component. Meanwhile, you make bigger components by composing smaller ones together, and you only need to know the types at the level of composition which is the public API for the components.

                                    1. 2

                                      You don’t need to track types across your entire application, and you’re able to do local reasoning within the scope of each component.

                                      This is the complete opposite of my experience. How is one supposed to locally reason about a function if you don’t know the types it operates on?

                                      1. 1

                                        You only need to know what the shape of the data a particular function expects. Generally, people document the shape of the data a component expects at the API level, and it’s often done using spec or malli contract systems. The advantage of using contracts is that unlike static typing they actually capture semantics of what the code is doing.

                                        Out of curiosity, how much experience do you have working with large Clojure projects?

                                        1. 2

                                          I implemented a ~10k LOC service (specialized in memory cache) in Clojure back before spec was a thing (11 years ago I think?). Prior to that, I only had hobby experience with CL. It was fun to write but hard to maintain.

                                          1. 1

                                            11 years ago there really wasn’t much to help out with tracking types. The first library I can think of that allowed describing the shape of the data would be schema, and that came out in 2013. I also find that code style plays a big role in maintainability.

                                            I’ve seen beginners write fairly impenetrable Clojure before, so if you were new to the language and working on a sizeable project I can see how things got messy. I’ve written some code I’ve regretted myself as well. My approach was to pay attention to the parts that I had trouble maintaining, and to adjust my style to make my code easier to follow.

                                            I do agree that it’s easier to make a mess using a dynamic language and you have to be more conscious about breaking things up. On the other hand, I find that statically typed code can get differently impenetrable. I’ve worked with Java for around a decade before I started using Clojure and I’ve seen some incredibly gnarly code. I’ve also never managed to contribute to a single open source project. Any time I’d open one up and try to add a conceptually simple fix, I’d be overwhelmed by all the classes and indirection. On the other hand, I’ve contributed to numerous Clojure projects and many people have contributed to projects I maintain.

                                            1. 1

                                              I don’t think the overabuse of massive class hierarchies is an issue with static typing (given many statically typed languages aren’t even using objects), this is more a problem with Java where a class/object is/was essentially the only abstraction mechanism so everything has to be forced through this. Any language (like Clojure) with first-class functions can avoid a lot of the headache.

                                              1. 1

                                                Types encourage coupling by virtue of types being global constructs and I suspet that’s why projects tend to be developed in monolithic style in statically typed languages.

                                  1. 14

                                    People complain all the time about how verbose the Java type system is. I mean, what about this kind of code:

                                    List customers = new ArrayList();
                                    

                                    Do I really have to say it twice?

                                    That’s a disingenuous example. Java gained support for the var keyword in March 2018 with the release of Java 10:

                                    var customers = new ArrayList();
                                    

                                    What’s more, one might meaningfully choose to write List over var to communicate that the rest of the code should not rely on the unique behavior (performance characteristics or unique methods) of the ArrayList as compared to other List implementations.

                                    A lot of people (myself included) argue that the Java type system gets in the way more than it helps. […] You give up the small amount of safety for a huge amount of flexibility.

                                    Given that I just refuted the only example the article gave of a problem with Java’s type system, I think this argument needs expansion. I recognize that Java’s type system has limitations, such its single-dispatch that necessitates the cumbersome Visitor pattern, but I’m not convinced that a large codebase would be better off sacrificing Java’s compile-time type safety to use Clojure. (Of course, other statically typed JVM languages might be even better than Java.)

                                    1. 11

                                      Another feature that Clojurists like to claim as a feature is Clojure’s nil handling and I have to strongly disagree.

                                      Yes, you avoid a NullPointerException where you try to use a nil value, but instead nil quietly continues propagating through your program, being part of maps, transforms of maps and at some point something falls over because the value that you expected is nil but that’s not a valid value, so you have to trace the entire program back to where the nil actually originated and see why that was wrong and fix it in that place.

                                      This combined with the fact that it is way too easy to get a nil in regular Clojure code (because getting a non-existing value out of a map will give you that unless you insist on a sentinel) makes it basically the Clojure equivalent of the infamous “undefined is not a function” error. You can be extremely defensive and to Go style “if error” checks (which due to Clojure’s macro system would be more bearable than in Go), but I really don’t think this “on error resume next” strategy is a strong point of the language.

                                      1. 4

                                        I really like Clojure and I think its reliance on nil punning is absolutely one of the most boneheaded “features” of the language. It feels like it was designed exclusively to look good in a show floor demo, but spending just a little time with it makes you realize that it’s error-prone in the ways that you mention and it isn’t semantically illuminating either. I chafe every time I see or type the idiomatic (if (seq collection) true-case false-case) to test whether collection is empty, because I get the feeling that someone thought it was a cleverly elegant way of expressing that condition. It’s not. It’s really, really not.

                                        1. 4

                                          I really like Clojure and I think its reliance on nil punning is absolutely one of the most boneheaded “features” of the language.

                                          +1 to that; the nil punning is definitely one of my pet annoyances with Clojure. However, it seems that many people feel differently. It inherited the nil punning from Common Lisp, where it’s also pretty (har har) common to nil-pun (for instance, (car nil) returns nil). But another problem is that Clojure doesn’t go all the way. There are several builtins that simply forward to a native call and those will raise a NullPointerException. There’s not really any rhyme or reason to it, you basically have to know which ones will pass through the nil (most will) and which will not (some surprising ones will not, for example most of the string functions, even though strings can be seen as collections).

                                          (if (seq collection) true-case false-case)

                                          I never got why that was considered idiomatic either. How is (if-not (empty? collection) true-case false-case) any less readable?

                                        2. 2

                                          I’ve been working with Clojure for around a decade now and nil punning has never been a real problem in practice in my experience. What actually happens is that you just let the nils flow through the code and you do validation at the edges. Nowadays, you’d also use Malli or Spec to define the schema at the API level. If you’re nil as an error then you’re not really writing idiomatic Clojure.

                                          1. 1

                                            This is the canonical answer that many issues with Clojure get: “you should’ve done it differently”, which while obviously true, I should just not have created bugs, but practically not helpful.

                                            I would rather see these things being acknowledged and tackled rather than played down. To me this is the canonical “I can run with scissors, as long as I am careful not to fall with scissors (or have prepared cushions that if I fall I don’t hurt myself)”. Not specific to Clojure itself, but I have found the Clojure community to be extremely insisting that that is the right way (imagine Python users all saying that having a GIL is Good Actually™).

                                            Yes sure there’s ways to deal with specific issue, like use a library that will only be invented in the future like Malli (2019) or Spec (1.9, 2017, still called “alpha”) which both came pretty late to the Clojure (2009) world and Schema which came earlier (2013) but is dead now but if the solution to this is validation of all intermediate maps then Clojure is missing a convenient language element that guarantees that keys are actually set. On the other hand, if the validation is only at the edges, you only get to know about it when it the validation fails and then you still have to trace back where that nil originally came from.

                                            And sometimes you just have a codebase that’s written this way or other and it generally works so you can either trace up where you accidentally created the nil and fix it or spend many hours of rewriting and adding validation everywhere (bonus points if this is a library that is not written by you, but rather FOSS code where contributing large patches is always a somewhat painful exercise, even if the maintainer is very active).

                                            1. 2

                                              Every language in existence has its own patterns and best practices. So the argument that Clojure practices are different from what you’re used to isn’t terribly convincing.

                                              Different languages make different design choices that have their own trade offs. This is of course the case with nil punning in Clojure as well. However, as I’ve already noted, I haven’t seen this choice manifest itself as an actual problem. If you’re claiming that it is then please show me examples that it is in fact a source of errors. For example, we could look at Github issues for popular Clojure libraries and see how many of these issues trace to nil punning.

                                              What you’re doing here is making an utterly unsubstantiated assertion that nil punning leads to errors. Then you take this assertiion and treat is as a fact without providing a shred of proof to support the notion.

                                              1. 3

                                                What you’re doing here is making an utterly unsubstantiated assertion that nil punning leads to errors.

                                                I would say it doesn’t lead to errors, it just makes debugging much more difficult by carrying on with an unexpected value until it crashes at some later point, where you may have no idea where the nil came from.

                                                1. 1

                                                  Clojure development is typically done interactively by connecting the editor to a REPL. My workflow is to continuously run code as I write it and I always know exactly what it’s doing. For example, let’s say I need to get some data from the db, massage it in some way, and send it to a client. I’d write a function to pull the data, run it, look at the data I’m seeing. Next, I’ll pass it to the function to transform it, and look at the result there, and so on. At each step I only need to worry about the current transformation I’m making and the state of the data in the last step.

                                                  As I’ve mentioned in another comment, thinking of nil is a wrong value is not the right mindset here. A better way to look at it is that you’re querying into the data structure and you may or may not get a result.

                                                  1. 1

                                                    In my experience, you tend to be a lot more “rough” about what you try out in the REPL. Typically those are couple of variations of the happy path. This means you won’t be testing what happens when some part of the input you’re expecting to mostly be there will be missing (thus yielding nil).

                                                    Besides, the point was that it’s difficult to debug, which you’ll usually be doing after a report of something happening on production. Or very complex code in development where certain inputs yield nil somewhere along the way.

                                                    1. 2

                                                      Any real world application is going to have some sort of regression testing which will catch these kinds of problems. Meanwhile, I’ve been maintaining large apps in production for many years now and your assertions simply doesn’t ring true to me. It’s generally very easy to tell where the problem is based on the stack trace. Vast majority of the time when you see a production issue, the problem will be within a few lines of where the trace leads you.

                                                      As I’ve already explained, nil should be treated as an expected result, and it’s handled sanely by standard library functions. Meanwhile, your complex functions are just combinations of these functions from the standard library. So, what actually happens is that nils just flow through the execution chain, and then you decide how you want to present them at the edges. This is also where you’d typically use things like spec to do validation and coercion of data.

                                                2. 1

                                                  Have you ever had any problems with Clojure?

                                                  1. 2

                                                    Sure, I don’t think there’s a language in existence that won’t give you problems. A few pet peeves I have would be how cons and conj work, the fact that some core functions fail to handle NPE when wrapping Java calls, hot loading of libraries being flaky (although this is more of a JVM problem), and poor REPL experience compared to CL. However, nil punning is simply not an actual problem that has any real negative impact on development or code quality.

                                                  2. 1

                                                    Every language in existence has its own patterns and best practices. So the argument that Clojure practices are different from what you’re used to isn’t terribly convincing.

                                                    The other language I can think of where it is somewhat common to give unexpected answers to wrong input data instead of failing is JavaScript, where it is not considered a good part of the language.

                                                    You’re making the assertion that is it not a problem by stating that it hasn’t been a problem for you personally in a decade (I’ve also been using Clojure on and off since before 1.0 and it being my favourite language for some time, but so what?), but even people in this thread have mentioned issues with it.

                                                    I can’t point at specific examples because the examples where I spend a lot of time debugging were in proprietary code bases where you often get to correlated multiple domain “objects” together to form new domain objects. I’d say this is less of a problem in popular Clojure libraries since they’re often wrappers around Java libraries, with a lot less complex data being shuffled around in maps.

                                                    1. 2

                                                      The other language I can think of where it is somewhat common to give unexpected answers to wrong input data instead of failing is JavaScript, where it is not considered a good part of the language.

                                                      Except that Clojure gives expected answers. As I’ve already pointed out, the only issue here is that your expectations don’t match how the language works. The way to think about it is that you’re making a query into the data structure, and the query either returns a value when present or nil when there isn’t one. This isn’t an expected answer.

                                                      You’re making the assertion that is it not a problem by stating that it hasn’t been a problem for you personally in a decade (I’ve also been using Clojure on and off since before 1.0 and it being my favourite language for some time, but so what?), but even people in this thread have mentioned issues with it.

                                                      I’m saying that it hasn’t been a problem for me personally, it hasn’t been a problem for other people I know working with the language, and I haven’t seen it be a problem in many libraries I use and have contributed to over the years.

                                                      I’d say this is less of a problem in popular Clojure libraries since they’re often wrappers around Java libraries, with a lot less complex data being shuffled around in maps.

                                                      There are plenty of Clojure libraries that do lots of complex data manipulation. I work in medical domain and I have to work with lots of complex data such as FHIR all the time.

                                          1. 4

                                            As a long-time Clojure and Java programmer, I don’t agree with Eric here. Clojure is really just a Lisp targeting the JVM. If you like Lisp and you’re in a context where you can make use of the JVM (which is more places than I thought that would be a decade ago), it is an absolutely fantastic language. The combination of the most powerful language family on a ubiquitous runtime has lived up to its promises. I still prototype ideas in it even if I’m not going to use the code in production.

                                            But Java is still very relevant, particularly for team-maintained large codebases, or where you really need to just write Java and Clojure is only adding noise. Good Clojure can be written and maintained by a large team, but it takes above-average Clojure programmers to do so and almost by definition you can’t have a large team (>10) of above-average Clojure programmers.

                                            1. 2

                                              I don’t really follow the argument about large teams to be honest. My experience is that the problem with large teams has little to do with the choice of technology. Large teams introduce a lot of communication overhead, which makes for longer meetings, more emails, and more confusion where left hand doesn’t know what the right hand is doing.

                                              Any large project can and should be broken down into smaller projects maintained by small teams. This is basically why microservice architecture has become so popular of late. Breaking things up is the best way to ensure that projects are maintainable regardless of the choice of language.

                                              All that said, I do think that Clojure tends to work best when you have mostly experienced developers working on a project. It’s also not a great choice if you’re doing a lot of rapid hiring where you’re going to have to train a lot of new devs on the language. So, Clojure will never replace languages like Java in corporate environments.

                                              1. 2

                                                I don’t really follow the argument about large teams to be honest.

                                                I should probably have used a “large codebase,” which is more likely to need a large team supporting it. But you’re right, it’s not necessarily true. And that’s much more likely to occur with Java both because it’s a verbose language, and static typing enables it.

                                            1. 9

                                              This reads like a long enumeration of reasons to use clojure in general (macros, code is data is code, etc.), but there’s very little argument about why it’s good for compilers in particular. What makes clojure better suited for that than, say, OCaml or Haskell?

                                              1. 6

                                                I find most arguments for X is greating for writing compilers pretty weak, even the more common ones about OCaml/Haskell/Standard ML (and I like both MLs and lisps a lot). Any high-level language is great for writing compilers. As far as I’m concerned, the only ones that aren’t “great” (where “great” means “easy”) are ones where you need to bring your own standard library and do manual memory management (e.g. C).

                                                1. 2

                                                  You can still talk about why macros, code is data is code, etc are particularly useful to writing compilers. What do they let you do that you couldn’t do otherwise?

                                                  1. 3

                                                    Sure I’m not saying all programming languages are identical. But the awesome parts of languages are awesome no matter what the domain so that’s why I find the arguments about being good for compilers weak as if you can’t easily write compilers in any high level language.

                                                    1. 6

                                                      I think Lisps in particular are so good for writing compilers in particular because they make treating code as data trivial, which is exactly what you want to do in a compiler, because it needs to represent code in a data structure somehow anyway.

                                                      Of course, if the parsing is particularly involved, a Lisp doesn’t offer that much more. It’s mostly useful if you’re using s-expressions throughout. But if you’re not using an s-expression syntax, languages with pattern matching and first class support for ADTs will be at a distinct advantage over languages without those (hence the reason SML is so popular). Optimizations and term rewriting is basically pattern detection and manipulation. A language without first class support for those will give you more friction.

                                                      1. 2

                                                        Part of it is that I don’t like the idea that novice programmers will be turned off by compilers because they always read that sml or clojure or C (or whatever) are great for building compilers and since they don’t know sml or clojure or C it’s not worth trying to build a compiler.

                                                  2. 3

                                                    This is a good talk directly comparing the trade between writing a compiler in Clojure and F#.

                                                    1. 1

                                                      I read this thru earlier and it made very little sense to me. I re-read it and I think what’s going on here is that they’re talking about the fact that using lisp to write a compiler for a lisp is a good fit, but I think they just straight up forgot to say what language it was that they were compiling? Anyway it’s not particularly coherent as-is.

                                                    1. 1

                                                      There isn’t any evidence presented in the article that composability (which is not metricized) helps any more than more formally explored forms of machine learning.

                                                      Here’s an example of a flawed argument from the article about why neural networks can’t do NLP: “Pixels come from dumb sensors, but as we have seen, words come from people with rich models of both the world and likely listeners.”

                                                      1. 1

                                                        Last I checked, existing AI approaches can only produce expert systems, and aren’t able to do effective transfer learning and self directed learning. A general purpose AI needs to be able to learn independently to solve novel problems that it hasn’t previously encountered, and to do that efficiently it must be able to leverage existing learning from other contexts. As the article states:

                                                        The set of possible situations is effectively infinite because situations are composed of combinations of an almost infinite set of possible pieces. The only way to match that complexity is to be able to dynamically compose pieces to fit the situation—we need the ability to combinatorially choose model pieces to match the combinatorial complexity of the environment.

                                                        Meanwhile, I’m curious what specifically you’re claiming is flawed in the argument that neural networks doing NLP have limited and superficial understanding of the content. That’s demonstrably the case.

                                                      1. 5

                                                        Fast or elegant. Writing Java in Clojure for higher performance is meh. This is what we get when trying to use a too high level of abstraction. It is really good that we have a simple way to observe performance and fix the bottlenecks though.

                                                        1. 7

                                                          The reality is that idiomatic Clojure without any optimizations is fast enough for vast majority of situations. Clojure is already significantly faster than a lot of popular languages like Ruby or Python out of the box. So, the amount of times you actually need to do these kind optimizations is pretty rare in most domains Clojure is used. However, having the ability to tweak performance to this level is really handy when you do end up in a scenario where that’s needed. I’m very much a fan of writing code with maintainability in mind as the primary concern, and optimizing things on case by case basis as the need arises. Clojure is hands down one of the best languages I’ve used in this regards.

                                                          1. 1

                                                            Clojure is already significantly faster than a lot of popular languages like Ruby or Python out of the box.

                                                            Any sources, if you don’t mind my asking?

                                                            1. 4

                                                              Totally anecdotal, but my rewrite of the Riemann monitoring system from Ruby to Clojure improved throughput by something like two orders of magnitude right off the bat, and that was the first thing I ever wrote in Clojure. With a little work, we went from ~700 events/sec (in ruby) to ~10 million events/sec per node. Not an apples-to-apples comparison there–that’s years of optimization, batching and network tricks, and different hardware, but like… coming from MRI, the JVM was a game changer.

                                                              1. 2

                                                                Here’s a post from AppsFlyer discussing a significant performance boost when we moving from Python to Clojure.

                                                            2. 1

                                                              I completely agree with you. My only problem is that is very hard to sell Clojure to people. Both clients and co-workers. Clojure and F# are the two default languages I use a lot for writing code for myself. Unfortunately team mates and clients force me to use Python, TS, C#, etc.

                                                              1. 3

                                                                My team’s been using Clojure for close to a decade now, and what I observed over that time is that developers experienced in imperative style often have a hard time getting into FP. Yet, when my team hires students who have little to no programming experience, they’re able to pick up Clojure very quickly and tend to love the language.

                                                                I think the big problem is with mismatched expectations. People build up a set of transferable skills that allow them to quickly move from one language to another as long as those languages are within the same family. If you learn a language like Ruby then you can quickly pick up Python, Js, or Java. You’ll have to learn a bit of syntax and libraries, but how you approach code structure and solve problems remains largely the same.

                                                                However, using a language like Clojure or F# requires a whole new set of skills that you wouldn’t pick up working with imperative languages. People tend to confuse this with FP being inherently more difficult as opposed to just being different.

                                                          1. 4

                                                            Is anyone using natively-compiled Clojure for anything? Clojure is seeming more attractive lately, given:

                                                            1. there’s a natively-compiled option
                                                            2. ClojureScript seems like the best alternative to writing JavaScript/TypeScript
                                                            3. new tools like Babashka have made scripting with Clojure possible
                                                            4. Rich Hickey and the language are now being supported by Nubank
                                                            1. 2

                                                              Looks like natively compiled stuff is mostly getting use for developer tooling like clj-kondo. Calva makes heavy use of this to provide intelligence for VS Code. I’ve used Babashka for some internal tooling and scripting, and it’s definitely a great way to do automation.

                                                            1. 1

                                                              @yogthos I’m really intrigued by this idea that the “real” hardware design underlying the PDP-11-like abstraction is more like a functional programming model…could you elaborate on that or link to more reading? I’ve read that ACM paper but it’s pretty brief. So maybe I just don’t understand the link to FP. Thanks.

                                                              1. 1

                                                                I don’t really have another paper handy, but basically what it comes down to is shared mutable state. The reason FP is a better fit is because you structure your code as a series of data transformation pipelines, and state is carried explicitly between them. This model maps much better to how a modern CPU or a GPU actually works internally. So, if we embraced a programming model without shared mutable state then it would map much closer to how hardware works and avoid the need for what’s effectively a VM layer in between.

                                                                1. 2

                                                                  That makes a lot of sense. Thanks!

                                                              1. 7

                                                                Counterpoint from Planning & estimating large-scale software projects:

                                                                Engineering does not work in a vacuum, and there are commercial contracts that will be signed, at a high level, without your involvement. Deals that will have been agreed before you joined the organization. “Tie-ins” with other companies that have specific launch dates. Marketing and finance departments that want to know when they’ll need to spend £xm on producing a Christmas ad campaign.

                                                                Entire teams of people, who aren’t software engineers, and are used to being held accountable for delivery dates in their fields, will expect you to be able to tell them when your part of a project is likely to be done.

                                                                1. 3

                                                                  Thing is that if you don’t involve your technical people in the initial project planning when you decide on timelines and sign contracts then these numbers are just being pulled out of thin air. Expecting your technical team to commit to made up timelines and budgets that weren’t informed by technical expertise means that you’re setting up your project to fail.

                                                                1. 1

                                                                  how can i buy this ebook from india ( my card was rejected in pragprog)

                                                                  1. 1

                                                                    Unfortunately, I’m not in the loop regarding how sales work with pragprog. I was under impression that it was global though.

                                                                  1. 4

                                                                    Just grabbed a copy to replace my 1st edition, thanks!

                                                                    1. 2

                                                                      Hopefully the new content is gonna prove useful. :)

                                                                      1. 2

                                                                        I bought it a fairly long time ago to help me get started on a personal project but ended up not having enough free time to work on it, so now I’ll be swinging back around and I’m sure it will help. Just gotta’ set aside some time to get back into personal projects.