This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # announcements (13)
- # aws-lambda (19)
- # babashka (11)
- # beginners (90)
- # calva (35)
- # chlorine-clover (16)
- # cider (8)
- # clj-kondo (6)
- # cljsrn (10)
- # clojure (44)
- # clojure-australia (1)
- # clojure-europe (35)
- # clojure-nl (6)
- # clojure-norway (7)
- # clojure-uk (101)
- # clojurescript (79)
- # community-development (40)
- # conjure (1)
- # contributions-welcome (4)
- # core-logic (2)
- # crux (15)
- # cursive (6)
- # datomic (4)
- # figwheel-main (5)
- # fulcro (18)
- # girouette (1)
- # graalvm (3)
- # hoplon (2)
- # hugsql (2)
- # jobs (5)
- # malli (26)
- # off-topic (74)
- # pathom (36)
- # portal (4)
- # reagent (10)
- # reitit (23)
- # remote-jobs (1)
- # shadow-cljs (27)
- # spacemacs (10)
- # sql (3)
- # startup-in-a-month (6)
- # tools-deps (55)
- # vim (11)
paredit is about “Structural editing” strict paredit also protecting integrity of your code disallowing deleting of closing/opening parenthesis if it introduces inbalance s-expression For examle: calva: https://calva.io/paredit/ enable strict paredit by default
the delete forward says it will prevent you from getting into an unbalanced state but the attached gif has an unbalanced close paren after a few deletions
That is because the recording is cropped. The extra paren is from the outer scope. I'll re-record it, since it does look like Calva paredit is not delivering on its promise.
ah makes sense. the paren is colored black which made it feel even more like being highlighted as mismatched rather than from an outer scope.
> It is common to conflate any interactive language prompt with a REPL, but I think it is an important aspect of Lisp REPLs that they are a composition of read-eval-print. I'm not sure I understand what that means. How is e.g. JShell or IRB not a "composition of read-eval-print"?
(I'm not trying to say that JShell or IRB etc. are as good as a full-fledged Lisp REPL — I'm wondering about the "composition" bit in particular.)
I think the point is that read and eval are the same building blocks that the Lisp uses to run your program. This means that you can do everything from the REPL that you can do by writing source files and running your program. In other languages, you can eval expressions at the REPL, but there are certain things that are out-of-bounds, such as adding new classes in Java.
Yes, and in IRB for example, there is no distinction between read and eval (only the latter is provided and it takes a string of code)
Right, I understand. What is the practical benefit of that from the point of view of using the REPL for interactive development, though? I understand the benefit in general (macros etc.)
For me it’s the tight iteration time that comes from working with a running program. I can inspect the working state of the program and re-define functions on the fly.
Note that most seasoned Clojurists recommend that you not usually type at the REPL prompt, but rather that you set things up so you can send forms to your REPL from your editor. You’re still just editing your program source files, but as you do so you’re sending bits and pieces over the REPL and updating your running program in real time.
Totally agreed, that's how I do all of my Clojure development. I guess what I'm really after is this: Imagine I'm a Ruby programmer who makes heavy use of IRB or Pry. A Clojurian comes along and says "Well, IRB or Pry aren't really REPLs. A Lisp REPL is a composition of read-eval-print." The Ruby programmer is like, "huh?", you know? Everything you said is true and that's already what I do, but I guess I'm just trying to figure out a way to explain the "composition" statement in such a way that someone who's used to a "non-compositional" REPL understands what I mean. I haven't used IRB or Pry etc. in a long time, but I think you can also use them to inspect the working state of the program and redefine functions, etc. You can't (easily) send things from the editor window into the REPL, but I guess that's more of a property of Lisps than Lisp REPLs, as such.
I guess it's just quite difficult to explain the benefits of a Clojure (or some other Lisp) REPL without actually showing what writing programs by evaluating things directly from your editor looks like.
I mean, if a Ruby dev can achieve a similar effect with IRB, does it matter whether IRB reads code differently from the regular Ruby startup? They might not find “composition” a compelling argument.
I think what you're saying makes sense, and I don't think there is any benefit to R and E being separate composable pieces, in the limited context of typing strings of code and seeing the result of evaluating it. In that sense, the
irb user is not missing out on anything.
but if you aren't modifying code as data then a REPL is a REPL even if RE are not decoupled
I guess I gained some new insight into this today... if you try to copy-paste multiple expressions at once into a Python shell, you get an error saying "SyntaxError: multiple statements found while compiling a single statement".
I think @U0DTSCAUU's first comment is bang on: with Clojure (and presumably with other Lisps), using the REPL is exactly the same as running the program via other means (e.g. via a
main function or something), whereas that isn't (necessarily) the case with other languages.
irb does allow you to copy-paste multiple expressions, but it might have other limitations -- not sure.
In any case, I think that's what "composition" refers to: since reading is separated from evaluation, the REPL is guaranteed to work the same way as when reading forms from a file, whereas that's not necessarily the case with other languages.
Periodic reminder: there is a #contributions-welcome channel where you can ask for contributions for your OSS projects
This might be a stupid question but i really wish to understand: Why do libraries and frameworks make so much emphasis on the fact that they might have just a few milliseconds faster startup times? For example does a 3 milliseconds difference in startup time really matter? or are developers just becoming too impatient ?
Off the top of my head i can see this in comparisons of frameworks like quarkus vs micronaut
The difference there isn't ms, it's probably seconds (when compiled to native which both frameworks support). And this can be a significant win in cloud environments.
it allows things like on demand scaling - I've worked on microservices that take multiple minutes to spin up
also think e.g. AWS Lambda where you pay per nanosecond or something like that
Starting fast also helps if your language doesnt support a repl... so if you can changed code -> deployed fast... then you can work faster.
the mirage project got ocaml startup times so low, they can feasibly spin up a new http server on demand for a request
In servers, 80% of the situations the runtime speed of code don't matter because the DB is a few orders of magnitude slower. And the most remaining 20% optimization gains pennies. What remains is HFT & Google electricity.
Yeah, I never thought of that. I think a single ms difference can be a big deal in High-frequency trading
both the jvm and the clojure language make multiple design decisions that trade more resource usage (read: spending more money on your containers per server) and longer startup times (read: needing to leave more servers running because "on demand" spinup is too slow), in exchange for runtime throughput (oops, the bottleneck was IO anyway...)
of course the thing clojure is really great at is optimizing programmer time (you probably spend a lot more on that than you do on hardware)
Large legacy clojure not that fun on programmer time. Immutability helps a lot, but no types is shaky business.
> 80% of the situations the runtime speed of code don't matter because the DB is a few orders of magnitude slower. Right. Which is why concurrency matters (more?) Some requests can only be sped-up so much. But certainly you'd never want to intentionally slow down other requests
• CPU-bound -> multiprocessing • I/O-bound, fast I/O, Limited Number of Connections -> multithreading • I/O-bound, slow I/O, many connections -> asyncio https://luminousmen.com/post/asynchronous-programming-python3.5 (was reading this the other day)
I am trying to come up with a
glob function for a library (similar to clj-commons/fs) but there are some nuances.
(glob path pattern)
- Should the behavior be recursive by default? Some shells (bash/zsh) and languages (Python, golang) seem to have conflicting opinions on this.
- If not recursive by default, what would you make of
(glob "." "**/*.md") then, the pattern assumes recursiveness
- Should it include hidden dirs by default?
you can also refer to Tcl's implementation, might find it useful https://www.tcl.tk/man/tcl/TclCmd/glob.htm
yes, that's what I'm building on, but they do not provide any function like this, only the raw building blocks
Looking at ruby's https://ruby-doc.org/core-3.0.0/Dir.html#method-c-glob
• not recursive by default
**/ makes it recur on the matched dirs
• hidden files not included by default
Generally ruby api follows unix forefathers wisdom.
**/ means recursive, instead of an explicit
:recursive option right? (double checking)
do you mean the
DirectoryStream class? afaik this isn't like
file-seq, it only lists one level deep