Threads for kbd

    1. 19

      Another one in the long list of JavaScript tools that ditched JavaScript as their implementation language for performance reasons. Hopefully this is more easily usable by the time I have to work on a NodeJS project again, because the performance improvement numbers look incredibly promising.

      1. 6

        This begs the question, why write Javascript on the server if Go is there.

        1. 8

          Watching this industry choose js in a lot of places they don’t have to (i.e. anywhere but the browser) has been strange to see.

          1.  

            Single language stacks are awesome to work in. That’s why I write my frontends in Rust, but I understand TS devs going the other way.

            1.  

              It’s such a bad language and ecosystem. Typescript barely improves anything there.

            2. 6

              Ok, question asked. Why write JS on the server when I could pick Java/PHP/Elixir/Go/Rust/Python/Ruby/C#/Zig/OCAML/Crystal/Nim/Perl/Kotlin/Scala/Lua/Haskell/Clojure?

              I think some people are aiming for a single language as a stack. Because JS seems to not be going away anytime soon and there are so many backend languages, people were/are trying to aim for JS on the server. There are many backend choices but only one frontend choice. Therefore, to get one language, and end-to-end types, JS on the server. Yes, I understand JS avoidance and all the arguments against. Yes, I rolled my eyes when the server was discovered again.

              If I question why I have two languages in my app then people move the goal posts and reduce app features. “I can just concat html text to the client using app.pl in /cgi-bin”. Sure, you always have had that option, that’s not what I mean. I mean for a certain size/complexity of application. I mean, just as one benefit or pro in the trade-off, if I have Go types they don’t go to my client. Or I have to / want to have some contract layer to sync the two. So I end up with two languages and some contract between them. In theory, you don’t have that with trpc/typedjson/tanstack/etc etc. Because your types are full-stack.

              So when people are talking about Go replacing Typescript this is still Typescript dev. It’s a tool written in Go to write/check/build Typescript. If you wanted to avoid NodeJS, you would have to look at things like Deno or Bun.

              1.  

                There are many backend choices but only one frontend choice.

                With so many languages taking on WASM targets, I think that’s becoming less true. And even before that, there are quite a number of compilers targeting JS. Of course there are drawbacks, and these approaches aren’t always practical for every web front-end project, but I do think “only one frontend choice” is overstating the case.

                1.  

                  I can see wasm for tight loops, canvas. I don’t see it for general stuff that also requires CSS but I guess we’ll see. There should be lots of sites made and they should look good and work well for users if it’s easy to do and aligns with their backend job role and backend interests.

              2. 5

                I think the reality is that most people are asking that same question and coming to that same conclusion. The theory of “frontend devs can own the API layer” hasn’t really played out as well as people had hoped and I know plenty of JS developers who are just as happy to write Go if it comes to it anyways.

                1.  

                  Why write Go if C is there?

                  Why write C if hand-optimized assembly is there?

              3. 4

                Congrats to the Fish team on the rewrite! I am officially interested in Fish at the moment, so, Fish advocates, please sell me on it. I have a well-configured Zsh with the few plugins that matter and I think it’s fine. What can I gain from Fish?

                1. 2

                  Speaking as a zsh switcher: you no longer need configuration to speak of; you get everything you want out of the box. I have some aliases defined but that’s about it. Plus nice things I wouldn’t have bothered to set up in zsh, like syntax highlighting and alt-arrow to switch directories. Plus some stuff that I think is unique to fish (?), like parsing man pages for completions instead of needing someone to write a script for you.

                  1. 2

                    Is there any equivalent to fzf.zsh and, more importantly, fzf-tab?

                    Just like GP, I’m now actively pondering jumping ship, just out of the “sane behavior by default” sentiment, but this kind of deep integration between completion and fuzzy matching is quite literally the bread and butter of my shell productivity.

                    1. 2

                      I don’t know everything those do, but take a look at:

                      I have the second one set up on one machine but don’t have enough experience to make a recommendation.

                      1. 2

                        Yeah fzf-tab is killer in Zsh, wouldn’t want to switch to Fish unless I could have something similar.

                      2. 1

                        you no longer need configuration to speak of

                        This is the worst reason to provide me. I’m wondering what benefits there are to switch to Fish given that my Zsh is already well-configured. It’s also untrue, as I use a lot of Zsh features like hashed directories, functions and aliases, and things like fzf-tab, and I’ll still need to configure all the things in Fish like direnv, atuin, my prompt, etc.

                        I’ve looked into ways to share my bash/zsh aliases with Fish and I guess there’s bass?

                        1. 2

                          If your config is super-personalized then yeah, any switch is going to involve some config. For me, the defaults were 90% what I wanted and the rest was minor tweaks to simple stuff like prompt and aliases (hm, I wonder if Claude could rewrite your aliases for you).

                          In that case I will just say the Fish language and its affordances for configuration are very nice. As a tiny example, if you want to set an environment variable persistently and globally, it’s just a switch, set -U. It even gets set instantly in all currently-running shells!

                          1. 1

                            Hehe we are different kinds of people. Out of everything I know about Fish that’s the part I dislike the most so far (needing to edit env vars through the cli). I source control everything, would much rather add an export to a config file.

                            Best things so far seem to be 1. way better array handling, 2. more regular shell syntax in general. I’m a bit jealous of the better array handling and argument passing model but yeah it seems like a wash for now, no reason to switch from Zsh.

                            1. 2

                              It’s just editing the ~/.config/fish/fish_variables file for you, so it’s entirely visible to SCM. You can just edit it yourself if you want. Or you can do it the old-fashioned way with set commands in config.fish or conf.d/*. (Of course you don’t get the instant cross-shell setting that way, but that’s no worse than zsh.)

                              1. 2

                                Do not edit fish_variables, if you need to modify it, do it so via CLI or config.fish/conf.d with set command, otherwise you risk it being overwritten

                                1. 1

                                  Oh, not a two-way thing, huh? OK, then I agree it seems like a problem if you want to do source control on your dot files.

                    2. 6

                      If you want to go mouseless in Firefox but aren’t a vim user, Surfingkeys is quite good: https://github.com/brookhong/Surfingkeys/

                      1. 10

                        Firefox has two of these out of the box: / for “quick find” and ' (single quote) for find a link (when you hit enter it navigates to the link found).

                        1. 3

                          These are OK-ish, but they both only work for links that have text in them. They can be a nice speedup in some cases but they can’t replace the mouse altogether.

                          1. 2

                            I see the difference now, thanks. I’ve tried this kind of extension before, and one issue I had was that i had to press the shortcut, wait for the popups on the screen, and then type the letter(s) in the popup. In contrast, with the built-in ones, I can start typing without having to wait.

                          2. 1

                            Came in to post this. It works well for my purposes, but as pointed in other replies, limited.

                            I love my PaperWM, like the OP mentions. (Actually, precisely today I was able to switch my work computer from Windows to Linux and now I have PaperWM everywhere.)

                            BTW, apparently, this is how blind users roll. If it doesn’t work well with keyboard navigation, likely it sucks for blind users. (But of course, good keyboard navigation does not imply good accessibility for the blind.)

                          3. 4

                            I’ve had good luck with https://www.qutebrowser.org/ although it might be a bit minimal for some. Definitely doesn’t have all the FF features. Its default bindings are somewhat vim-like, but you can rebind.

                            1. 1

                              Yeah, QuteBrowser out of the box seems better than Firefox, but last I checked it doesn’t have uBlock Origin, so the overall experience was a pretty significant step back for me. Maybe if LibreWolf goes down the tubes I’ll give it another look.

                              1. 1

                                Since v2.0 it has a built-in adblock, which has been good enough for me. See Q8 in the FAQ

                            2. 1

                              Thanks for the link! Surprised I hadn’t heard of this extension before. This seems like a more extensible vimium? Any downsides?

                            3. 3

                              I just use the terminal and open Finder at the current directory with open .

                              1. 1

                                This looks good! For a long time I used dtrx (“do the right extraction”). I guess nowadays I tend to just use the built-in compression/extraction on Mac, but I’m happy to have an all-in-one cli tool. This seems ergonomic.

                                1. 8

                                  Didn’t read the article yet, but isn’t Go an awful choice for wasm because it brings a runtime with it?

                                  Edit: read the article, justification was basically “we knew Go” (which is fine) but didn’t address the runtime issues. They spent a lot of time discussing memory issues, which again would be better handled in a non garbage-collected, non-runtime-having language, I’d think.

                                  1. 7

                                    On paper, maybe, but the whole idea was to have n=1 languages for both of our UIs, and we weren’t about to rewrite everything in Rust. :)

                                    The Go runtime seems to be “good enough” but there are some tricks to it, like configuring a hard memory limit in the client so Go GC’s before it hits the limit and crashes:

                                    var memoryLimit = 1.7 * 1024 * 1024 * 1024
                                    
                                    func AppClient() {
                                    	// Have Go enforce a memory limit so it GCs instead of crashing.
                                    	debug.SetMemoryLimit(int64(memoryLimit))
                                    
                                    	// ...
                                    }
                                    

                                    The memory challenges were more around fitting in WASM’s 2GB memory cap when viewing absolutely gigantic traces or huge amounts of logs. And also minimizing allocs in key places. These are both general optimizations that paid off on the TUI side too.

                                    1. 3

                                      Did you experiment with TinyGo’s WASM backend at all? For large codebases it’s easy to run into its limitations but in cases where it can be made to work the resulting wasm can be much smaller, especially if you tweak things a bit.

                                      It sounds like go-app itself would be a problem and considering the size and nature of the project my guess is that it probably wouldn’t work anyway but I am curious if you’ve tried and how far it got.

                                      1. 4

                                        Yeah, I gave TinyGo a try but I kept running into missing packages/APIs and it was too troublesome to chase down all the broken dependencies (like gRPC). In the end I just threw Brotli compression at the problem and called it a day.

                                        Still think the project is really cool though and would love to try it again in the future.

                                    2. 2

                                      In addition to the heavyweight runtime and GC, Go’s syscall/js package seems to have been abandoned in perpetual experimental status as well (similar to their WebSockets package).

                                      Go doesn’t seem like the best choice for WASM.

                                    3. 2

                                      I’d love to see a modern terminal implementation. Using non standard keys shouldn’t be this hard. Some, like Kitty, have tried but those are more of an addon instead of a redesign.

                                      If you want to better manage your command history by project with docs/comments take a look at tome playbooks (by me). It also helps with multiline pasting.

                                      https://github.com/laktak/tome

                                      Extrakto, also for tmux, makes it easier to select and copy (also mine):

                                      https://github.com/laktak/extrakto

                                      1. 1

                                        Curious if you’ve tried Ghostty. Seems promising. I’ll need history search and better scrollback UX before I switch full time myself, but I believe the keybindings are configurable and the speed is impressive.

                                        1. 1

                                          I meant the keys for apps running in the terminal. For example mapping different actions for Tab and Ctrl+I in vim can be difficult, even more so with tmux in the middle.

                                        2. 1

                                          I’ve thought about this too. I think it’s kinda gotten to the point where you’d kinda need to be willing to throw away old bad ideas and accept that it will break some programs. Make an experimental rework of some of the core pieces, wait for/help libs like ncurses and termbox to use that functionality, and then help other terminals implement it. Even just a standard feature-detection mechanism would be really nice.

                                          1. 2

                                            Not sure you’d have to break anything if you add a translation layer. Isn’t that what tmux and vim with its integrated terminal are doing already?

                                          2. 1

                                            Some, like Kitty, have tried but those are more of an addon instead of a redesign.

                                            “Fully rewrite the terminal” is not the path forward. Kitty’s design is appropriate, IMU it’s basically a switch that enables a full keyboard protocol that any app can opt into. Just like Kitty was able to add a full graphics protocol to the terminal, it can be extended, people just need to agree on extensions.

                                            1. 2

                                              I’d rather have a new terminal protocol and a legacy layer. That would encourage more developers to support it IMO and make it easier for users as well to find out what works with what.

                                              1. 2

                                                I’d rather have a new terminal protocol and a legacy layer.

                                                Cool, go for it.

                                          3. 2

                                            How realistic is using Gleam as an alternative to TypeScript today?

                                            1. 5

                                              It’ll come down to personal taste and your specific requirements really. Folks are happily using Gleam for frontend and commercial programming.

                                              1. 2

                                                This is what I’m looking for: a language that compiles to javascript that’s usable and not this monstrosity that TS is these days

                                                1. 2

                                                  Yeah I was a fan of CoffeeScript back in the day, and I spent some time trying Elm but that was not it. It’d be nice if so much modern infrastructure wasn’t based off a language “written in 10 days”.

                                                2. 1

                                                  I used to use node and typescript for pet projects. I’m using Gleam for the last two I started and so far it suits all my needs.

                                                3. 11

                                                  One of my favorite bits about Zig is that it has a data structure that will do the array of structs -> struct of arrays conversion for you at compile-time so you can do the data-oriented optimization basically for free.

                                                  1. 4

                                                    Haven’t touched Node in a long while… Is this better than Bun?

                                                    1. 5

                                                      I would say so, yeah. definitely subjective tho.

                                                      1. 2

                                                        I can’t imagine any javascript runtime being better than what Sumner and team are doing with Bun. Here’s a thread disputing Deno’s benchmark results.

                                                      2. 5

                                                        I’m a fan of the symlink pattern described in the “trials and errors” section. Works more than well enough for most of my use cases.

                                                        1. 5

                                                          FWIW, chezmoi’s templating features allow users to choose to symlink select files (or all dotfiles, if desired). It is a much more flexible tool than something like GNU stow.

                                                          1. 3

                                                            The templating is exactly why I switched after years with rcm and GNU stow. It’s surprisingly powerful for maintaining separate configs over multiple machines, especially with multiple OS choices(Mac, NixOS, OpenBSD, Windows) or sections that need to draw from credentials / sensitive info.

                                                            1. 2

                                                              Oh, totally! The project is awesome, it owns a problem space that I’m grateful to not have to wade.

                                                              I like how the write up mentioned two precursors (symlinks, stow) to its usage, one of which works well enough for me. I should have said as much in the original comment. Rereading I see how it can come across as dismissive; apologies there, I hadn’t intended that.

                                                            2. 1

                                                              Agree. I symlink anything in my source-controlled ~/setup/HOME into my actual $HOME with a small script. It backs up anything that already exists, etc.

                                                            3. 1

                                                              On my m2 mba:

                                                              $ hyperfine 'zsh -ci exit'
                                                              Benchmark 1: zsh -ci exit
                                                                Time (mean ± σ):      66.4 ms ±   0.4 ms    [User: 42.5 ms, System: 21.8 ms]
                                                                Range (min … max):    65.8 ms …  67.2 ms    43 runs
                                                              

                                                              I use my own prompt written in Zig (that also checks git status) and don’t use any zsh plugin managers (never really understood why people do).

                                                              1. 1

                                                                To be clear: I don’t use a plugin manager (except if you count Nix itself as a plugin manager). What I use is parts of Zim framework (but not Zim, the plugin manager part, itself).

                                                              2. 5

                                                                Has anyone got more info on “Avoid Using Poetry”?

                                                                1. 13

                                                                  I think this stems from the fact that Poetry was released in 2018 and declared 1.0 in 2019. But then, shortly thereafter, the Python community released several dependency and packaging-related PEPs: PEP 517, PEP 518, PEP 621 and PEP 660. As a result, from 2019-2023, Python standardized a new approach to packaging, but poetry had, instead, created a fork in the road. Tools like rye, Hatch, and PDM embrace the PEPs, whereas Poetry is sort of “its own thing.” So using Poetry is kinda similar to using Conda/miniconda: it works, but it’s not designed around Python packaging standards. When you use it, you are making a bet that the maintainers keep it going. But it’s a sort of ironic situation since I think Poetry influenced a lot of the packaging standards that ended up making their way into approved PEPs.

                                                                  1. 13

                                                                    It also really says something about the state of Python tooling that Poetry continues to be discussed and recommended so many years later. Like, if a weird, non-standard tool continues to occupy so much “space” in the ecosystem, then the ecosystem still has some pretty significant work to do.

                                                                    1. 3

                                                                      I’ve been using Poetry. It works — I just published a new version of my library with it — and it’s still used by prominent people in the community. I thought it was PDM that went down the non-standard road by following provisional and ultimately rejected PEPs?

                                                                      1. 2

                                                                        Yes, for a while PDM defaulted for a rejected pep that basically proposed to have a node_modules directory but for Python. Venvs were secondary. Once it was rejected, though, the default changed.

                                                                  2. 11

                                                                    The overall list is very opinionated, but that one stood out to me also. Poetry is very actively maintained and works well. I find it quite ergonomic.

                                                                    Also, the alternatives the author recommends conflict with his earlier advice to avoid downloading “standalone builds” to set up python… both PDM and hatch do just that.

                                                                    I’m not aware of a substantive reason to avoid poetry, and would be very curious to hear about reasons to avoid it; with its ability to export requirements.txt files, it seems very low-risk to me.

                                                                    1. 5

                                                                      When Poetry introduced a new installer script, their solution to get people to migrate was literally to introduce deliberate breakage of CI jobs. For what was marked as the Poetry 1.2 release, so not even a major version bump. This broke a lot of people’s trust in Poetry (see that linked discussion and other related ones).

                                                                      Personally, I don’t ever trust an alternative package frontend in my CI/CD (can’t have them break it if I don’t let them run in it) and always want to export to a standard requirements file to be installed by standard pip. Unfortunately, last I checked Poetry had also deprecated their built-in export functionality and said it will have to move to third-party in the future.

                                                                      They also, as the other reply pointed out, have not implemented the standardized packaging metadata and 4+ years after the relevant PEPs finalized, still have only a draft PR that might hypothetically be part of a future 2.0 release. This makes it difficult to migrate to or coexist with other standards-based tooling.

                                                                      I am not a huge fan of alternative package frontends in general, but on the occasions when I do use one I avoid Poetry for these reasons.

                                                                      1. 5

                                                                        Unfortunately, last I checked Poetry had also deprecated their built-in export functionality and said it will have to move to third-party in the future.

                                                                        Why would you say this? After reading the supplied link I can confirm this is literally not true. Poetry supplies a first-party plug-in for the package manager that provides this functionality, it’s not being “deprecated”. Quote:

                                                                        In a future version of Poetry this plugin will not be installed by default anymore. In order to avoid a breaking change and make your automation forward-compatible, please install poetry-plugin-export explicitly.

                                                                        1. 1

                                                                          Today the functionality is available as part of the default Poetry install with no need to install third-party plugins.

                                                                          In the future it will not be available as part of the default Poetry install, and will require installing a third-party plugin.

                                                                          The Poetry documentation contains a warning of this impending change.

                                                                          Sure, technically it does not use the exact literal word “deprecated”, but that’s a deprecated feature and a deprecation warning.

                                                                            1. 1

                                                                              Regardless of who maintains it, it’s currently a default part of Poetry requiring no additional installation or configuration steps. It is going to become a non-default part of Poetry requiring an additional installation or configuration step. And the documentation warns about that impending change.

                                                                              That’s a deprecation.

                                                                      2. 3

                                                                        Poetry’s approach to version dependency ranges is a pain in the neck. Basically, it assumes a pessimistic version of SemVer and locks dependencies to avoid upgrades on the major version. SemVer is pretty debatable in the context of Python at the best of times, and this choice has caused a huge amount of difficulty, as it can often make it impossible to resolve dependencies.

                                                                        See https://iscinumpy.dev/post/bound-version-constraints/ for more.

                                                                      3. 1

                                                                        I agree it’s good to have a script to encapsulate the project setup for each language you use. Create basic files, directory structure, git repository with appropriate ignores, and install dependencies you’re going to want (eg. pytest). I have create- scripts for many languages. If anyone cares, here’s my Python project setup. (In looking at that, I need to update my default dependencies since switching to ruff)

                                                                        1. 7

                                                                          Impressive work on the docs!

                                                                          This means contributors can test changes to Zig standard library documentation, as well as autodocs functionality, by pressing refresh in their browser window, using a only binary distribution of Zig.

                                                                          It used to take upwards of 13 seconds. Now it takes 25ms.

                                                                          I too am dismayed by JS documentation toolchains. They seem to be very common, but also very heavy.

                                                                          But writing your own is a lot of work! In any case, this looks like huge progress


                                                                          On a different note, if I’m reading this right, Oils/YSH will likely have the same thing for func only (even though it’s obviously vastly different as a language)

                                                                          The alternate plan for this is to make all I/O operations require an IO interface parameter, similar to how allocations require an Allocator interface parameter today.

                                                                          i.e. funcs will be pure, and can’t do I/O without a parameter. (But procs are impure, and can do everything.)

                                                                          This is a huge change, but it has a bunch of benefits. I think it can be done without seeming too weighty

                                                                          • portability - looks like this is Zig’s main motivation. (This is not our main motivation, but you may want to do shell-ish configuration on Windows, and this could help)
                                                                          • security - if you have a big tree of packages like Rust or JS or Go, which is increasingly common in modern dev, I think it’s better if applications can control the capabilities that their dependencies can access
                                                                          • for Oils it’s also a “Perlis-Thompson problem” aka function coloring – func/proc has compositional issues like async/sync. Restricting I/O makes them more distinct and will preven/discourage weird and arbitrary interleavings

                                                                          It reminds me of my thoughts about functional programming – it means so many different things

                                                                          1. no global mutable state – Erlang/Elixir do have global mutable state – https://lobste.rs/s/mumfox/elixir_nitpicks#c_qxhfnw
                                                                          2. no ambient/global I/O - what Zig seems to be proposing
                                                                          3. expressions/recursion are preferred over statements/loops – e.g. Haskell/Elixir style vs. Python style

                                                                          IMO number 1 and 2 are much more important for the “good reasoning” of functional programming than 3 .

                                                                          It makes units of code understandable by their signature. And composable in the same way.

                                                                          So we may have a weird situation where Zig is more “functional” than Erlang/Elixir (at least according to my priorities)

                                                                          1. 7

                                                                            Re: the security implications of “make all I/O operations require an IO interface parameter”.

                                                                            This is proposed in Eliminate the POSIX API layer #6600. What is proposed is not a Capability based architecture (with security guarantees). It’s only a new portable OS abstraction. Zig would continue to support platform-specific OS interfaces like std.os.windows and std.posix. And Zig would continue to support C FFI. Note that C FFI is an ambient god-mode, allowing any dependency that uses it the freedom to anything at all, which is the complete opposite of a Capability based security architecture.

                                                                            I’ve spent some time thinking about how to design my new programming language to support capability based security. Getting those security guarantees requires some extreme design choices, and I don’t get the impression that the Zig community is considering anything like this. Specifically, how do you provide a C FFI in a language with capability based security?

                                                                            1. 5

                                                                              Specifically, how do you provide a C FFI in a language with capability based security?

                                                                              The obvious part of the answer is that any safe abstraction that is built on unsafe foundations must have a way to securely encapsulate the unsafe parts. Fortunately capabilities do that by design.

                                                                              A more interesting problem is how code can demonstrate that it uses only a controlled sliver of the FFI. One possibility might be to base the FFI around capabilities on shared objects, then you expect that a module that only has a capability on zlib can’t make a network connection. But that idea is incompatible with static linking, and it is undermined by the way popular C libraries tend to have sprawling convenience APIs. (I had to think for a while to be sure the zlib/networking example is plausible…)

                                                                              I would like a language with a capability-oriented module system. Ideally it would be normal and convenient to compose modules and their dependencies in a dependency-injection style, except that it ought to happen at compile time. It would probably have a strong flavour of ML modules and functors: a functor is a module that takes its dependencies as capability arguments. Then you could have simple easy-to-audit modules that (given an general FFI capability) just provide a curated list of foreign types and functions, separate from higher-level modules that turn them into safe APIs.

                                                                              1. 1

                                                                                Yeah I would like such a module design – I honestly think it could encourage more reuse, not less!

                                                                                I can see why doing it at compile time is appealing, especially with Zig comptime – but I have found dynamic composition to be very useful and common. Probably you would want a mix of both, with similar syntax.

                                                                                The static version could be a partially evaluated version of the dynamic version

                                                                                Rust seems to unify static and dynamic dispatch more than C++, but I’m not sure it’s all the way there

                                                                              2. 5

                                                                                Hm I think you have to treat any C dependency as impure by default. C is the wild west – I consider mutable global env vars like LANG to be I/O, so even tolower() is impure in my eyes. It certainly has all the same bug-inducing properties

                                                                                So instead of libc::glob() it has to be io->glob() or glob(io, ...). And you pass io around everywhere, or you wrap io in a more restricted “role” like globber and you pass that around.

                                                                                I think it can be done with some small ergonomic affordances

                                                                                In Oils/YSH I was thinking of abbreviating glob(io, '*.txt') as glob!('*.py')

                                                                                ! sometimes means mutability (Ruby, Lisp) but I would use it for I/O and side effects in general


                                                                                I haven’t thought much about compilers vs. interpreters, but I think a compiler toolchain could simply enforce the rule that any FFI is considered impure. And then you have an opt-in (similar to unsafe) where you can declare that say sin() is a pure function.

                                                                              3. 2

                                                                                The alternate plan for this is to make all I/O operations require an IO interface parameter, similar to how allocations require an Allocator interface parameter today.

                                                                                That was definitely the most interesting line of the patch notes to me. I’d love to read more if there’s a Zig ticket about this.

                                                                              4. 11

                                                                                Fish might be the most successful “Rewrite it in Rust” project I’ve ever seen. There’s only about 11k~ lines of C++ left in the whole repository 🤯.

                                                                                1. 10

                                                                                  For anyone interested in the state of the rust rewrite, one of the maintainers posted a nice update on this a month ago: https://github.com/fish-shell/fish-shell/discussions/10123

                                                                                  1. 5

                                                                                    It’ll be interesting to read a retrospective when they’re done.

                                                                                  2. 1

                                                                                    I created a “To consume” (watch/read etc.) list in TickTick and quick-add things to it. Then anything permanent gets added to the appropriate place in Obsidian.

                                                                                    1. 2

                                                                                      qutebrowser is a keyboard-focused browser with a minimal GUI.

                                                                                      What’s the benefit of using qutebrowser over Firefox with Vimium?

                                                                                      1. 14

                                                                                        The keyboard focus is first class and the browser is built around it instead of being a bolted on addition that stops working as soon as you are in a non browsing context.

                                                                                        Vimperator/Pentadactyl were much better than vimium/tridactyl but RIP XUL based extenions, and I think qutebrowser is on the same level as those.

                                                                                        1. 4

                                                                                          I would get into situations where I still had to use mouse in Firefox with vimium (or was it a different one), I think it didn’t work on built-in pages for example.

                                                                                          1. 3

                                                                                            Vim’s style of keyboard bindings works within the restrictions of Firefox’s extension model, but Firefox prevents extensions from rebinding the keys would would need to make an Emacs equivalent, the switch to webextensions effectively killed every one of the Emacs-style extensions.

                                                                                            (That said, I prefer solving this problem at my WM level instead; I tried qutebrowser but the adblocking was much worse than ublock origin at the time, plus it didn’t have reader mode which is a pretty critical feature.)

                                                                                            1. 6

                                                                                              For what it’s worth, a readability userscript has been around since 2016, and an improved one based on Mozilla’s library since 2019.

                                                                                              Adblocking is still worse than uBO due to lack of element hiding, but it’s already gotten much better in v2.0.0 (2021) when support for the Brave adblocking library was introduced.

                                                                                              1. 3

                                                                                                Any time I see the word userscript I immediately know there is a gap there for people who go dead-eyed at the word userscript.

                                                                                                1. 1

                                                                                                  Those people probably go dead eye also when you talk about using a different browser.

                                                                                            2. 2

                                                                                              Nothing if you don’t want another Chromium based application.

                                                                                              1. 1

                                                                                                What’s the benefit of using qutebrowser over Firefox with Vimium?

                                                                                                As mentioned, the keyboard driven interactions feel more deeply integrated than implementations at the userscript level and that’s probably the main selling point.

                                                                                                Also configuration options for the browser UI are more flexible, in part because config is (or can be) a python file. Also I may be biased since I’m more comfortable with python than C++ but it feels a lot more “hackable” to me than firefox if you build from source. You can slap in new behavior in a couple of lines of python and a browser restart which feels a lot more accessible than trying to touch the source for FF or chromium.

                                                                                                Admittedly kind of a niche perk, but qutebrowser’s core audience is probably a lot more likely to appreciate it than the general population.

                                                                                              2. 2

                                                                                                Thanks for the link. I don’t have time to watch the video now, but I am interested in this space.

                                                                                                We repeatedly see the tension between code and configuration. Tools like Chef and Puppet used a Ruby DSL, so a limited subset of a full language. Then everyone started stuffing logic into YAML, with tools like Ansible and Salt. Invariably, they “evolve” loops and conditions. Now we have tools like Terraform that use HCL, which is just an abstraction over JSON, to also do loops and conditions and templating and so on. Tools like Pulumi take the other approach again of using a full programming language used in a specialized way, and a lot of the newer stacks from AWS and Terraform similarly use JSII to bring-your-own-programming-language for their CDK platforms.

                                                                                                We keep going back and forth on this and the churn feels really stupid and a waste of lifetimes of human potential. Clearly we desire a more constrained way to write more constrained domains of code, but the more we constrain the more we need to break out of the constraints!

                                                                                                The language I’m most interested in as a reasonable compromise between a “full” language and a “configuration” language is https://cuelang.org/. It’s got an interesting use of types, among other things. I’m not so familiar with Dhall. Would you please give a quick comparison between the two?

                                                                                                1. 7

                                                                                                  I don’t think a simple config language is tenable for IAAS configuration. Modern infrastructure is replicated, so a simple language will require tons of repetition if a new block is to be copied per server or per region. It’s also common to have duplication with slight changes. For example. nonprod envs are usually the same as prod envs but with different dependencies and names, most parameters won’t need to change. (In fact, you want minimal changes so testing can happen in an env that’s very similar to prod.)

                                                                                                  So, very quickly, you end up with ways to increase repetition with variation (loops over a list) reduce duplication (inheritance, mixins, includes).

                                                                                                  I think what people do want is to be able to diff two versions of a simple language. The input language can be complex, and, in the limit, might as well be a regular programming language, as Pulumi does it. But it is easier to review a diff using the final, expanded, simple output language.

                                                                                                  You can end up in the middle tar-pit, like GCL at Google. It’s a super complex language with lots of gotchas. It actually is Turing-complete in a terrible way. It’s simple to just use something like a restricted Python - and there has been a general switch to that at the company, as well.

                                                                                                  1. 4

                                                                                                    It’s simple to just use something like a restricted Python - and there has been a general switch to that at the company, as well.

                                                                                                    Which leads to another sub-optimal endpoint: now every tool you use has a slightly different interpreter which has cherry picked different language features to support. Now you get to play Python feature roulette every time you edit a configuration file!

                                                                                                    1. 1

                                                                                                      Anyone who wants a restricted Python should use Starlark https://github.com/bazelbuild/starlark/blob/master/spec.md

                                                                                                      Starlark seems pretty nicely designed, tho there aren’t many implementations - there’s a golang one and a java one (part of bazel). But I really hope it doesn’t suffer from multiple dialects.

                                                                                                      1. 2

                                                                                                        tho there aren’t many implementations - there’s a golang one and a java one (part of bazel)

                                                                                                        There’s also a Rust implementation as part of Buck 2: https://github.com/facebookexperimental/starlark-rust.

                                                                                                    2. 4

                                                                                                      Modern infrastructure is replicated, so a simple language will require tons of repetition if a new block is to be copied per server or per region.

                                                                                                      As a software dev, Terraform HCL drove me absolutely nuts. So much copy and paste. “There are patterns here, can I make a function?” “You can create an HCL module”. Ugh.

                                                                                                      1. 3

                                                                                                        I also think Cue is very interesting! I haven’t looked at it very much, so I don’t think I can do a proper comparison with Dhall. Generally my understanding is that you use Cue together with .yaml, and cue defines the validations etc. With Dhall you just use Dhall. You can convert it to json/yaml, but you can also use it directly. Also, Dhall mostly does typing, as in you just say “this is a number” and “this is a string”, while cue does more validation like “this is a number that is larger than this other number”. You can do that in Dhall as well, but it’s more clunky. Dhall feels more like a “Json for Haskell”, and CUE I guess is more of an “TLA+ for yaml” or something.

                                                                                                        For cloud stuffs I have used the AWS CDK, and I think it’s probably the best approach there. I should try Pulumi at some point. :)

                                                                                                        1. 4

                                                                                                          I like Cue’s types because in practice types are not “this is an integer” but “this is an IP address” or “this is a number in the range of…” and so on. I don’t think Cue is at all dependent on YAML, my understanding is it’s both the configuration format itself, as well as the language in which you define the types/constraints on top of your data fields. So it’s got a neat consistency “all the way down”.

                                                                                                          1. 2

                                                                                                            In practice types are not “this is an integer” but “this is an IP address” or “this is a number in the range of…” and so on

                                                                                                            Yes, that’s what I was trying to say.

                                                                                                            It’s not bound to .yaml, but it seems very cleary advertised as validation for .yaml, .json and other text. The home page of CUE shows a video of it validating .yaml on the top.

                                                                                                          2. 4

                                                                                                            CUE is a superset of JSON and you can write all your data in CUE. YAML and JSON are possible output formats.

                                                                                                          3. 2

                                                                                                            We repeatedly see the tension between code and configuration. Tools like Chef and Puppet used a Ruby DSL, so a limited subset of a full language. Then everyone started stuffing logic into YAML, with tools like Ansible and Salt.

                                                                                                            There is a third way - Pulumi (and I think AWS CDK) let you use a full programming language with no restrictions. With CDK it’s Typescript, and in Pulumi’s case you can use “any JVM language (Java, Scala, Kotlin, Clojure), .NET (C#, F#, PowerShell), Node.js (JavaScript, TypeScript), Go, Python”.

                                                                                                            I’ve been using Pulumi with Typescript and it’s been great. My last exposure to DevOps had been with Chef, which I really disliked using.

                                                                                                            I wouldn’t call myself a DevOps engineer or SRE, more just a fullstack engineer who ended up needed to deploy and manage a bunch of infrastructure on AWS.

                                                                                                            1. 3

                                                                                                              I cover Pulumi and AWS/Terraform CDK in my comment. I’m glad to hear your experience with Pulumi has been good, It’s the product I’m most interested to try next time I need to do IaC.

                                                                                                              1. 2

                                                                                                                This sounds like a bad idea to me. One of the main benefits of Dhall is that it is a total programming language giving you guarantees about program termination. I don’t want my infrastructure deployment blowing up because I got too cute with recursion in javascript or whatever.

                                                                                                                1. 2

                                                                                                                  I talk about this in my talk as well, sadly total programming doesn’t guarantee that. It can still use way too much memory or create a function that will take so long, it might as well be forever. This blog post describes it pretty well: https://www.haskellforall.com/2020/01/why-dhall-advertises-absence-of-turing.html

                                                                                                                  you can craft compact Dhall functions that can take longer than the age of the universe to evaluate.

                                                                                                                  1. 1

                                                                                                                    I can’t remember the last time I managed to crash a JavaScript interpreter. I’m pretty sure that in practice this is not a problem anyone has (it would be recoverable, at least with Pulumi). Anyway it’s always possible that any tool could experience eg a network or power outage so they all need to be able to recover from that kind of thing.

                                                                                                                2. 1

                                                                                                                  Puppet has its own language.

                                                                                                                  1. 1

                                                                                                                    The heritage from Ruby is quite obvious though.

                                                                                                                3. 4

                                                                                                                  Responded to the survey. I don’t use Fennel too extensively as I don’t use Lua much, but I’d prefer to use Fennel wherever I use Lua. Here is basically the extent of my Fennel code, which I use for my Hammerspoon config: https://github.com/kbd/setup/blob/master/HOME/.hammerspoon/init.fnl

                                                                                                                  The easy function definition syntax, among other conveniences, makes the code much more concise. I’m just always frustrated when errors don’t have matching line numbers, and it’s annoying that I often have to add do blocks so that I can add some debugging that I then remove when I’m done writing code.

                                                                                                                  1. 2

                                                                                                                    The easy function definition syntax, among other conveniences, makes the code much more concise.

                                                                                                                    But IIRC you don’t get arity checks when you use the “normal” function definition syntax, right?

                                                                                                                    1. 1

                                                                                                                      Fennel behaves the same as Lua afaik and any un-passed arguments are silently nil:

                                                                                                                      $ lua
                                                                                                                      Lua 5.4.6  Copyright (C) 1994-2023 Lua.org, PUC-Rio
                                                                                                                      > function hello(name) print("Hello " .. name) end
                                                                                                                      > hello('keith')
                                                                                                                      Hello keith
                                                                                                                      > hello()
                                                                                                                      stdin:1: attempt to concatenate a nil value (local 'name')
                                                                                                                      
                                                                                                                      $ fennel
                                                                                                                      Welcome to Fennel 1.3.1 on PUC Lua 5.4!
                                                                                                                      Use ,help to see available commands.
                                                                                                                      Try installing readline via luarocks for a better repl experience.
                                                                                                                      >> (fn hello [name] print (.. "Hello " name))
                                                                                                                      #<function: 0x6000034c8120>
                                                                                                                      >> (hello)
                                                                                                                      runtime error: attempt to concatenate a nil value (local 'name')
                                                                                                                      ...
                                                                                                                      >> (local hello2 #(print (.. "Hello " $1)))
                                                                                                                      nil
                                                                                                                      >> hello2
                                                                                                                      #<function: 0x600003af9950>
                                                                                                                      >> (hello2)
                                                                                                                      runtime error: attempt to concatenate a nil value (local '_241')
                                                                                                                      ...
                                                                                                                      >> (hello2 "keith")
                                                                                                                      Hello keith
                                                                                                                      
                                                                                                                      1. 3

                                                                                                                        Arity checking is one of those things I really feel like the computer should be responsible for, not me. You can define functions with lambda instead:

                                                                                                                        $ nix-shell -p fennel --run fennel
                                                                                                                        Welcome to Fennel 1.3.0 on PUC Lua 5.2!
                                                                                                                        Use ,help to see available commands.
                                                                                                                        Try installing readline via luarocks for a better repl experience.
                                                                                                                        >> (lambda hello3 [name] (print (.. "Hello " name)))
                                                                                                                        #<function: 0x600002187ed0>
                                                                                                                        >> (hello3)
                                                                                                                        runtime error: Missing argument name on unknown:1
                                                                                                                        ...
                                                                                                                        >> (hello3 "Keith")
                                                                                                                        Hello Keith
                                                                                                                        

                                                                                                                        This way you get an error when you first try to call the function, instead of only finding out later when the presence of a nil value screws something up.

                                                                                                                      2. 1

                                                                                                                        You don’t get arity checks with fn but you do get them with lambda (which is also aliased to λ if you prefer brevity). Which you use is up to you and the language doesn’t emphasize one over the other, but of course there is a slight performance penalty to checking.

                                                                                                                        In any case all are shorter than the Lua equivalent of function which also has the requirement for an explicit return in it.

                                                                                                                      3. 1

                                                                                                                        I’m just always frustrated when errors don’t have matching line numbers

                                                                                                                        Can you set the correlated option to the compiler? That should make it so the compilation output line numbers match up with the original source.

                                                                                                                        If you have access to the error handler and you’re not doing AOT, another option is to print the stack trace from fennel.traceback instead of debug.traceback; that will apply source mapping more accurately.

                                                                                                                        1. 1

                                                                                                                          I’m just executing the fennel code with:

                                                                                                                          fennel = require("fennel")
                                                                                                                          table.insert(package.loaders or package.searchers, fennel.searcher)
                                                                                                                          fennel.dofile("init.fnl")
                                                                                                                          

                                                                                                                          And the tracebacks are output to the Hammerspoon console by Hammerspoon, so I don’t have control over them.

                                                                                                                          1. 1

                                                                                                                            Try this:

                                                                                                                            require("fennel").install({correlate=true}).dofile("main.fnl")
                                                                                                                            
                                                                                                                            1. 1

                                                                                                                              Ty, but no such luck. Introduced a random error on line 38, invoked it and got:

                                                                                                                              2023-08-14 15:56:08: 15:56:08 ERROR:   LuaSkin: hs.hotkey callback: init.fnl:44: attempt to call a nil value (method 'frae')
                                                                                                                              stack traceback:
                                                                                                                              	init.fnl:44: in function <init.fnl:42>
                                                                                                                              	(...tail calls...)
                                                                                                                              

                                                                                                                              in the Hammerspoon console. Line 44 is in a different function.

                                                                                                                              1. 1

                                                                                                                                Hm; odd. Unfortunately Hammerspoon won’t run on my computer, so I don’t think I can try it for myself to debug.

                                                                                                                                Edit: I do remember hearing about Spacehammer which is like hammerspoon but has native fennel support. I’d guess it would include an override for the stack trace printing which uses the source maps?