40 comments

  • janetacarr7 hours ago
    I have my qualms with Janet. Mostly, it&#x27;s lack of package management versioning and lack of libraries in general (advanced HTTP routing, etc).<p>I do LOVE that Janet can create binaries with JPM, scripts, and is very portable. I once put the Janet programming language on the Playdate game console as POC.<p>I actually do enjoy writing Janet, but every time I do people think I created the language (I did not).
    • FelipeCortez7 hours ago
      Julia Evans has a fun blog post using Julia to visualize Gunzip: <a href="https:&#x2F;&#x2F;jvns.ca&#x2F;blog&#x2F;2013&#x2F;10&#x2F;24&#x2F;day-16-gzip-plus-poetry-equals-awesome&#x2F;" rel="nofollow">https:&#x2F;&#x2F;jvns.ca&#x2F;blog&#x2F;2013&#x2F;10&#x2F;24&#x2F;day-16-gzip-plus-poetry-equa...</a><p>you should totally do a &quot;Janet writes Janet&quot; version
    • Karrot_Kream4 hours ago
      If you want server side, as veqq says there&#x27;s joy which implements its own lightweight http server. If you want a client, it&#x27;s quite trivial to use the Janet C API to wrap libcurl or any other HTTP client. If you&#x27;re open to LLM development have the LLM write the wrappers and write your actual logic in Janet.
    • ramblurr4 hours ago
      Have you tried jeep?<p><a href="https:&#x2F;&#x2F;github.com&#x2F;pyrmont&#x2F;jeep&#x2F;" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;pyrmont&#x2F;jeep&#x2F;</a><p>It let&#x27;s you vendor deps and easily install modern Janet bundles without jpm.
    • veqq5 hours ago
      &gt; advanced HTTP routing<p>What do you concretely mean by this? I use <a href="https:&#x2F;&#x2F;github.com&#x2F;joy-framework&#x2F;joy" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;joy-framework&#x2F;joy</a> for all web stuff and can probably get your missing features in within the week.
      • cptmurphy3 hours ago
        TLS. There are some curl wrappers but last time I checked they did not work
        • cfiggers3 hours ago
          There&#x27;s a few that don&#x27;t work, but one works phenomenally well— CosmicToast&#x2F;jurl is incredible (unless you&#x27;re on Windows—the library as a whole does work on Windows but the build script doesn&#x27;t have Windows instructions in it, you have to hack that yourself).
        • smartmic2 hours ago
          I am happy with <a href="https:&#x2F;&#x2F;github.com&#x2F;pyrmont&#x2F;churlish" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;pyrmont&#x2F;churlish</a>
  • 1313ed0110 hours ago
    There is also fennel, earlier language originally by same developer, that is similar, but compiles to, and is fully implemented in, Lua. No standard library of its own so missing many nice things like the parser library from janet, but it is good for writing scripts for things that embed Lua.<p><a href="https:&#x2F;&#x2F;fennel-lang.org&#x2F;" rel="nofollow">https:&#x2F;&#x2F;fennel-lang.org&#x2F;</a>
    • ux2664787 hours ago
      Fennel really is great, and a great way to get into the clojure family. My biggest gripe with it is that debugging is the typical transpilation bed of needles. The bridge between Fennel and the Lua VM is super fragile, and it just doesn&#x27;t have half the quality of the Janet debugger and REPL. It&#x27;s a real shame, because Fennel is way more portable, and thanks to LuaJIT is capable of breaking SBCL&#x27;s jaw, which is absolutely fucking <i>insane</i>. But the transpilation experience just completely kneecaps it imo. There are workarounds you can do, but even if you mess around with implementing a debug.setinfo you still run into less-than-fun edge cases like with match-blocks.<p>I think there&#x27;s a lot of value in forking LuaJIT2 and reworking the debugging and error structures within to make it more suitable for language transparency. Doing so would make languages like Fennel much more attractive.
      • radiator13 minutes ago
        Relevant issue #1457 VM instrumentation for third-party tools <a href="https:&#x2F;&#x2F;github.com&#x2F;LuaJIT&#x2F;LuaJIT&#x2F;issues&#x2F;1457" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;LuaJIT&#x2F;LuaJIT&#x2F;issues&#x2F;1457</a> was opened by Mike Pall as recently as three weeks ago.<p>I gather that some features will be added to 2.1 but others only to 3.0.
      • JHonaker7 hours ago
        &gt; capable of breaking SBCL&#x27;s jaw<p>What exactly do you mean by this? Speed? Portability? Ease of use?
        • ux2664784 hours ago
          What I mean by that is that it&#x27;s in the same weightclass of speed, depending on the problem being tackled. In the case where data&#x27;s shape is mutable, SBCL will scream ahead thanks to CLOS. You can cheat LuaJIT with dynamically-defined C-structures via abuse of the FFI lib instead of native tables, but it&#x27;s not as nice as CLOS nor is it very safe. In the case that the shape of data is changed extremely frequently? CLOS might actually end up falling behind here. Another area where SBCL will likely win out is when the hotpath is bottlenecked on string operations.<p>Where I&#x27;d say it advances into breaking SBCL&#x27;s jaw is that the runtime, interpreter, jitter, etc. are all much smaller than SBCL&#x27;s runtime and compiler. If you&#x27;re looking for a complete system, I&#x27;d say SBCL wins out obviously. You&#x27;re talking a world-class REPL, debugger, a high quality stdlib, etc. All it&#x27;s missing is a text editor like LispWorks (emacs and pretty much every other FOSS Lisp editor I&#x27;ve seen is a massive downgrade.) With that in mind, SBCL is not something you embed in an application written in another language. The holy grail is getting something as fast as SBCL, as flexible as SBCL, but as a 50k loc self-contained runtime. LuaJIT is the reigning heavyweight champ there, so having a Lisp-adjacent language like Fennel running atop it is a pretty damn compelling idea.<p>Interestingly with regards to text editors, Lua doesn&#x27;t have that problem technically. Lite-XL is dangerously close to being zmacs&#x2F;LispWorks for Lua. Poetically, just like Lua it&#x27;s fairly bare bones and requires extension to be a decent IDE. But the underlying structure is absolutely fantastic, being based around a fairly cohesive object model rather than coats of paint over text buffers.
      • chamomeal6 hours ago
        Is fennel clojure-ish? I’m vaguely aware of it being a lisp, but I didn’t know it was clojure-ey. Pretty neat sounding!
        • veqq5 hours ago
          All new Lisps since ~2010 have been Clojure-y-: <a href="https:&#x2F;&#x2F;p.hagelb.org&#x2F;new-lisps.html" rel="nofollow">https:&#x2F;&#x2F;p.hagelb.org&#x2F;new-lisps.html</a> (Lone Lisp and LispE are the only exceptions and LispE still has _some_ Clojure features.)
  • xrd9 hours ago
    The author made these using Janet (discussed on HN in the past):<p><a href="https:&#x2F;&#x2F;bauble.studio" rel="nofollow">https:&#x2F;&#x2F;bauble.studio</a><p><a href="https:&#x2F;&#x2F;toodle.studio" rel="nofollow">https:&#x2F;&#x2F;toodle.studio</a><p>Those two fascinating art tools got me very excited about Janet a while back.
  • ramblurr11 hours ago
    Always nice to see janet getting some attention.<p>shout out to one modern feature: sandbox<p>&quot;Disable feature sets to prevent the interpreter from using certain system resources. Once a feature is disabled, there is no way to re-enable it.&quot;<p><a href="https:&#x2F;&#x2F;janet-lang.org&#x2F;api&#x2F;misc.html#sandbox" rel="nofollow">https:&#x2F;&#x2F;janet-lang.org&#x2F;api&#x2F;misc.html#sandbox</a>
    • declan_roberts9 hours ago
      It&#x27;s a really cool feature but what is a scenario when your average programmer needs such sandboxing?
      • myaccountonhn9 hours ago
        I sandbox all my utilities and programs in case some compromised third-party dependency decides to run lose. It&#x27;s a way to limit the blast radius.
      • briaoeuidhtns8 hours ago
        you&#x27;re embedding it as a scripting api and want to limit permissions to just what&#x27;s needed
      • petee8 hours ago
        The TIC-80 game engine embeds Janet, and if i recall sandboxes the games created
  • a-french-anon9 hours ago
    &gt; SETQ is def<p>At first I said &quot;what&quot; out loud, since SETQ doesn&#x27;t create bindings, it only updates them then I read the doc (<a href="https:&#x2F;&#x2F;janet-lang.org&#x2F;docs&#x2F;bindings.html" rel="nofollow">https:&#x2F;&#x2F;janet-lang.org&#x2F;docs&#x2F;bindings.html</a>) and the author is indeed wrong (&quot;bindings created with def are immutable&quot;). He probably meant &quot;SETQ is set&quot;.<p>I <i>really</i> want to like Janet, as it seems to be the sweet spot between Guile, Tcl and CL (minus the speed&#x2F;maturity of SBCL) but I have a visceral reaction to square brackets (so vectors) being used in lambdas and control flow operators. Same as Clojure, I simply can&#x27;t get over it. Maybe I will with enough effort?<p>Also, what&#x27;s the current LSP&#x2F;SLIME status? Really important these days.
    • nlitened9 hours ago
      Square brackets’ use is very consistent and rather logical in how they are used in Clojure’s syntax.<p>When round brackets are used, the first element in the list defines how the rest of the list is interpreted, for example:<p>(func a b c) — run a function with its parameters<p>(macro x y z) — expand a macro with its parameters<p>([p q r] …) — “bare” function body that starts with a vector of parameters, and executable forms follow.<p>Square brackets are used where elements are the same “kind”, and the first one is not special, e.g.:<p>(defn f [a b c] …) — a collection of same-kind parameters, the first parameter is not special<p>(let [a 1 b 2] …) — a collection of bindings, the first binding is not special<p>The only exception that comes to mind is grouping multiple matching elements in `case`, but it for ergonomics.<p>Once I got the logic, when which is used, I changed my mind, and ever since I’ve felt it’s beautiful.
      • a-french-anon8 hours ago
        Thanks a lot, that&#x27;s a very interesting way of seeing it.
    • iLemming2 hours ago
      &gt; I have a visceral reaction to square brackets<p>Once you understand how destructuring works in Clojure, it then becomes obvious what role square-brackets play.
    • veqq5 hours ago
      You can... just not use square (and curly) brackets. Instead of `[1 2 3]` just write `(array 1 2 3)`. Instead of `(fn [x] (+ 1 x))` just write `(f (x) (+ 1 x))`. They are never necessary.
      • BoingBoomTschak5 hours ago
        Huh! So like some Schemes and Racket? Yet I must read them in code that isn&#x27;t mine, which is a large part of the problem.
        • xigoi2 hours ago
          Not quitek in Scheme, parens and brackets are completely interchangeable.
  • mackeye9 hours ago
    janet has replaced sh, python, awk, etc. for me, for system scripts over a certain length! it has a very fast startup time (on my system, 1.4ms via hyperfine vs. 1ms for dash) for scripts (not compiled executables), and its sh-dsl module allows typing shell commands very elegantly, like ($ cmda w x | cmdb y z). the ability to load an image to debug is a big help, too. i&#x27;ve started using it very recently but it&#x27;s probably one of my favorite languages now, and the only other lisp i&#x27;ve used is mit scheme for sicp.
    • iLemming2 hours ago
      &gt; janet has replaced sh, python, awk, etc....<p>babashka did that for me.
      • yolkedgeek1 hour ago
        This is a great comparison and I&#x27;ve been wondering about it for a while.<p>Between babashka, janet(i discovered it just now), fennel, guile. Which one would be a better scripting language? Please tell me you experience, and if you are interested, we can work on a small article and benchmark about this.
        • iLemming43 minutes ago
          It&#x27;s platform-dependent isn&#x27;t it? Otherwise, the practical differences between Lisp dialects are negligible. For me writing either in Janet or Fennel or Clojure feels almost like writing in the same language.<p>Babashka has replaced bash-scripting for me. I don&#x27;t hate Bash, but why would I ever choose to use a language that has no true REPL, if I don&#x27;t have to? bb is pretty much Clojure, which is the greatest choice if you&#x27;re dealing with data - any data. Clojure is incredibly data-driven, which wins me over Janet. I also reach out to nbb whenever I need to deal with Node. e.g. scraping scripts driven by Playwright.<p>Janet is great when you need tiny runtime or you&#x27;re dealing with subprocess-heavy scripts - Janet feels closer to actual shell syntax; or when you have to embed it to C&#x2F;C++ program.<p>Fennel is indispensable for any Lua - mpv, Hammerspoon, AwesomeWM and Neovim configs, etc.
          • veqq4 minutes ago
            &gt; Clojure is incredibly data-driven, which wins me over Janet.<p>I&#x27;m curious what difference you see? I&#x27;ve been all in on Janet, but barely used Clojure. What more data driven aspects does Clojure have .... offer? My mental model&#x2F;assumption&#x27;s always been that Janet&#x27;s Clojure without JVM and (sadly) not so pure. I don&#x27;t use any of Janet&#x27;s C interop facilities.
  • krinne11 hours ago
    This post is refreshing - smells of the pre AI discussions on the internet. A new language, a new syntax, heavy debate with people who have spent years writing code. I think someone should start a community online where AI isnt allowed.
    • probably_wrong11 hours ago
      &gt; <i>I think someone should start a community online where AI isnt allowed.</i><p>In case you haven&#x27;t followed the saga, the latest[1] digg.com relaunch failed because they couldn&#x27;t deal with the bot onslaught [2]. Whoever finds a reliable way to keep AI out of an online community first is likely to become a very rich person.<p>[1] Second-to-last, actually, seeing as there seems to be a new homepage right now.<p>[2] <a href="https:&#x2F;&#x2F;www.techspot.com&#x2F;news&#x2F;111698-digg-relaunch-fails-two-months-ai-agents-spambots.html" rel="nofollow">https:&#x2F;&#x2F;www.techspot.com&#x2F;news&#x2F;111698-digg-relaunch-fails-two...</a>
      • andrewflnr6 hours ago
        I suspect real ways to keep AI out of a community, or really to have an online community at all, are going to be structurally incompatible with making anyone rich. The possibility of getting rich poisons the incentives.
      • dwedge10 hours ago
        &gt; In case you haven&#x27;t followed the saga, the latest[1] digg.com relaunch failed because they couldn&#x27;t deal with the bot onslaught [2]<p>Given that they wrote their goodbye post using LLMs and gave up after such a short amount of time, I don&#x27;t take that at face value the same way I don&#x27;t believe AI layoffs
      • flir9 hours ago
        We&#x27;ve already got models that can handle it - eg web of trust. We don&#x27;t want to use them.<p>Plus &quot;AI&quot; is a spectrum, with &quot;the AI fixed a typo for me&quot; at one end, and &quot;the AI writes my posts for me&quot; at the other.
        • makkes8 hours ago
          Web of trust has been a miserable failure because of the GPG&#x27;s horrible UX and high entry barrier. It&#x27;s dead, Jim.
          • andrewflnr7 hours ago
            I think they were referring to invitation trees like lobste.rs.
            • ASalazarMX4 hours ago
              That&#x27;s for children. Make the Pope a certification authority, and he can certify people he trusts, and so on, until the chain reaches you. When you commit a sin, your certificate gets revoked, along with its children.<p>It would give the web of trust a flair of biblical damnnation, and after your fall you could always seek a new certification authority more aligned with your values, like Milei or Putin.<p>When a world leader dies, the tree pruning would be almost apocaliptic.
      • layer88 hours ago
        &gt; Whoever finds a reliable way to keep AI out of an online community first is likely to become a very rich person.<p>I believe it’s the opposite: You have to pay competent human moderators. Like here on HN.
        • LtWorf7 hours ago
          Half the posts here are AI grifting.
          • whyenot7 hours ago
            That’s a pretty extraordinary claim. Do you have anything quantitative to back it up? HN has bots, I think that is a fair assumption, but half? How do you know that for sure?
            • GroksBarnacles6 hours ago
              [flagged]
              • dcuthbertson6 hours ago
                TIL that statements of obvious exaggeration are called causal, hyperbolic statements. Who knew?<p>All kidding aside, I&#x27;ve never heard them called causal hyperbolic before. It&#x27;s a good term.
      • ponkpanda10 hours ago
        Perhaps requiring webauthn credential for any post&#x2F;comment with a whitelist of permitted webauthn hardware devices which must have touch&#x2F;interaction enabled.<p>I&#x27;d have to read the FIDO specs, however the only place I&#x27;ve seen webauthn hardware pinning in the wild is with Azure AD&#x2F;Entra which is ostensibly based on token GUID. If this is the only enforcement mechanism available, it&#x27;s spoofable.
        • nkrisc8 hours ago
          Then you’ll end up with a forum of only bots because they’ll spoof it and real people won’t put up with the hassle.
        • tialaramex9 hours ago
          FIDO tokens are designed to able (if authorized by the software, your web browser typically offers a pop-up where you can decline this) to prove their membership of a batch of tokens, but not their individual identity.<p>The Entra feature you thinking of lets somebody say &quot;Only things which can prove they&#x27;re in this list work&quot;. This <i>could</i> make sense if you, as their employer, issue every employee a custom DoodadCorp Doodad FIDO key and so you don&#x27;t want somebody&#x27;s Yubikey or off-brand generic device to work. It&#x27;s <i>stupid</i> and you shouldn&#x27;t do it in other scenarios, but your &quot;this is how we detect humans&quot; idea is arguably a scenario where that could make sense.<p>[Edited to add: This feature is called &quot;Attestation&quot;]
        • wbl7 hours ago
          Doesn&#x27;t actually work that well. Browsers hate this, the hardware isn&#x27;t actually difficult for bots to access, and privacy story is bad. There are solutions being worked on.
        • layer88 hours ago
          This would result in hardware farms of such devices being automatically operated, like the existing iPhone farms used for similar purposes.
      • Cassell5 hours ago
        Altman’s orb is as terrifying as it is because businesses might see it as a solution to a real problem—a problem he helped to create.
        • throwway1203854 hours ago
          The reason we didn&#x27;t see it in the US first is because he was probably gathering data from a pilot system. When he finishes his moonbase and&#x2F;or volcano lab then we should probably start moving to the Northern Territories or the Yukon.
      • 21asdffdsa129 hours ago
        Pay per interaction model? 1 cent per post.
        • intrasight7 hours ago
          Probably the only solution. But the penny has been deprecated so it will have to be a nickel.
          • imglorp7 hours ago
            Only copper was deprecated. Real $0.01 absolutely exists in your bank etc.<p>Anyway, marketers see a popular site like a physical billboard, where they would pay thousands a month for their message to be seen by thousands of people. If you made it cost pennies to post, and a few more pennies to boost and astroturf, AND that the post would be seen by millions of people, they&#x27;d say &quot;By Grabthar&#x27;s hammer, what a bargain!!&quot; and order a hundred more per day...
        • phainopepla23 hours ago
          I think pay per account (like the Metafilter model) would be better. If you charge $10 for lifetime access and ban slop-posters, it quickly becomes expensive to be a slop merchant
      • kitd8 hours ago
        Age verification with facial ID? ;)
      • geokon11 hours ago
        lobste.rs uses a web-of-trust referral system. I guess it still involves a moderator killing off bad nodes, but it seems to scale well
        • usefulcat4 hours ago
          &gt; it seems to scale well<p>This seems hard to say without knowing how large it is. To me, it seems like a relatively small community, far smaller than HN anyway.
        • dust-jacket10 hours ago
          yeah but I can&#x27;t post there because I don&#x27;t know anyone with an account and frankly CBA traipsing around looking for someone who has an account.<p>does seem like more things will have to go this way though
          • ramon15610 hours ago
            +1, if anyone wants to help me I&#x27;d be honored. mail me at ramon(@)odeva(.)nl
          • Timwi1 hour ago
            [dead]
      • pbronez9 hours ago
        Isn’t the solution high-quality identity verification? There are piles of digital identity companies out there. They make money selling to banks for KYC compliance. Heck, there are background check as a service companies designed to add trust to gig economy platforms.<p>I used to think that a small payment could accomplish the same thing, but X selling blue check marks proved that doesn’t help much. Well, at least it’s a much weaker signal than the previous curated version.<p>The challenge is any barrier to entry high enough to discourage motivated spammers is also high enough to discourage casual users. That disrupts the network effects you’ve traditionally needed to bootstrap a social website.<p>If I was trying to get a new social site off the ground right now, I would try:<p>1) secure a good brand from the pre-AI era. Twitter, Digg, Friendster, MySpace. Something that motivates a first look.<p>2) Require third party identity verification on sign up, configured so the social site is never the custodian of PII, though require enough demographics to support high-value advertising later. Verification is free to the user, ideally provide multiple verification options- one US and one EU at minimum.<p>3) Target a few core communities and invest. Find the people who moderate historically great subreddits, were active in twitter communities during the good years, etc. get them in your platform. Maybe even pay them.<p>That should be enough to tell you if it’s going to work or not.
      • Decabytes8 hours ago
        Blizzard&#x27;s Real ID system would fix all of this. It was ahead of it&#x27;s time &#x2F;s
    • 9dev10 hours ago
      &gt; a community online where AI isnt allowed.<p>This is something I think about a lot, especially how one could pull it off without tearing down anonymity online. Having some sort of &quot;proof of humanity&quot; is a hard problem to solve.
      • mr-pink8 hours ago
        not really, you can just ask people to do a shit job identifying traffic lights and motorcycles and they&#x27;ll do it.
    • DoughnutHole11 hours ago
      The amazing thing about AI is that you don’t even need AI superfans to shoehorn it into a conversation that doesn’t even touch on AI. Detractors will do it for them.
      • NuclearPM10 hours ago
        Yes, it’s similar to Trump. But that makes sense right? AI is changing the world drastically, and so is Trump and his fascist friends.
    • wmedrano5 hours ago
      Ironically, the top comment (this) is now about AI.
    • matheusmoreira7 hours ago
      &gt; I think someone should start a community online where AI isnt allowed.<p>That&#x27;s lobsters I guess. AI posts got banned there after a 300+ comment discussion, probably the biggest ever on the site.<p>The exact rule the moderators settled on was &quot;meaningful human authorship&quot; but don&#x27;t be fooled: a lot of people on lobsters are <i>ideologically</i> opposed to LLMs. Doesn&#x27;t matter how &quot;meaningfully&quot; the technology was applied. My work was classified as slop simply because AI touched it. People referred to me as an exhibitionist and fetishist when I talked about using AI. Just a heads up for anyone who&#x27;s thinking of joining.
      • crumpled7 hours ago
        on my way!
        • Linux-Fan3 hours ago
          I like the Lobsters stance on AI. Also posts are tagged hence you can decide for yourself if the topic may be interesting <i>despite</i> being touched by AI.<p>I haven&#x27;t found a way to join Lobsters yet hence for the meantime I keep posting here only. Not so much of an issue since I am mostly a happy lurker.
          • matheusmoreira3 hours ago
            Here&#x27;s the lobsters stance in case anyone is wondering:<p><a href="https:&#x2F;&#x2F;lobste.rs&#x2F;s&#x2F;29pm2f&#x2F;llm_generated_submissions_should_be" rel="nofollow">https:&#x2F;&#x2F;lobste.rs&#x2F;s&#x2F;29pm2f&#x2F;llm_generated_submissions_should_...</a><p>TL;DR Plenty of ideological opposition which will loudly call you out for <i>any</i> usage of AI, and also quite a few nuanced takes which will no doubt be overridden by the vocal opposition. It got to the point the site itself told me to leave.<p>I don&#x27;t feel comfortable posting my projects there anymore, even though they do have meaningful human authorship. Still have my account, but I&#x27;m essentially a lurker now. I&#x27;ll participate if someone else independently posts my stuff there.<p>Feel free to reach out and introduce yourself if you want an invite.
    • shevy-java11 hours ago
      &gt; a new syntax<p>How is the syntax new?<p>It looks like lispy - see the outer parens in the examples given.
      • embedding-shape10 hours ago
        Heh, every time you show a average developer lisp for the first time the reaction is the same. Little do they know conditionals, GC, REPLs, macros and more comes from the syntax and language dreamed up in the 50s&#x2F;60s.
        • maleldil9 hours ago
          I don&#x27;t see why Lisp&#x27;s history would necessarily imply the family is worth learning in 2026. What (other than macros) do lisps offer that other modern languages don&#x27;t?
          • drob5189 hours ago
            You don’t program in Lisp, do you? I used to be confused by the smug Lisp weenies. Now I am one. And the difficult thing I’ve found over the years is that Lisp is sort of unexplainable. You either “get it” or you don’t. Yes, it has macros, but macros are a bit overrated. I’ve been programming in Lisp for decades and I rarely write macros. I think the thing that is difficult to convey is how powerful Lisp’s core execution environment is while at the same time being just a page of code that a CS undergraduate can understand. Literally everything else is a library. And those libraries can create syntax, generate code on the fly, and do many other powerful things. But most people won’t “get it” until they take the plunge. I didn’t. Until I did. And now, I don’t feel a need to defend Lisp at all. It won’t go away. You can’t kill it. The folks that “get it” will always have it, and those that don’t “get it” will reach for their Blub language again and again. Such is the way of the world.
            • matheusmoreira5 hours ago
              Yeah, I didn&#x27;t get it either until I implemented my own lisp.<p>&gt; the difficult thing I’ve found over the years is that Lisp is sort of unexplainable<p>I&#x27;ve found that getting rid of the parentheses helps.<p><pre><code> f(x) (f x) [&quot;f&quot;, &quot;x&quot;] (print (&lt; 10 20)) [&quot;print&quot;, [&quot;&lt;&quot;, 10, 20]] </code></pre> Lisp code is just normal Python lists which get evaluated by an interpreter function. Like this:<p><pre><code> code = [&quot;print&quot;, [&quot;&lt;&quot;, 10, 20]] def eval(code): # magic eval(code) True </code></pre> Filling out that eval function is a great way to learn lisp.<p>These articles are very good and accessible:<p><a href="https:&#x2F;&#x2F;www.norvig.com&#x2F;lispy.html" rel="nofollow">https:&#x2F;&#x2F;www.norvig.com&#x2F;lispy.html</a><p><a href="https:&#x2F;&#x2F;norvig.com&#x2F;lispy2.html" rel="nofollow">https:&#x2F;&#x2F;norvig.com&#x2F;lispy2.html</a>
            • frwrfwrfeefwf4 hours ago
              Getting lisp is analogous to spiritual enlightenment. If someone doesn&#x27;t have the eyes to see and ears to hear, there&#x27;s little you can do for them, except pray.
            • maleldil6 hours ago
              &gt; You don’t program in Lisp, do you?<p>Not anymore. I started with Racket and went through the Little Schemer. I did Clojure for a while. I even used Babashka to write all my scripts, then later rewrote them in other languages.<p>I gave it a good try. Maybe it wasn&#x27;t enough to properly &quot;get it&quot;?
              • chamomeal5 hours ago
                Aw man I love babashka. I will say the lack of static types in clojure is pretty brutal for me. Especially when combined with the obtuse error messages. But I still love babashka and the whole REPL driven world.<p>What did you end up rewriting your bb scripts in?
                • drob5185 hours ago
                  If there&#x27;s one thing that I sometimes wish Lisp had, it&#x27;s types. Most of the time, I don&#x27;t need or even want them. But when you&#x27;re doing a big refactor or changing the shape of your primary data structure, it would be nice to have the compiler be able to assist you in detecting locations where you&#x27;ve cross-wired something. But other than that, I don&#x27;t care. And yes, Clojure&#x27;s error messages could be better, but they have been getting better over time.
                  • tmtvl1 hour ago
                    &gt; <i>If there&#x27;s one thing that I sometimes wish Lisp had, it&#x27;s types.</i><p>Let&#x27;s write some very silly code to turn an integer into a list of digits in Common Lisp:<p><pre><code> (deftype Digit () &quot;A non-negative integer smaller than 10.&quot; &#x27;(Mod 10)) (defun integer-&gt;digits (integer) &quot;Turns a given INTEGER into a list of digits.&quot; (declare (type Integer integer)) (labels ((digit-loop (integer digits) (declare (type Integer integer) (type List digits)) (if (&lt; integer 10) (list* integer digits) (multiple-value-bind (quotient remainder) (truncate integer 10) (declare (type Integer quotient) (type Digit remainder)) (digit-loop quotient (list* remainder digits)))))) (declare (ftype (Function (Integer List) List) digit-loop)) (digit-loop (abs integer) nil))) (digit-loop 2026) ; =&gt; (2 0 2 6) (digit-loop &quot;2026&quot;) ; The value ; &quot;2026&quot; ; is not of type ; INTEGER ; when binding INTEGER ; ; Type HELP for debugger help, or (SB-EXIT:EXIT) to exit from SBCL. ; ; Restarts: ; 0: [ABORT] Exit debugger, returning to top level.</code></pre>
              • drob5185 hours ago
                That&#x27;s a very reasonable try. Your statements are not unfounded. If I may ask, what&#x27;s your daily driver now and why do you favor it over Lisps?
            • layer88 hours ago
              There are reasons why not that many programmers “get it”, and it’s not because the others are uninformed. It’s a matter of valuing different things.
              • embedding-shape6 hours ago
                Hmm, that&#x27;d be weird, how do you know you &quot;value something different&quot; if you haven&#x27;t &quot;got it&quot;? You&#x27;d need to &quot;get it&quot; first, then you can understand if you value something different or not, otherwise how would you know?
                • layer85 hours ago
                  The usual insinuation is that if you don’t like it, you “just don’t get it”. I meant not “getting it” in that sense.
              • drob5187 hours ago
                Absolutely! But it’s also because they don’t really understand one of the things. It’s the Blub Paradox.
            • cdelsolar8 hours ago
              this is incredibly smug, but fun to read :) I briefly &quot;got&quot; Clojure but forgot again. Maybe I&#x27;ll give this Janet thing a try.
              • drob5185 hours ago
                LOL, indeed. Clojure is fun. I haven&#x27;t used Janet, but I appreciate seeing some of the good ideas that it stole from Clojure (stealing being the sincerest form of flattery, and all that). IMO, one of Clojure&#x27;s greatest gifts, above and beyond other traditional Lisps like CL and Scheme, is its focus on immutable data structures. When I started playing with Clojure, I was skeptical. I figured performance was going to be horrible. Now, I can&#x27;t live without them. It&#x27;s one of those subtle features that just changes how you program. It&#x27;s one reason I choose Clojure over CL and Scheme today. Janet seems to have both mutable and immutable data structures, which is nice. Clojure has transients, but that&#x27;s sort of partially mutable. That said, with Clojure, one of the nice things is that you can always drop back to Java&#x27;s full mutability if you want, but that&#x27;s obviously relying on the platform and not Clojure the language.
            • cmrdporcupine3 hours ago
              Honestly... it&#x27;s entirely possible to &quot;get&quot; Lisp and at the same time not really see anything that compelling about it for doing your own work.<p>I &quot;get&quot; Lisp just fine, have made my own hobby Lisp interpreters, have written programs in Lisp, am an emacs user, etc. etc.<p>And yet if you handed me a terminal and an editor and asked me to write a program, I would never reach for Lisp to do it. My eyes don&#x27;t like it. (Also I like static types).
          • evdubs4 hours ago
            S-expressions. Defining data in JSON or XML is way worse than S-expressions.
          • BoingBoomTschak5 hours ago
            Just saying &quot;macros&quot; is a bit reductive: in CL, you have access to the full language at (read) parse time, compile time and runtime. Said macros also mean that logical OR&#x2F;AND short-circuiting isn&#x27;t a compiler black box, you can implement such behaviour easily yourself.<p>------<p>The syntax is actually a big pro for a lot of people. I love its streamlined look that basically reads like Python once you let your IDE indent properly and learn to see &quot;through&quot; the parentheses (CL, Scheme).<p>The original language where everything is an expression and it shows. Where Python still needs an ugly ternary and made match a statement, Lisp has had the perfect IF and COND since the dawn of time.<p>Symbols are still a cool and useful concept that almost no other language I know of got.<p>The numerical tower - despite some holes - is amazing. Built-in rationals and &quot;correct math&quot; as sane default (i.e. 1&#x2F;2 not returning 0) never get old.<p>------<p>And if you let me rave about CL specifically (e.g. DECLARATIONs as &quot;#pragma done well&quot;, restarts, CLOS&#x2F;MOP, runtime READ&#x2F;COMPILE, etc...), there are a lot of cool features barely copied anywhere that&#x27;d improve other languages, but these aren&#x27;t part of &quot;what make Lisp Lisp&quot;.
    • soomtong11 hours ago
      It’s been a few months, but I built a tool by Janet lang to communicate with an LLM via HTTP. Of course, I probably had Claude Code write it for me. It turned out better than I expected.<p>I was really impressed by how small the executable file was. I’d only ever done web development with Node.js up until then.
  • uka11 hours ago
    &gt; But by allowing you to unquote literal functions, Janet makes it possible to write macros that are completely referentially transparent.<p>These lisp guys really get excited over very abstract things. If you say this to an average person on the street they will probably try to run away.
    • fredrikholm9 hours ago
      &gt; very abstract things<p>A C macro with literals that lacks referential transparency:<p><pre><code> #define MULTIPLY(x, y) x * y int result = MULTIPLY(2 + 3, 4); &#x2F;&#x2F; 14 </code></pre> Not knowing what something means does not make it bad, which is what I&#x27;m assuming you meant given how you phrased your sentence.<p>Having a shared language of patterns and problems that occur in programming is a good thing. Ridiculing such terminology on the basis of &quot;that group of programmers sure are weird&quot; is pointless and counter productive.
      • uka6 hours ago
        Thank you for the lesson. Very productive of you and on point.<p>Now if you relaxed just a little bit - the world would be much nicer place.
    • bryanrasmussen11 hours ago
      you ever try to explain object oriented programming languages and their benefits to the &quot;average person on the street&quot;?
      • rambrrest11 hours ago
        somehow i also never got the idea around these languages like lisp. I remember i studied them in school - but i quickly forgot and never got around to relearning it.
        • barrell10 hours ago
          It took me probably 5 years of writing Clojure before it clicked. Once you get used to structural editing and repl driven development, it’s really hard to go back to syntactic languages.<p>It’s kind of like in treesitter style editing, where you can “swap these two arguments,” “select this function,” “wrap this in a try block” with a single keyboard command… but way more standardized and granular. Plus with the ability to execute anything you highlight<p>All that and then you realize you can store code as data (since it’s just a data structure) and run data as code.<p>I think most programmers don’t realize how arbitrary the difference is between code and data until they get used to using LISP.
          • drob5188 hours ago
            Spot on. For me, it clicked with Common Lisp, 15 years after I graduated from university. Now, Clojure is my daily driver. And it’s extremely difficult to explain to people. I’ve gotten to the point where I don’t even try. You’re right about all the things you mentioned. Once you discover structural editing, everything else seems primitive, on the level of cavemen playing with rocks. But it’s not just one feature that makes Lisp better. It’s all of it which interrelates and creates a powerful synergy (I hate that word, but in this case it’s appropriate) that just isn’t matched by anything else. There are other languages that have a similar vibe, notably Forth and Prolog, but they are often misunderstood, too. Honestly, that’s my real test of whether someone is a senior programmer: do they understand and at least have an appreciation for these languages, even if they don’t program in them everyday.
        • xigoi11 hours ago
          The idea is that instead of having to learn tens of different syntactic constructs with subtle and often arbitrary differences, you just have parentheses and use them to build everything.
          • embedding-shape10 hours ago
            This is such a undervalued benefit, once you&#x27;ve learned s-expressions, you can basically learn a bunch of languages without having to learn completely new syntax. It&#x27;ll be slightly different, with different idioms and names, but a hell of a lot easier than doing the same across every &quot;It&#x27;s like C but 50% of the syntax is different actually&quot; language out there, which is most of them.
            • jurip9 hours ago
              Is the <i>syntax</i> really the stumbling block for most languages? Would Rust&#x27;s lifetimes or Swift&#x27;s isolation rules be easier if they used more parens? Are the scoping rule differences between Emacs Lisp and Scheme easier to comprehend because the syntax is similar?
              • lelanthran42 minutes ago
                &gt; Would Rust&#x27;s lifetimes or Swift&#x27;s isolation rules be easier if they used more parens?<p>For me, certainly. But it&#x27;s not a matter of adding parens, it&#x27;s more removing extra syntax.
              • embedding-shape9 hours ago
                Yes, a commonly occurring stumbling block for me is trying to use one language&#x27;s syntax while actually programming in another, especially when it comes to all the Algol&#x2F;C-like language, I probably mix things on a daily basis.<p>The concepts would be easier to grok up front if they just used normal function calls instead of &quot;And now for this special syntax that only exists for this particular feature&quot; which just adds more things to remember, instead of just the concepts themselves.
              • dragandj9 hours ago
                Yes it is, because as soon as programmers step out of the most basic language level (which is kinda similar in most mainstream languages) there&#x27;s a bunch of wildly different concepts, with wildly different ways of writing them. Writing them in isolation might be manageable, but it&#x27;s combining them effectively that gets hairy very quickly, unless one is very experienced in said language. But then, translating that to OTHER languages becomes a bar that is too high!
              • iLemming4 hours ago
                [dead]
          • layer88 hours ago
            That just moves the subtle and often arbitrary differences to the functions and macros you use.
            • xigoi7 hours ago
              The kind of subtle difference I’m talking about is that in C, you have to put a semicolon after struct {…} and do {…} while (…), but not after other curly brace constructs. What would be the analogue in Janet?
              • layer87 hours ago
                The first one is pretty C-specific and for example doesn’t exist in Java. Similarly for the second one, the reason is that `while` is used for two different constructs, which for example isn’t the case in Rust. These are just accidental complexities stemming from unfortunate design decisions in C. Having a richer repertoire of syntactic constructs doesn’t by itself imply such complications.<p>My point was, replacing <i>n</i> syntactic constructs by <i>n</i> functions or macros doesn’t reduce the cognitive load of having to know how each construct works. To the contrary, one can argue that everything having the same syntactic form makes it more difficult to distinguish different classes of features.
                • xigoi7 hours ago
                  &gt; The first one is pretty C-specific and for example doesn’t exist in Java.<p>It was just an example, most languages have quirks like this. I don’t know about Java, but in Rust you have the turbofish operator, whose necessity stems from using the less-than sign as both an operator and a delimiter.<p>&gt; My point was, replacing n syntactic constructs by n functions or macros doesn’t reduce the cognitive load of having to know each of them.<p>The difference is that if you don’t know a function&#x2F;macro, you can just read its documentation. If you don’t know a syntactic construct, where do you look?<p>Another advantage is that if you want to create new functionality similar to existing language features, it won’t stick out like a sore thumb. For example, you could create an until loop:<p><pre><code> (until (window-should-close) (draw-screen)) # is equivalent to (while (not (window-should-close)) (draw-screen)) </code></pre> In Rust, it would have to look completely different from a while loop:<p><pre><code> until!(window_should_close(), draw_screen()); &#x2F;&#x2F; is equivalent to while window_should_close() { draw_screen(); }</code></pre>
        • zelphirkalt11 hours ago
          Probably depends on whom you are asking. For me the essence is (1) having functions or procedures as the basic building blocks, not classes. (2) Having all the utility and higher order functions you need to deal with the functions and procedures first idea. (3) Having a very powerful syntax, that allows great semantic editing and is never ambiguous. Oh and can actually be extended in useful ways, without having to wait for a committee to decide upon &quot;the one syntax to rule them all&quot;.
          • veqq5 hours ago
            &gt; can actually be extended in useful ways<p>I just made a library with [query syntax](<a href="https:&#x2F;&#x2F;codeberg.org&#x2F;veqq&#x2F;declarative-dsls" rel="nofollow">https:&#x2F;&#x2F;codeberg.org&#x2F;veqq&#x2F;declarative-dsls</a>) over various data structures a la sql:<p><pre><code> (import declarative-dsls&#x2F;dataframes :as df) (def people (df&#x2F;dataframe :name :age :job)) (df&#x2F;dataframe? people) (df&#x2F;insert! {:name &quot;Bob&quot; :age 30 :job &quot;Developer&quot;} :into people) (df&#x2F;insert! {:name &quot;Alice&quot; :age 27 :job &quot;Sales&quot;} :into people) (df&#x2F;update! :set {:job &quot;Engineer&quot;} :where |(= ($ :job) &quot;Developer&quot;) :from people) (df&#x2F;save-csv people &quot;people.csv&quot; :sep &quot;\\t&quot;) (def people2 (df&#x2F;load-csv &quot;people.csv&quot; :sep &quot;\\t&quot;)) (-&gt; people2 df&#x2F;dataframe-&gt;rows df&#x2F;rows-&gt;dataframe df&#x2F;print-as-table) </code></pre> Printing:<p><pre><code> job age name -------- --- ----- Engineer 30 Bob Sales 27 Alice </code></pre> It also has datalog and minikanren (with s expr, sharing the same goals etc.) And it vectorizes like APL:<p><pre><code> (df&#x2F;v + [1 2 3] 1 [1 2 3] 1) # returns: [4 6 8] (df&#x2F;v + 1 {:column [1 2 3] :key [1 2 3]}) # returns: {:column @[2 3 4] :key @[2 3 4]} (df&#x2F;v * [1 2 3] [[1 1 1] [1 2 2] [1 2 3]]) # returns: @[@[1 1 1] @[2 4 4] @[3 6 9]] </code></pre> Or you can just use [J directly from Janet](<a href="https:&#x2F;&#x2F;git.sr.ht&#x2F;~subsetpark&#x2F;jnj" rel="nofollow">https:&#x2F;&#x2F;git.sr.ht&#x2F;~subsetpark&#x2F;jnj</a>):<p><pre><code> (jnj&#x2F;j &quot;3 4 $ i. 10&quot;) # returns: ((0 1 2 3) (4 5 6 7) (8 9 0 1)) (jnj&#x2F;j &quot;$&quot; [3 4] (range 10)) # returns: ((0 1 2 3) (4 5 6 7) (8 9 0 1)) </code></pre> The Joy Web Framework has a cool [db query dsl](<a href="https:&#x2F;&#x2F;github.com&#x2F;joy-framework&#x2F;joy&#x2F;blob&#x2F;master&#x2F;docs&#x2F;database-queries.md" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;joy-framework&#x2F;joy&#x2F;blob&#x2F;master&#x2F;docs&#x2F;databa...</a>) too: `(var account (db&#x2F;find-by :account :where {:login (auth-result :login)}))`, used for a [web auth](<a href="https:&#x2F;&#x2F;codeberg.org&#x2F;veqq&#x2F;janetdocs&#x2F;src&#x2F;commit&#x2F;848dcbd8e54ad5e0e8555abc0b5c72dab1720282&#x2F;routes&#x2F;home.janet#L79" rel="nofollow">https:&#x2F;&#x2F;codeberg.org&#x2F;veqq&#x2F;janetdocs&#x2F;src&#x2F;commit&#x2F;848dcbd8e54ad...</a>).<p>From my response, bigger than the article: <a href="https:&#x2F;&#x2F;lobste.rs&#x2F;s&#x2F;y0euno&#x2F;why_janet_2023#c_lspe6n" rel="nofollow">https:&#x2F;&#x2F;lobste.rs&#x2F;s&#x2F;y0euno&#x2F;why_janet_2023#c_lspe6n</a>
        • iLemming3 hours ago
          &gt; studied them in school - but i quickly forgot and never got around<p>Because industry lied to you, promising &quot;simplicity and riches&quot;. The industry didn&#x27;t just overcomplicate programming. It institutionalized the complication. Why? Because complexity is a moat.<p>Complex frameworks need certified experts. Certified experts charge more. Companies built around expertise need the complexity to persist. So the complexity gets marketed as sophistication.<p>They&#x27;ve promised: &quot;Java&#x2F;C# will get you hired anywhere&quot;, but you&#x27;re hired to write xml (these days yaml). &quot;OOP models the real world&quot;, they said. The real world doesn&#x27;t have abstract factory visitors. &quot;Design patterns make you senior&quot;, but you only learned workarounds for language deficiencies. &quot;Learn the framework, get the job&quot;. Framework dies, you start over. &quot;Specialization is valuable&quot;. you&#x27;re now hostage to one ecosystem.<p>A programmer who understands fundamentals is dangerous to this system. The fundamentals:<p>- a function transforms input to output.<p>- composition builds complexity from simplicity.<p>- types describe what&#x27;s possible.<p>- effects should be explicit.<p>And then you realize that Lisp is the skeleton key. All that above is Lisp, or came from Lisp. Every language is either: Lisp with different syntax, or C with different syntax, or arguing between the two.<p>If you learn Lisp, you don&#x27;t learn a language. You learn what languages are. You&#x27;re no longer a consumer of a programming language or two, or a few. You are native speaker in all of them.
      • skeledrew9 hours ago
        Pretty straight-forward, as the world as we perceive it is made of objects with attributes, interacting with each other via their methods. OOP easily fits the brain of the average person in the street.
        • iLemming2 hours ago
          &gt; the world as we perceive it is made of objects<p>Of course easier to explain the &quot;strategy pattern&quot; to a florist, instead of saying &quot;imagine a function that takes a function&quot;. Who the hell understands functions? Such a mind-bending concept, literally nobody really knows how they work. Einstein famously complained about it. Too bad he didn&#x27;t know OOP - would&#x27;ve been so much easier. I couldn&#x27;t grok general and special relativity for so long, thank god I&#x27;ve found Java - it made it so much easier. I don&#x27;t know what Persian mathematicians been smoking in 12th century to come up with this utterly fucked up idea of a function. And fuck Leibniz as well.
        • the_af8 hours ago
          [dead]
    • wmedrano3 hours ago
      I started writing a Scheme interpreter about a year ago and got pretty far. I dropped it a few months back since I got a new job.<p>I&#x27;m thinking of getting back and am wondering if the niche (and difficult for me to implement) features are worth it. I might be better off skipping dynamic-unwind, maybe even ripping out call&#x2F;cc, in favor working on the debugability, ecosystem, performance, and package management story.
    • SoftTalker3 hours ago
      &gt; If you say this to an average person on the street they will probably try to run away.<p>This is the average reaction I get any time I get the &quot;so what do you do&quot; question. I try to stay very vague &quot;I do computer work&quot; or something. Or I&#x27;ll say &quot;Oh, nothing interesting&quot; and try to change the subject. Any more specific than that and they start looking for the exits.
    • prerok10 hours ago
      Average programmer too &#x2F;j<p>Frankly, though, I think lispy community has benefited from being smaller. For example, even though the now ancient Design Patterns already warned programmers to prefer composition over inheritance, the OO programmers still created 15 levels deep hierarchies.
    • iLemming4 hours ago
      &gt; over very abstract things.<p>I beg to differ. There&#x27;s just isn&#x27;t &quot;easy and straightforward&quot; path to simplicity. We thought that explaining the world with &quot;objects&quot; was simple and instead of using already existing language, OOP took &quot;objects&quot; (an easy choice) and invented a elaborate taxonomy of &quot;patterns&quot; to work around the limitations of objects. Just look at this mess:<p>- Strategy Pattern: Interface + multiple classes + dependency injection + factory maybe. Bruh, it&#x27;s just a function that takes a function.<p>- Singleton: Private constructor + static instance + thread safety + double-checked locking. Bruh, it&#x27;s a fucking value. You define it once. It doesn&#x27;t change. You&#x27;re done.<p>- Observer&#x2F;Event System: Interface + listener registration + event loop + memory leak when you forget to unsubscribe. Bruh, tis a fucking function applied to a list (or stream).<p>- Decorator; Wrap a class in another class that implements the same interface. Bruh - it&#x27;s function composition. You learned this in algebra class before you turned fourteen.<p>- Command: Encapsulate a method call as an object with execute(), undo(), history queue... It&#x27;s a function stored in a variable. That&#x27;s it. That&#x27;s the pattern.<p>- Factory: Separate class whose entire job is to call constructors. Come on, it&#x27;s just a fucking function.<p>- Template Method: Abstract base class with a method that calls abstract methods subclasses must override. It&#x27;s a higher-order function.<p>- Iterator: Interface with hasNext() and next(), mutable state, ConcurrentModificationException. It&#x27;s fucking map.<p>The Gang of Four book exists because Java made functions second-class citizens, so programmers spent 20 years building elaborate object scaffolding to simulate... functions. FP didn&#x27;t solve these problems. It just never had them.<p>Yet somehow the industry likes to pretend that every programmer knows (or should know) OOP, while keep telling everyone how hard programming is.<p>Those who found the truth understand that there&#x27;s a reason why Lisp just refuses to die and it&#x27;s unlikely it ever will. At 70 years, it is still flourishing.
      • Jtsummers1 hour ago
        &gt; The Gang of Four book exists because Java made functions second-class citizens<p>Why do people write silly things like this? GoF was <i>published</i> in 1995, the same year Java was first released, and includes neither Java code nor any mention of Java. Java had no influence on that book.
        • Jtsummers1 hour ago
          iLemming, your reply is [dead] and I don&#x27;t know why. Responding to parts of it:<p>&gt; Peter Norvig made this argument explicitly in 1998, showing 16 of 23 patterns are &quot;invisible or simpler&quot; in Lisp<p>The GoF book even mentions this so Norvig&#x27;s presentation is a useful read, but even the authors of the book knew it was true. It&#x27;s not like he added a new idea with that bit you quoted, the useful parts of the presentation were <i>which</i> patterns became invisible or simpler and why.<p>&gt; Let&#x27;s try not to nitpick on literal wording to avoid engaging with the substance, could we?<p>I responded to a common, but false, claim. Don&#x27;t make false claims and I won&#x27;t call you out for it.
          • iLemming1 hour ago
            You can replace Java there with pretty much any OOP language, where functions are not first-class citizens, and it will still be true. There are no &quot;false claims&quot; here. The main point is valid. We have orchestrated an entire industry around &quot;objects&quot;, while much simpler abstractions have already existed. You probably just have not experienced the &quot;true&quot; nature of Lisp, where you can interactively change any behavior of the running program, directly from your editor, without linking, linting, compiling, restarting or even saving the code you type. The process is an enormously joyful experience, it feels like playing a video game. You probably have little idea of what we&#x27;ve lost and what we&#x27;ve gained from the industry heavily tilting towards OOP.
            • Jtsummers57 minutes ago
              &gt; There are no &quot;false claims&quot; here.<p>You wrote:<p>&gt;&gt; The Gang of Four book exists because Java made functions second-class citizens<p>That is a false claim. You asserted a causal relationship between Java and the content of the GoF book that does not exist without time travel.<p>&gt; You probably just have not experienced the &quot;true&quot; nature of Lisp, where you can interactively change any behavior of the running program, directly from your editor, without linking, linting, compiling, restarting or even saving the code you type.<p>Sure buddy. You know <i>so</i> much about me...
              • iLemming34 minutes ago
                OMG. You got me. I&#x27;m so, so sorry you caught me spreading lies about your precious programming language (or your favorite book, I don&#x27;t know what you&#x27;re trying to protect more). Thank you from the bottom of my heart for the diligent work of protecting the truth and keeping this place free of disinformation. Please send me a DM with your mailing address and I&#x27;ll send you a medal, shipping cost included.<p>&gt; Sure buddy. You know so much about me...<p>I should have checked your comment history first before making assumptions. Please accept my apologies if I sounded patronizing. Shouldn&#x27;t be an excuse for my tone, in my defense I could say: &quot;I said &#x27;probably&#x27;&quot;. Still disagree with you overly correcting me since I firmly believe the overall notion of my original comment is correct. Thus I won&#x27;t remove my snarky, sarcastic paragraph above.
        • iLemming1 hour ago
          [dead]
    • the_af8 hours ago
      &gt; <i>These lisp guys really get excited over very abstract things. If you say this to an average person on the street they will probably try to run away.</i><p>Referential transparency is a funny name for a very powerful feature which helps you understand what the program does better, it&#x27;s not a deeply abstract thing. Don&#x27;t let the name scare you.<p>You could ask &quot;why the funny name&quot;? Well, specialized professionals use specialized jargon, even for &quot;normal stuff&quot;. It&#x27;s unreasonable to expect otherwise. Car mechanics also have weird names for car parts that are absolutely essential for the car and not that hard to understand if they explained them to you.
  • soomtong9 hours ago
    This document was really helpful when I first met Janet:<p><a href="https:&#x2F;&#x2F;janetdocs.org&#x2F;tutorials" rel="nofollow">https:&#x2F;&#x2F;janetdocs.org&#x2F;tutorials</a><p><a href="https:&#x2F;&#x2F;janet.guide&#x2F;" rel="nofollow">https:&#x2F;&#x2F;janet.guide&#x2F;</a> (the author&#x27;s one)
    • veqq5 hours ago
      I&#x27;m really happy you liked it! It&#x27;s still a work in progress.
  • p1necone1 hour ago
    First time I&#x27;ve seen &#x27;wat&#x27; used as a noun, I like it.<p>(for those unfamiliar with the reference: <a href="https:&#x2F;&#x2F;www.destroyallsoftware.com&#x2F;talks&#x2F;wat" rel="nofollow">https:&#x2F;&#x2F;www.destroyallsoftware.com&#x2F;talks&#x2F;wat</a>)
  • wodenokoto11 hours ago
    I&#x27;ve been drawn into the Janet posts that surface every once in a while here on HN, but found the otherwise highly praised &quot;Janet for Mortals&quot;, not being for mortals at all.
    • veqq5 hours ago
      I have some gentler introductory stuff like: <a href="https:&#x2F;&#x2F;janetdocs.org&#x2F;tutorials" rel="nofollow">https:&#x2F;&#x2F;janetdocs.org&#x2F;tutorials</a>
    • lelanthran10 hours ago
      &gt; I&#x27;ve been drawn into the Janet posts that surface every once in a while here on HN, but found the otherwise highly praised &quot;Janet for Mortals&quot;, not being for mortals at all.<p>I&#x27;m surprised: the language is very straightfoward, simple, very few rules to remember. It&#x27;s a Lisp but with a very small surface area.<p>I mean, compared to other languages, Janet really is easier to lean, so I&#x27;m surprised that the book for it is difficult (did not read the book, but familiar-ish with the language. I don&#x27;t have anything but praise for it, TBH).
    • petee10 hours ago
      Personally I get hung up on the macro syntax being near the beginning, but there is so much valuable stuff past that
    • shevy-java11 hours ago
      &gt; not being for mortals at all.<p>I had that with Haskell. Although, while Haskell is too hard for me, I actually like its syntax.<p>Janet seems to be Lisp 2.0, so the syntax is lispy.
  • 0x020311 hours ago
    Seems some of the listed advantages for Janet would also apply for tcl (small&#x2F;simple, easy to learn, embeddable, usable as a shell, great for domain specific languages). It would be interesting, to me at least, to see a fan of Janet compare the two.
    • embedding-shape10 hours ago
      I&#x27;ve only used Tcl briefly, mostly for automation which it&#x27;s great at. But it&#x27;s a Algol-like imperative language, doesn&#x27;t have any type of macros and makes everything based on strings (which makes sense for automation) instead of lists, with all the tradeoffs that comes with.<p>It seems easier to figure out what the similarities are, because I think they&#x27;re pretty few, they seem to differ more than they are similar.
      • nrclark2 hours ago
        Tcl is pretty good at functional-programming type stuff, and it can absolutely do anything that you could do with a macro. It isn&#x27;t Algol-like at all imo, maybe beyond some superficial syntax. It feels a lot more like if LISP and Bash had a baby out of wedlock.<p>(I&#x27;ve written a lot of Tcl over the years and it&#x27;ll always have a spot in my heart)
      • adrian_b8 hours ago
        Tcl being based on strings creates the same problems like in bash scripts, i.e. it is too easy to misuse the quotation rules, leading to subtle bugs.<p>Using for scripting LISP-like languages is much more foolproof, especially for more complex scripts.
        • packetlost7 hours ago
          Ok, but now I want to embed Janet in a TCL program
    • ux2664788 hours ago
      Janet is faster, but lacks anything like tk. It&#x27;s probably also quicker to learn, as you don&#x27;t get into complex evaluation structure until you start messing around with quasiquotes, while tcl requires you to understand mixing 3 different layers of evaluation right off the bat. tcl&#x27;s vm imo is easier to understand as well.<p>tcl if you want a UI, janet if you want an embedded scripting language.
  • didibus4 hours ago
    Wow I never realized Janet was released more than 10 years after Clojure.<p>Clojure: 2007<p>Janet: 2019
  • 1vuio0pswjnm78 hours ago
    The author does not mention that Janet comes with _built-in_ networking<p>Having tried many tiny interpreters over the years, that&#x27;s relatively rare IME
  • skeledrew11 hours ago
    This got me thinking of Hy. I wonder how syntactically close they are; there might be an exploitable Python -&gt; Hy -&gt; Janet path here.<p>[0] <a href="https:&#x2F;&#x2F;hylang.org&#x2F;" rel="nofollow">https:&#x2F;&#x2F;hylang.org&#x2F;</a>
    • cfiggers6 hours ago
      I use both. They&#x27;re similar for simple use, but above a certain level of complexity Hy has a lot of Python-isms that bleed through. It really doesn&#x27;t ever let you forget that underneath all the parentheses you&#x27;re really writing Python. Janet feels like its own stand-alone language in that respect, where Hy is more like a syntax swap.<p>I have the impression that Hy&#x27;s user base is larger, though (not that either one is huge).
    • rcarmo11 hours ago
      I used Hy for a long time, then tried Janet, and ultimately realized that I wanted more batteries included but didn&#x27;t want Python... So I forked <a href="https:&#x2F;&#x2F;github.com&#x2F;rcarmo&#x2F;go-joker" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;rcarmo&#x2F;go-joker</a> and am tinkering with it until it does all I want.
  • defrost11 hours ago
    Previously (April 2023) | 140 comments: <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=35539255">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=35539255</a>
  • AHTERIX500010 hours ago
    Does embedding Janet still lean on global state?
    • OskarS6 hours ago
      My first question too, and I checked out the linked book [1], and sure seems like it! There&#x27;s global functions like `janet_init()` and `janet_loop()` all over the place.<p>A language shouldn&#x27;t advertise itself as &quot;embeddable&quot; if it does this. It means you can&#x27;t have multiple interpreters, you can&#x27;t use it on multiple threads, etc. GNU Guile does this too, and it&#x27;s a baffling decision! For my field (audio plugins like VSTs), it means it&#x27;s absolutely a no-go, because hosts can load any number of instances of your plugins and potentially run them in parallel in the same address space, they <i>can&#x27;t</i> rely on global state like this. Each interpreter has to be separate.<p>Lua does this right, as does Python (as of 3.12, when they made the GIL local to each interpreter) and I think most of the JavaScript engines. And it&#x27;s not hard, instead of a global `janet_init()`, just have an opaque pointer bundle all the state, like `janet_init(interpreter)`. If you want a global interpreter, just stick it in a global variable.<p>[1]: <a href="https:&#x2F;&#x2F;janet.guide&#x2F;embedding-janet&#x2F;" rel="nofollow">https:&#x2F;&#x2F;janet.guide&#x2F;embedding-janet&#x2F;</a>
      • petee5 hours ago
        Janet global state is thread local;[1] janet_init() is called once per thread.<p>[1] official docs: <a href="https:&#x2F;&#x2F;janet-lang.org&#x2F;capi&#x2F;embedding.html" rel="nofollow">https:&#x2F;&#x2F;janet-lang.org&#x2F;capi&#x2F;embedding.html</a>
        • OskarS3 hours ago
          So you can&#x27;t execute a Janet script on a different thread than it was created on? Still not good: if you&#x27;re making audio plugins, you don&#x27;t control the threads which your program runs on. It&#x27;s just not good enough, IMHO.
          • petee1 hour ago
            Not sure exactly what you&#x27;re getting at, you mean transfer mid-execution to another thread? You can load and run a script on any thread you can load janet on, and you can coordinate across threads if need be. To clarify, janet_init just sets up the VM<p>I&#x27;d also go take a look at the actual docs and code, I&#x27;m not sure I know the exact answer, but assumptions won&#x27;t help<p>Edit: there was someone on the Zulip that mentioned working on audio plugins, and there are a couple other audio-related projects you could check out. Someone there might have a better answer -- <a href="https:&#x2F;&#x2F;janet.zulipchat.com&#x2F;" rel="nofollow">https:&#x2F;&#x2F;janet.zulipchat.com&#x2F;</a>
  • lindig11 hours ago
    &gt; Instead of regular expressions, Janet’s text wrangling is based around parsing expression grammars. Parsing expression grammars are simpler, more powerful, and more predictable than regular expressions.<p>I would dispute that this is the case. In PEGs, alternatives are not commutative, unlike in regular expressions. This can lead to quite frustrating debugging. While a valid choice, the advantage over REs is overstated.
    • jsmith456 hours ago
      I&#x27;d argue they are not commutive in regexes either, at least as implemented in practice. Implemented regexes favor the leftmost alternative even when both sides of the alternative match. This matters in cases like: capturing groups, and backtracking implementations. There absolutely are cases where one ordering of alternatives could yield catastrophic backtracking for some input, while the other will avoid it completely.<p>I personally don&#x27;t like this at all. This means that regex engines that try to generate optimized matching code for an expression can end up generating suboptimal code if you don&#x27;t want alternative order to matter, since the engine needs to keep that invariant, except in the case when it can prove that the alternatives won&#x27;t overlap, and a later one can be checked in constant time. If both are true, it is legal to reorder them to do the constant time check before the big complicated wildcard-filled alternative.<p>But personally, I have never written a regex where I actively cared about the alternative evaluation order. I&#x27;ve used some other people made where order is important but never written one myself.<p>I&#x27;d love to be able to tell the engine &quot;feel free to swap the evaluation order of my alternatives while optimizing&quot;, but few if any such engines offer that as a feature.<p>Now I get that PEGs have commutivity problems are that are different from regexes&#x27;, which make the issue worse, but that doesn&#x27;t mean regexes do things right either.
    • nrclark2 hours ago
      Something I&#x27;d observe here: without expressing an opinion about PEGs vs regexes, I&#x27;d note that regexes are much more widely used. They&#x27;re also completely sufficient for an awful lot of text processing tasks. PCRE regexes would be a great inclusion to the stdlib, and would probably be popular.
      • xigoi2 hours ago
        &gt; PCRE regexes would be a great inclusion to the stdlib<p>Why? Anything that can be done with a regex can also be done with a PEG, and the PEG will be much more readable.
    • xigoi10 hours ago
      The non-commutavity is a feature, not a bug. It allows you to have clearly defined parsing for grammars that would traditionally be considered ambiguous.
      • layer88 hours ago
        But that’s not how humans writing code <i>generally</i> think about ambiguous expressions. You can see that by how few precedence rules programmers tend to internalize, and often prefer extra parentheses to make sure that the parser interprets it the way they mean.
        • Timwi32 minutes ago
          &gt; But that’s not how humans writing code generally think about ambiguous expressions. You can see that by how few precedence rules programmers tend to internalize<p>I&#x27;d argue that it <i>is</i> how humans think about ambiguous syntax, <i>except</i> in the special case of operator precedence, which is the most complex example. A more salient example to me would be, say, the case of an ‘else’ block after a double-‘if’:<p><pre><code> if (c) if (d) X; else Y; </code></pre> It&#x27;s technically ambiguous, but you only need to run into it once, see how your IDE auto-formatter indents it, and then you&#x27;ve internalized the precedence rule immediately.
        • xigoi6 hours ago
          I am not talking about operator precedence, that’s a separate thing. Consider the parsing of math expressions, where juxtaposition of terms denotes multiplication unless it can be interpreted as something else. So f(x+2) is function application, whereas 3(x+2) is multiplication. With a PEG, you just write a standard expression grammar with an additional choice at the end for the implicit multiplication. With a conventional parser, this is much more difficult – you have to explicitly list all the different ways that terms could be next to each other without meaning something else.
        • tejtm3 hours ago
          We absolutely order more likely &#x2F; preferred options before other options. Codifying that as a short circuit optimization is a feature.
          • layer81 hour ago
            We rarely have preferences that are independent of the concrete use case. Your argument boils down to saying that existing precedence hierarchies are badly designed (or else they would always match everyone’s intuitions), but that’s not the case. (Operator precedence is only one illustrative example here.)
    • petee10 hours ago
      &quot;small peg tracer&quot;[1] is really helpful for breaking down a PEGs operation<p>[1] <a href="https:&#x2F;&#x2F;github.com&#x2F;sogaiu&#x2F;small-peg-tracer" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;sogaiu&#x2F;small-peg-tracer</a>
    • zelphirkalt11 hours ago
      PEGs are just soooo much easier to read than regexes for anything more complex than a few words or single line matching. REs are a hammer that tempts people to see everything as a nail, but once one progresses beyond that phase one usually wants as few REs as possible.
      • layer88 hours ago
        That’s mostly an artifact of concise regex syntax I believe. When you write regular expressions in an ABNF-like form, they become much more intelligible.
    • bmn__11 hours ago
      Came here for this comment. Janet would score positively in my mind if the evolutionary dead-end PEG were replaced with a grammar parser that is known to work under all circumstances.
      • xigoi2 hours ago
        Under what circumstances does PEG not work?
  • zabzonk9 hours ago
    Thought this might be about JANET, the rationale for which I have never really understood. The wikipedia article on it is not very explanatory: <a href="https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;JANET" rel="nofollow">https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;JANET</a>
    • edwinbalani1 hour ago
      From memory, it was for Joint Academic Network. I&#x27;m surprised the Wikipedia article doesn&#x27;t mention it at all, but it seems hard to find an authoritative source.
  • 6LLvveMx2koXfwn11 hours ago
    Maybe needs a (2023) in the title?
  • doug_durham4 hours ago
    DSLs. Creating a language that only you know that will double the learning curve for the folks coming after you. It&#x27;s fine for personal projects, but almost always an anti-pattern.
  • hlude7 hours ago
    The shell DSL is what made me want to try Janet
    • veqq5 hours ago
      We recently migrated to a standard library version: <a href="https:&#x2F;&#x2F;janet-lang.org&#x2F;1.41.2&#x2F;spork&#x2F;api&#x2F;sh-dsl.html" rel="nofollow">https:&#x2F;&#x2F;janet-lang.org&#x2F;1.41.2&#x2F;spork&#x2F;api&#x2F;sh-dsl.html</a>
  • gspr11 hours ago
    The embeddability sounds very appealing. Does anyone have experience with using this somewhere one might traditionally reach for Lua?
    • xigoi11 hours ago
      I have built a markup language with embedded scripting in Janet. I originally tried to use Lua, but found the verbosity extremely frustrating.
  • boltzmann648 hours ago
    if those are the reason why you love janet, then you will love tcl because you will be able to do all the same things without drowning in parenthesis and weird syntax.
    • sph4 hours ago
      There are three languages worth learning that expand your mind: Lisp, Forth and Tcl. Despite all exhibiting homoiconicity, they couldn&#x27;t be more different from one another.<p>(I&#x27;d include Rebol but it&#x27;s as mind-blowing as it&#x27;s dead technology from a lost timeline)
    • WalterBright6 hours ago
      Dammit, Janet, I love you!
  • IshKebab12 hours ago
    Pretty compelling, especially &quot;Janet does not adhere to the ancient customs. CAR is called first. PROGN is called do. LAMBDA is fn, and SETQ is def.&quot; - a sign of good sense for sure!<p>How fast is it?<p>Also my main objection to Lisps is still the horrible bracket syntax. Yes it&#x27;s unambiguous and easy to parse, but it&#x27;s HORRIBLE to read and edit. I wish this project had been a success (or something similar to it): <a href="https:&#x2F;&#x2F;readable.sourceforge.io&#x2F;" rel="nofollow">https:&#x2F;&#x2F;readable.sourceforge.io&#x2F;</a><p>Also I don&#x27;t think static typing is really optional for me at this point.
    • adrian_b10 hours ago
      Actually not all those are ancient customs, and not all that Janet uses is newer.<p>In the first description of the language LISP, from March 1959 (AIM-008), John McCarthy had used the names &quot;first&quot; and &quot;rest&quot;, instead of what later will be called &quot;CAR&quot; and &quot;CDR&quot;.<p>The names of &quot;CAR&quot; and &quot;CDR&quot; appear to have come from the students who worked at the practical implementation of the LISP interpreter on an IBM 704, and unfortunately we have remained stuck with them, like also with other features that were intended only for a temporary use, until being replaced in the &quot;final version&quot; (which was abandoned).
    • setopt11 hours ago
      &gt; Pretty compelling, especially &quot;Janet does not adhere to the ancient customs. CAR is called first. PROGN is called do. LAMBDA is fn, and SETQ is def.&quot; - a sign of good sense for sure!<p>Just FYI, many of these are also done in Scheme and its derivative Racket. They kept lambda (but even Python did that), but progn -&gt; begin, setq -&gt; set!, car -&gt; first, and so on.<p>&gt; Also my main objection to Lisps is still the horrible bracket syntax. Yes it&#x27;s unambiguous and easy to parse, but it&#x27;s HORRIBLE to read and edit.<p>I have pretty mixed feelings at this point. I don’t mind it for normal programming, but when I do numerical programming (physics models, etc.) you often get extremely long and verbose expressions that are IMO difficult to parse compared to the math-like infix operator notation used in other languages.
      • aeonik11 hours ago
        I&#x27;m starting to prefer the s expression syntax when dealing with tree structures like json.<p>I wonder if we were raised on tree based algebra if math would be easier to do, or harder.<p>Like, solve for x.<p><pre><code> (= (+ (* 2 x) 3) 11) (= (* 2 x) (- 11 3)) (= (* 2 x) 8) (= x (&#x2F; 8 2)) (= x 4) </code></pre> Though this isn&#x27;t too bad.<p><pre><code> (= (+ (pow x 2) (pow y 2)) (pow r 2))</code></pre>
        • setopt8 hours ago
          I think also a lot of my objections could be worked around if one simply had a &quot;math&quot; macro that evaluates infix math notation as a DSL, similarly to how the CL &quot;loop&quot; macro does a DSL for iteration.<p>Perhaps this exists already somewhere?
          • veqq4 hours ago
            &gt; exists already<p>The helloworld of macros lets you do `(infix 1 + 2)`:<p><pre><code> (defmacro infix [a op b] ~(,op ,a ,b)) </code></pre> A useful one with precedence letting you to `(infix 2 + 4 * 5)`:<p><pre><code> (defmacro infix [&amp; toks] (def prec {&#x27;+ 1 &#x27;- 1 &#x27;* 2 &#x27;&#x2F; 2 &#x27;% 2}) (var pos 0) (defn climb [min-p] (var left (toks pos)) (++ pos) (while (&gt;= (get prec (get toks pos) -1) min-p) # nil&#x2F;operand -&gt; -1, stops the loop (def op (toks pos)) (++ pos) (set left ~(,op ,left ,(climb (inc (prec op)))))) # inc =&gt; left-associative left) (climb 0)) </code></pre> But ultimately, APL notation is best: <a href="https:&#x2F;&#x2F;git.sr.ht&#x2F;~subsetpark&#x2F;jnj" rel="nofollow">https:&#x2F;&#x2F;git.sr.ht&#x2F;~subsetpark&#x2F;jnj</a>
          • xigoi2 hours ago
            &gt; Perhaps this exists already somewhere?<p><a href="https:&#x2F;&#x2F;janet-lang.org&#x2F;spork&#x2F;api&#x2F;infix.html" rel="nofollow">https:&#x2F;&#x2F;janet-lang.org&#x2F;spork&#x2F;api&#x2F;infix.html</a>
        • setopt8 hours ago
          I definitely prefer s-exps over both xml and json myself too!<p>Interesting question. Much of the difficulty does stem from mentally translating back and forth between conventional notation and s-exps too, since you can’t really avoid the standard notation when reading and writing math and physics papers. And current-day math and physics notation has been optimized to some extent for the infix notation; perhaps one would have invented more expressive higher-order functions or macros to denote s-exp math if that was what everyone used for centuries.
        • krupan7 hours ago
          If you ever used an RPN calculator then this is very familiar
    • tmtvl7 hours ago
      All programming languages have horrible syntax (except maybe Forth). Some examples:<p>Statements are terminated by either a dedicated graphical character, in which case it&#x27;s easy to forget the character and have a problem, or by a newline (or maybe a different white space character, but I haven&#x27;t encountered that yet) in which case decent formatting of code may require a dedicated graphical character to indicate that the newline DOESN&#x27;T terminate the statement, in which case we have the same problem. Having newline-terminated statements without continuation character would be consistent, but would hamper readability because identifiers would need to be strictly limited in length to keep certain lines from exceeding available screen space (or alternatively readability would suffer from lines only being partially readable).<p>And that&#x27;s before getting into the weeds of how mathematical notation is tricky (most people have learned infix notation at maths class in school, so they mightn&#x27;t appreciate how horrible it is), how different types of brackets (round, square, curly) can have inconsistent semantics, the downsides to the various ways of indicating lexical blocks (brackets, white space, keywords,...), et cetera.<p>The ideal programming language would probably be one which allows switching between different syntaxes based on what works best for the user (for example, someone could write code in S-expressions, another person could have that code automatically translated into SRFI-119 Wisp expressions and work with it like that, a third person could then have it rendered into something more Lua-like,...). Which is something I think the Racket people are working on, but I may be mistaken.
    • graemep11 hours ago
      Syntax is not that important to me. I prefer Python style indentation, but its really not that important - its just something to get used to for me.<p>Is static typing that important for a scripting language? From the intro to the book:<p>&gt; And to be clear, I’m not going to try to convince you to bet your next startup on Janet, or even to use it in any sort of production setting. But I think it’s an excellent language for exploratory programming, scripting, and fun side projects.
    • xigoi10 hours ago
      &gt; Also my main objection to Lisps is still the horrible bracket syntax. Yes it&#x27;s unambiguous and easy to parse, but it&#x27;s HORRIBLE to read and edit.<p>I use Parinfer, which allows me to edit Janet as if it was an indentation-based language.
      • IshKebab9 hours ago
        Yeah I mean I guess if you have to use that syntax, it&#x27;s nice to have a better editor for it. But IMO the existence of that tool clearly demonstrates that the syntax is pretty bad.
        • imtringued9 hours ago
          Most editors manage your indentation, parentheses and braces for you. Not sure how that is a unique marker for lisp style languages.
        • adrian_b8 hours ago
          All C-derived languages (e.g. Java and Rust) have a bad syntax, with tons of superfluous parentheses and many other superfluous tokens, like semicolons or commas.<p>This normally matters very little, because a good editor will always insert a complete template whenever you type something like &quot;if&quot;, &quot;for&quot;, &quot;while&quot; etc.<p>Most programmers are blind to the syntax defects with which they are accustomed and they notice only the syntax defects with which they are unfamiliar.<p>I would prefer a language with a good syntax, but unfortunately which programming languages have survived in widespread use has a poor correlation with the technical qualities of a language and especially a really negligible correlation with how good its syntax was.
    • packetlost7 hours ago
      It&#x27;s a scripting language, so it&#x27;s not going to compete with anything compiled or JITed, but it has a pretty efficient threaded bytecode interpreter (that is almost more interesting than the language itself!). It&#x27;s certainly good enough for most situations where you would reach for a scripting language.
      • IshKebab4 hours ago
        AoT&#x2F;JIT compilation is a property of the implementation, not the language.<p>It would be good to know order of magnitude anyway. Like, are we talking Ruby&#x2F;Python level, etc.
        • veqq4 hours ago
          In my tests, it&#x27;s 5-10x Python for long running things (about 30% slower than Fennel on LuaJit) but for small things, because you can easily shift work to compile time, it beats normal Go: <a href="https:&#x2F;&#x2F;codeberg.org&#x2F;veqq&#x2F;verse-reader#performance" rel="nofollow">https:&#x2F;&#x2F;codeberg.org&#x2F;veqq&#x2F;verse-reader#performance</a>
    • ux2664788 hours ago
      &gt; How fast is it?<p>Roughly as fast as puc-rio Lua. It won&#x27;t blow your socks off, but it&#x27;s more than respectable.
    • zelphirkalt10 hours ago
      Out of those renames, I agree with car-&gt;first and progn-&gt;do. setq is ugly, but I think using def is maybe questionable. lambda I would have just kept the same.
    • e12e11 hours ago
      Are you aware of:<p><a href="https:&#x2F;&#x2F;docs.racket-lang.org&#x2F;sweet&#x2F;index.html" rel="nofollow">https:&#x2F;&#x2F;docs.racket-lang.org&#x2F;sweet&#x2F;index.html</a>
  • netbioserror9 hours ago
    Janet is ALMOST an incredible tool...but what I want is a very clear bifurcation between the standard library&#x27;s stateful mutating procedures, and stateless value-returning functions. I ran into that wall hard trying to make something non-trivial.<p>It also turns out that the mix is due to the standard library leaning on raw C loop iterations underneath whenever it can. Which is great! But it confuses the library&#x27;s interface paradigms.
  • anthk10 hours ago
    Luxferre.top has some Janet based softwrae.
  • makach11 hours ago
    Excellent. Although I suspect the author of the programming language invented this Janet for all the perfect puns. Yes, Janet. No. Janet.
  • bjourne7 hours ago
    Damn it, Janet. No proper namespaces. Hard pass.
    • xigoi1 hour ago
      What do you mean? When you import a module in Janet, it adds a namespace prefix to all symbols. What more do you want?
  • veqq5 hours ago
    &gt; I never thought it could happen to me.<p>But I am truly biased. I have basically forgotten how to code everything else (besides APL family languages) in the past _checks notes_ 10 months since I started Janet. I even run a community [docs site](<a href="https:&#x2F;&#x2F;janetdocs.org&#x2F;" rel="nofollow">https:&#x2F;&#x2F;janetdocs.org&#x2F;</a>) and am writing [my own tutorial](<a href="https:&#x2F;&#x2F;janetdocs.org&#x2F;tutorials&#x2F;learn-to-program" rel="nofollow">https:&#x2F;&#x2F;janetdocs.org&#x2F;tutorials&#x2F;learn-to-program</a>) (albeit slowly). I even use it in production for all new software (within 3 weeks of starting, I had rewritten all personal scripts etc.)<p>&gt; Janet is simple<p>You can do literally everything with just hashmaps. The whole language is basically a hashmap, implementation wise. `(keys (curenv))` prints out all locally defined symbols. `(keys (getproto (curenv)))` prints the parent hashmap of the current environment i.e. all the core symbols. I don&#x27;t, but you can basically do CLOS via hashmaps (and there is a [fuller implementation](<a href="https:&#x2F;&#x2F;git.sr.ht&#x2F;~subsetpark&#x2F;fugue" rel="nofollow">https:&#x2F;&#x2F;git.sr.ht&#x2F;~subsetpark&#x2F;fugue</a>) too.)<p>&gt; Janet is distributable<p>I have like 20 websites and another dozen or so services running on Janet (with the [Joy webframework](<a href="https:&#x2F;&#x2F;github.com&#x2F;joy-framework&#x2F;joy" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;joy-framework&#x2F;joy</a>) which I wrote a [tutorial](<a href="https:&#x2F;&#x2F;janetdocs.org&#x2F;tutorials&#x2F;Joy-Web-Framework" rel="nofollow">https:&#x2F;&#x2F;janetdocs.org&#x2F;tutorials&#x2F;Joy-Web-Framework</a>) for), on a single free-tier VPS with 512mb of RAM.<p>&gt; Janet has ... immutable collections<p>...not really. In reality, the whole standard library constantly returns mutable versions from everything. There&#x27;s no reason to really try to be immutable at this point. Although there are cool [combinator libraries](<a href="https:&#x2F;&#x2F;git.sr.ht&#x2F;~subsetpark&#x2F;apcl-janet" rel="nofollow">https:&#x2F;&#x2F;git.sr.ht&#x2F;~subsetpark&#x2F;apcl-janet</a>) and I&#x27;ve even made combinatorish versions of basic functions:<p><pre><code> (defn better-cond [&amp; pairs] (fn :bc [&amp; arg] # names for stack traces (label result (defn argy [f] (if (&gt; (length arg) 0) (apply f arg) (f arg))) # naming is hard (each [pred body] (partition 2 pairs) (when (argy pred) (return result (if (function? body) (argy body) # calls body on args body))))))) </code></pre> Combinatory inspired cond, which allows for pairs. The test does not need an argument and the body may be a simple value or a function:<p><pre><code> (map (better-cond string? &quot;not a number&quot; odd? &quot;odd&quot; even? &quot;even&quot;) [1 2 3 &quot;cat&quot;]) # the args! (map (better-cond 1 (fn [arr] (array (min ;arr) (max ;arr)))) # (recombine array (unapply min) (unapply max))) (partition 2 (range 10))) # these are the args! ((better-cond &lt; &quot;first is smaller&quot; &gt; &quot;second is smaller&quot;) 5 3) # these are the args passed into the func! I am excited! </code></pre> &gt; Janet lets you pass values from compile-time to run-time<p>That&#x27;s what got me hooked, in a few ways. In Racket or Go, I had to do a lot of work to process data at compile time so the runtime could literally just be a lookup table. In Janet? That&#x27;s the default behavior of any `def` outside of main. The following turns a .tsv of the bible into a hashmap in the binary, when compiling:<p><pre><code> (def verses (reduce (fn [acc line] (let [parts (string&#x2F;split &quot;\t&quot; line)] (if (= (length parts) 5) (let [[_ abbrev ch vs text] parts] (put-in acc [abbrev ch vs] text)) acc))) @{} (string&#x2F;split &quot;\n&quot; (slurp &quot;kjv.tsv&quot;)))) (def abbrev-array (keys verses)) # also makes an array of the abbreviation column </code></pre> So the rest of the program is literally just accessing the hashmap ([twice as fast](<a href="https:&#x2F;&#x2F;codeberg.org&#x2F;veqq&#x2F;verse-reader#performance" rel="nofollow">https:&#x2F;&#x2F;codeberg.org&#x2F;veqq&#x2F;verse-reader#performance</a>) as the Golang version using `embed`):<p><pre><code> (defn main [_ &amp; args] (if (or (empty? args) (= &quot;-h&quot; ;args) (= &quot;help&quot; ;args)) (do (print &quot;Usage: kjv &lt;book&gt; [chapter:verse]&quot;) (os&#x2F;exit 1))) # show help (let [Capitalized (string (string&#x2F;ascii-upper (string&#x2F;slice (first args) 0 1)) (string&#x2F;slice (first args) 1)) book (find |(string&#x2F;has-prefix? $ Capitalized) abbrev-array)] (pp (match args [_ chap verse] (get-in verses [book chap verse]) [_ unsure] (match (string&#x2F;split &quot;:&quot; unsure) [chap verse] (get-in verses [book chap verse]) [chap] (get-in verses [book chap])) [_] (verses book))))) </code></pre> The equivalent go program was 5x longer and required an extra program to convert data into a 40k line .go file with a giant literal hashmap, to be faster than the naive Janet.<p>...but actually Ian Henry means Janet e.g. keeps closures synced across images&#x2F;sessions:<p><pre><code> (defn timer [t] (var t t) # this is slightly annoying, must shadow as params are immutable [(fn [] (set t (+ t 1))) (fn [] (set t (+ t 2)))]) (def tx (timer 0)) # call like this: ((tx 0)) ((tx 1)) # make an image and save it to file (def my-module @{:public true}) (spit &quot;test.jimage&quot; (make-image (curenv))) </code></pre> Exit and start a new REPL session:<p><pre><code> (defn restore-image [image] (loop [[k v] :pairs image] (put (curenv) k v))) (restore-image (load-image (slurp &quot;test.jimage&quot;))) ((tx 0)) </code></pre> It saved the closure and all relevant image in the `(curenv)` hashmap.<p>Condensed from my longer response: <a href="https:&#x2F;&#x2F;lobste.rs&#x2F;s&#x2F;y0euno&#x2F;why_janet_2023#c_lspe6n" rel="nofollow">https:&#x2F;&#x2F;lobste.rs&#x2F;s&#x2F;y0euno&#x2F;why_janet_2023#c_lspe6n</a>
  • xuzhenpeng9 hours ago
    [flagged]
  • rohitsriram10 hours ago
    [flagged]
  • nicechianti7 hours ago
    [dead]
  • shevy-java11 hours ago
    <p><pre><code> (defn foo [first &amp; rest] ...) </code></pre> So basically Lisp 2.0.<p>Although, this here is a good idea:<p>&quot;pass values from compile-time to run-time&quot;<p>Would be nice if some kind of &quot;scripting&quot; language be as fast as a compiled language, but without ruining the syntax. Just about 99% of the languages that are shown, have a horrible syntax. Syntax is not everything, but most language designers don&#x27;t understand that syntax also matters. So tons of horrible languages emerge. Nobody will use those languages, so 99% of them will die off quickly.
    • xigoi10 hours ago
      What would be a better syntax according to you? I have found Janet’s syntax very pleasant to work with as opposed to JavaScript, Lua or even Python.
    • Imustaskforhelp10 hours ago
      can&#x27;t there theoretically be a language which transpiles to Janet to get all the benefits without additional paranthesis too?<p>Not sure if such transpilation would have a perf hit though, I hope somebody responds who knows about it more.<p>I don&#x27;t deny that syntax matters itself too but there are some ideas of janet like sandboxing and other features which seem to me to be worth implementing in other languages too.<p>Personally, I would be really interested in a language like lua&#x2F;wren which can transpile to Janet too.
      • rmunn7 hours ago
        &quot;... all the benefits without additional parenthesis too?&quot;<p>I guess you don&#x27;t like Lisp&#x27;s syntax. I didn&#x27;t either until I realized the key insight: when you&#x27;re writing Lisp, you&#x27;re basically writing an AST. Which is why it&#x27;s so easy to manipulate your code. Want a new feature the language doesn&#x27;t have, such as the pattern-matching they added to C# a few versions back? <i>You can add it yourself</i>; you don&#x27;t need to wait for a language committee to implement it years after you needed it. That&#x27;s all that macros are: functions that take AST and return AST, which is then executed.<p>And once I realized that Lisp&#x27;s syntax was basically an AST, I no longer saw the parentheses. Now I just see blonde, brunette, redhead... Oops. Sorry. Wrong reference.
      • iLemming1 hour ago
        &gt; like lua&#x2F;wren which can transpile to Janet too.<p>Really? I&#x27;ve used dozens of languages and honestly, I just can&#x27;t wrap my head around how ugly Lua code can get. At first, I tried treating it as &quot;javascript with no bad parts&quot;, turns out, modern JS is far, far better than 1996 JS and nicer than Lua. The most annoying part about Lua is that I never know how to format it for better readability - should I add line breaks, or not, etc. lua-fmt often just makes it worse.<p>When I found Fennel I immediately moved to it, even though it was &quot;experimental&quot;. Since then, I just don&#x27;t want to deal with Lua, aside from some small one-liners.
      • petee10 hours ago
        I guess you could transpile direct to Janet bytecode, and performance would be in theory the same as native Janet?
  • flintenmuschi8 hours ago
    Why, Henry?
  • wolfi111 hours ago
    why is it called Janet? perhaps to prevent it to be identified with the acronym for Lots of Irritating Single Parenthesis?
    • petee10 hours ago
      It was named after the sentient computer system in the TV show &quot;The Good Place&quot;<p>A humourous clip: <a href="https:&#x2F;&#x2F;youtu.be&#x2F;etJ6RmMPGko?si=W98LdG1jDdUCXsHV" rel="nofollow">https:&#x2F;&#x2F;youtu.be&#x2F;etJ6RmMPGko?si=W98LdG1jDdUCXsHV</a>
      • embedding-shape10 hours ago
        Also mentioned in the GitHub repository:<p>&gt; Why is it called &quot;Janet&quot;? Janet is named after the almost omniscient and friendly artificial being in The Good Place<p><a href="https:&#x2F;&#x2F;github.com&#x2F;janet-lang&#x2F;janet#why-is-it-called-janet" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;janet-lang&#x2F;janet#why-is-it-called-janet</a>
    • xigoi10 hours ago
      If it was called [Something] Lisp, Lisp enthusiasts would complain that it’s not a lisp because it does not use linked lists as the primary data structure.
    • Imustaskforhelp10 hours ago
      I know that Lisp has lots of paranthesis and I don&#x27;t have enough experience with Lisp at all.<p>But from the looks of it, Janet has some great ideas like the one that @ramblurr shared here about sandboxing (&quot;Disable feature sets to prevent the interpreter from using certain system resources. Once a feature is disabled, there is no way to re-enable it.&quot;)<p>Lisp from my understanding is incredibly polarizing and many people love it and many people hate it and that&#x27;s fine, but at a certain point wouldn&#x27;t it feel repetitive for statement like this and I am unsure of how healthy discussion about programming concepts can be done this way.<p>There are so many interesting things from lisp-y languages like Janet and Julia is technically lisp-y too and Julia&#x27;s compilation to GPU is awesome and Nim too which can compile to C&#x2F;C++&#x2F;JS!<p>It&#x27;s just so many interesting concepts overall in programming that paranthesis don&#x27;t seem a concern to me as the underlying concept can be translated to something else, like sandboxing feature, transpilation to GPU or multiple targets!<p>And there are many unique concepts in non-lispy languages like golang (cross-compat, portability with static binaries), elixir (concurrency!) too.<p>It&#x27;s just good to see the amount of innovation within programming from all spheres of influence :-D
      • iLemming2 hours ago
        &gt; Lisp from my understanding is incredibly polarizing<p>No it&#x27;s not! It&#x27;s as &quot;polarizing&quot; as &quot;group theory&quot; or &quot;set theory&quot;. Lisp is fucking math - it maps closely to formal mathematical&#x2F;logical notation. You just can&#x27;t &quot;hate&quot; math - you can be confused by it, be unfamiliar with it, intimidated by it. But hatred directed at something that is simply precise and consistent says more about the person than the thing.<p>This is basically a reoccurring theme on every programming forum, whenever a Lispy PL gets mentioned. There are tons of confused programmers who look at Lisp examples and &quot;hate&quot; it. Without a single practical experience of using Lisp. They don&#x27;t know anything about structural editing, they never experienced REPL-driven development. And I&#x27;m not talking about shit like &quot;Python REPL&quot;, which is a bleak attempt, a shallow shell compared to the &quot;true Lisp REPL&quot;.<p>It takes a bit of time and curiosity to realize how enormously powerful, beautiful and practical the idea of Lisp is. And it&#x27;s really sad that smart people refuse it outright, without even attempting to understand it. Sure, it may take some time to discard the old habits that took years to build and accept this unfamiliar thing. Yet there&#x27;s a point, after which comes the realization that Lisp can literally replace every single programming language with better ergonomics. I&#x27;m so mad at myself for wasting huge chunk of my life, chasing things of lesser importance, instead of just figuring out Lisp sooner.<p>I guess, to a degree you&#x27;re right - you either hate Lisp or love Lisp, there&#x27;s no in-between. But &quot;hate&quot; means you simply don&#x27;t know it. Once you do - there&#x27;s no way not to fall in love.
      • adrian_b10 hours ago
        While I do not like the excess of parentheses of LISP and similar languages, their syntax is very consistent and predictable. Moreover, while LISP has an excess of parentheses, it omits a greater number of commas that are required in many other programming languages.<p>I am much more annoyed by the random syntax inconsistencies of most popular programming languages, which are either caused by original language design mistakes, or, more frequently, by the late addition of some features that were not planned in the original language, so they had to be squeezed in with the help of various ugly workarounds.<p>While during the last years I have not used much LISP like languages, there have been times when I used them a lot, for several years, in scripting applications, e.g. the LISP variant of old AutoCAD, the Scheme-like scripting language of the Cadence EDA applications, or the scsh Scheme dialect that is usable for replacing UNIX shell scripts.<p>In all cases, these languages allowed a greater productivity associated with rarer bugs than the more popular scripting languages, like Python, Perl, TCL, bash.<p>While aesthetically I might prefer the look of a Python program, for solving a practical production problem I would prefer to write scripts in one of the LISP derivatives. Obviously, the productivity in various programming languages depends a lot on individual preferences and previous experiences.<p>It should be noted by all those who believe that the LISP-derived languages have too many parentheses, that the C programming language and all languages with syntax derived from it, like Java or Rust, have a great excess of parentheses in comparison with the older languages that had better designed syntaxes, e.g. ALGOL 68 or IBM PL&#x2F;I.<p>For example, compare<p><pre><code> for (i = 1; i &lt;= 100; i += 5) { ... } </code></pre> with<p><pre><code> for i from 1 to 100 by 5 do ... od </code></pre> or<p><pre><code> if ( ... ) { ... } else { ... } </code></pre> with<p><pre><code> if ... then ... else ... fi </code></pre> The first example has 12 syntactic tokens instead of the minimum required, which is 6.<p>The second example has 8 syntactic tokens instead of the minimum required, which is 4.<p>If I cannot have a decent programming language with a minimum number of parentheses, I would rather have a programming language where all the places that need parentheses are predictable, like in LISP, instead of having a language like C and its derivatives, which require parentheses in random places, for no good reason at all.
        • NetMageSCW7 hours ago
          Now do<p><pre><code> for (i = 1; i &lt;= 128; i *= 2) { … } </code></pre> with by.<p>Now do<p><pre><code> if (x &lt;= 0) throw ParameterException; </code></pre> with fewer “syntactic tokens”.