• 1 Post
  • 19 Comments
Joined 2 months ago
cake
Cake day: August 13th, 2026

help-circle

  • Why are you so confident of that, if you’re a non-native English speaker? I’m a native English speaker, and I have also written and read many technical blog posts for over a decade, and I see Claudish all over the place.

    If what you said were true, then I would have never have seen Claudish, and that’s obviously not true.

    If you genuinely haven’t seen Claudish in English on the Internet in the last year, then I would suggest that’s because your English is not as native as you think it is. Or maybe you just don’t use Claude that much. (I use Claude all the time, because it is useful, but that also makes its tics very apparent when I encounter them on a blog. And yes it immediately makes me suspicious of sloppy thought.)


    Actually one prominent and sorta sad example is that I’m basically certain Professor Joe Hellerstein has been using Claude to write blog posts since April 2025. The timing is pretty suspicious on its own.

    https://jhellerstein.github.io/blog/

    e.g. https://jhellerstein.github.io/blog/cost-of-committing/ - so many Claudish tics here

    I was reading his papers on distributed systems (CALM, Bloom, etc.) over 10 years ago. That was technical prose.

    I don’t know if he had a blog prior to 2025, but I bet if he did, you can compare the prose and see that it’s now done with Claude.


    score 1 · canonical




  • That is not what I get on my Debian machine! Further adding to the confusion :-)

    $ /bin/bash --posix -c "echo 'a\nb'"
    a\nb
    
    $ /bin/bash --version
    GNU bash, version 5.2.15(1)-release (x86_64-pc-linux-gnu)
    
    $ /bin/sh -c "echo 'a\nb'"
    a
    b
    

    That doesn’t surprise me, because POSIX does not specify which one is right. bash is POSIX-compatible and dash (/bin/sh on Debian) is POSIX-compatible, in this respect, and they are incompatible/contradictory behaviors.

    I think you are on OS X because your /bin/sh is the last GPLv2 version of bash, 3.2.57, which is ancient.

    So apparently bash 3 and bash 5 have incompatible/contradictory behaviors, and both are POSIX-compatible. POSIX doesn’t help you!


    Just to prove the point more, here’s a Red Hat machine:

    $ /bin/sh -c "echo 'a\nb'"
    a\nb
    
    $ /bin/sh --version
    GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)
    

    Red Hat uses bash as /bin/sh, and it behaves differently than Debian which uses dash as /bin/sh.

    i.e. /bin/sh being “POSIX” is a weak guarantee, not something most people want to rely upon.


    score 2 · canonical


  • POSIX shell aka /bin/sh is bash on OS X, while it’s dash on Debian, busybox ash on Alpine, etc.

    The OP makes this claim, which I’m saying is not really true in a practical sense:

    That means you can run your program on a wide range of hosts, from a Linux virtual machine, to a BSD server, to a Mac laptop, to a tiny single-board computer

    As an analogy, imagine if there was no such thing as JavaScript. Imagine you wrote v8 code (Chrome), or you wrote SpiderMonkey code (Mozilla), or you wrote Opera browser code.

    That more accurately describes the situation with Unix shell. It is not as standardized as JavaScript, basically because there is not that much industry motivation do make it so.

    And not just shell – it’s all the utilities that shell calls, which you need to get things done.


    score 1 · canonical


  • create programs that are highly portable, able to run on any contemporary Unix system with no runtime dependencies other than the basic utilities specified by POSIX.1-2024. (Of course, your programs may have their own runtime dependencies; that’s fine. But everything in Brut adheres to the POSIX constraint.) That means you can run your program on a wide range of hosts, from a Linux virtual machine, to a BSD server, to a Mac laptop, to a tiny single-board computer

    I don’t believe in “just use POSIX shell” … Here is a recent article (not from me) that makes some good points:

    I actually forgot about this example, and it’s pretty bad:

    $ sh -c "echo 'a\nb'"
    a
    b
    
    $ bash -c "echo 'a\nb'"  # same program has a different meaning!!
    a\nb
    
    # POSIX doesn't help you !!!
    

    i.e. busybox ash and dash are the default /bin/sh on Alpine and Debian respectively, and they differ a lot from bash, which is the /bin/sh on other distros (I think Red Hat based systems, although I am not sure. Maybe Arch)

    Also I am not sure but on OS X did /bin/sh used to be bash 3 (which has many differences from bash 4 !!), and then it changed to zsh? Or do they have a different stable /bin/sh ? I suspect the former


    If you really want to make shell portable in shell, you will get into crazy hacks like this: https://github.com/modernish/modernish

    Modernish is a library for shell script programming which provides features like safer variable and command expansion, new language constructs for loop iteration, and much more.

    i.e. It’s not even that you can’t use echo, but you have to turn shell into a different programming language. Look at modernish code – it’s a different language, that happens to run on many shells.


    As far as Oils, I would say OSH makes a large subset of bash a reasonable portable target – it is the most bash-compatible shell in the world: https://pages.oils.pub/spec-compat/2025-11-02/renamed-tmp/spec/compat/TOP.html

    And YSH is a different language, which is better done in native code, at the interpreter level, than in shell (as modernish does)


    score 9 · canonical






  • Any Fedora users here? I briefly mentioned this in the post, but I was able to get the same tarballs compiling pretty easily on Debian/Ubuntu and Alpine. Basically ./configure; make of zsh, and some MyPy deps via python3 -m pip.

    But, for some reason, I ran into multiple build errors on a Fedora image from sourcehut. I was kind of surprised by that, and also that I couldn’t figure out what the problem was :-/

    Compiling bash had this error

    /usr/homes/chet/src/bash/src/parse.y: In function ‘decode_prompt_string’:
    /usr/homes/chet/src/bash/src/parse.y:5741:21: error: implicit declaration of function ‘count_all_jobs’ [-Wimplicit-function-declaration]
    

    This error with a MyPy dependency also happened on Fedora, but not Debian/Alpine (also resisted my attempts to patch it)

    https://github.com/python/typed_ast/issues/169

    The zsh error is related to ncurses, and I installed the ncurses-dev package from Fedora

    /usr/include/term.h:783:56: note: previous declaration of ‘boolcodes’ with type ‘const char * const[]’
      783 | extern NCURSES_EXPORT_VAR(NCURSES_CONST char * const ) boolcodes[];
          |                                                        ^~~~~~~~~
    make[3]: *** [Makefile:232: termcap.o] Error 1
    

    http://travis-ci.oilshell.org/srht-jobs/1135480/dev-setup-fedora.wwz/_tmp/soil/logs/spec-bin.txt

    So I was surprised to get 3 different build errors on Fedora that didn’t happen on Debian/Ubuntu/Alpine, especially for bash and zsh which are extremely common. I was beginning to suspect that the sourcehut image has something weird about it, and this doesn’t happen on stock Fedora, but I didn’t have time to look into it more.


    The goal of this is to make it easy for people to change Oils on any distro, and not rely on containers! We need specific versions of our dependencies. The build deps are stabilizing so Nix should also work, though it will take some work to pin MyPy and its deps.


    score 2 · canonical


  • For some more color, I get a strong impression that the v8 codebase is monstrously complex, and kind of “topped out” several years ago.

    That is, trying to make it faster now is like squeezing blood out of a stone. It seems impressive but I think under the hood it’s strained - https://v8.dev/blog

    v8 is at least 2 million lines of code now, it’s probably almost the size of GCC or Clang.

    I’ve been watching videos on WebAssembly for the past few years, and two of the co-creators Andreas Rossberg and Ben Titzer were also tech leads of v8. (WASM is basically JavaScript JITs in the browser given an alternative front end that’s not JS. My rough version of the history at the end of this comment - https://lobste.rs/s/djxada/missing_point_webassembly#c_dveoie )

    It’s honestly a little surprising to me how much they throw shade at v8 :-P It sounds like they regret the state of the codebase, and it was not fun to work in.


    On the other hand, mycpp is like a 5000 line Python program that prints C++. It’s dirt simple and naive (since I don’t really know how to write compilers), but it results in very fast code. As long as we can correctly print C++ types, then the C++ compiler does all the work.

    So naively that’s 2M lines vs. 5000 lines, or a 400x code size difference. Honestly that sounds roughly right – v8 is more the product of 400 engineers, while mycpp is like 1.

    But mycpp is much faster, just because it does straightforward AOT.

    The tradeoff of course is that it took us quite awhile to make the Oils statically typed, so this technique is possible. Definitely longer than I thought, for a relatively small codebase. But there was really no other option, since it’s not like we will write a JIT … that is a crazy amount of engineering


    score 2 · canonical


  • One comparison is with JavaScript: for a long time there was an assumption that a lot of optimizations were just inapplicable given the lack of a type system and everything, until eventually we found a way to do them.

    Yes but this only goes so far … I wrote a little rant here about how AOT compilation (Rust, C++, Go) is better for a big class of problems, basically anything in involving languages – interpreters, type checkers, formatters, linters

    https://news.ycombinator.com/item?id=35045520

    To be controversial, JITs have “failed”, otherwise we wouldn’t be rewriting a lot of code. Emery Berger frames Perl / Python / JS / PHP as the “irrational exuberance” languages

    The canonical example being that the TypeScript compiler would be a lot faster if it wasn’t running on a JavaScript runtime. All that type info is thrown away, and doesn’t contribute to speed.

    Many people are rewriting these tools in AOT languages (esbuild in Go, etc.) and that choice makes a lot of sense. Python has a lot of really slow tools like Black and or yapf, compared with clang-format.

    For Oils we wrote a Python-to-C++ translator that uses MyPy static types. It was more work to make the source program 100% statically typed, vs. trying to get a JIT to do it, but it’s way faster, and uses way less memory [1]. We basically have garbage-collected C++ semantics and not Python semantics (but Python syntax). So it’s all AOT, and no JIT at all.

    Brief Descriptions of a Python to C++ Translator

    I still prefer an interpreter-like development experience, and I like dynamic languages for metaprogramming. But if the concern is speed, then AOT compilation with static types is just better IMO. (For numeric problems, the pattern where you use Python to generate an IR and then compile/parallelize/GPU it is still AOT, so it’s true that you have to look more carefully, and can’t just go by the language)

    [1] e.g. https://www.oilshell.org/release/0.20.0/benchmarks.wwz/mycpp-examples/


    score 3 · canonical



  • The words are all messed up at this point, but RPC traditionally meant mechanisms like “procedure naming” and “marshal arguments and return values”. It’s designed to make remote procedure calls as convenient as local ones with respect to particular programming languages.

    So I’d say HTTP isn’t RPC because it’s not designed for, or convenient for, that purpose.

    You can make it do such things, but it takes extra work, and you also lose things like HTTP proxy support (middleboxes).

    If HTTP were RPC, then you wouldn’t have additional protocols like JSON-RPC tunneled inside HTTP. JSON-RPC specifies how your arguments and return values are marshaled.

    If HTTP were RPC, you wouldn’t have to say “HTTP POST”. Middleboxes understand HTTP verbs; they often don’t understand your custom protocol inside HTTP. The network isn’t just about the end points.

    Likewise, TCP/IP isn’t a protocol for hypertext, although you can use it that way. You have another layer with more semantics.


    score 38 · canonical



  • OK now I see what expandEnd is trying to do – based on the capture of the begin pattern, it’s dynamically compiling a regex for an end pattern. (This is trying to match TextMate semantics, and TextMate also apparently does this dynamic compilation …)

    Except that rewrite is unsound:

    • \1 versus \\1 – the latter is a backslash and then the digit 1, and gets messed up
    • [\1] – is in a character class, not a backreference
    • \10 is not a backreference – there are only 9 in JS, with a single digit

    This is gross … I wanted to call it slop, but it’s actually inherited from TextMate. So there is pre-AI slop too, or Unix sludge …


    score 1 · canonical


  • Yup, so this should say Textmate-like grammars, not “TextMate grammars”

    MicroLighter uses the CSS Custom Highlight API and TextMate grammars

    The grammars look like they are forks of upstream, eliminating all the Oniguruma constructs and so forth:

    https://github.com/davatron5000/microlighter/tree/main/src/grammars

    To be fair the README does address this, which I missed the first time. But the tagline is not accurate

    MicroLighter reads TextMate grammars with the browser’s native RegExp … It does not use Oniguruma, WebAssembly, or generated token markup.

    But it also munges regexes with regexes, which is pretty gross:

    /**
     * Replace TextMate end-pattern backreferences with escaped begin captures.
      ...
     */
    const expandEnd = (pattern, beginMatch) => pattern.replace(/\\(\d+)/g, (reference, index) => {
      return beginMatch[index] === undefined ? reference : escapeRegex(beginMatch[index]);
    });
    

    So yeah it seems poorly-specified – not something I’d want to build on. TextMate itself is a bit poorly specified, which is why everyone has to drag along Oniguruma


    I would like something like this, but not confined to JavaScript regexes. I am thinking about a “lexing VM” for syntax highlighting and other tools like sloccount, that’s built on top of regular languages and constructs like “find constant string”, “capture delimiter”, etc. I’ve been thinking about that since using writing syntax highlighters in Vim and C++/re2c: https://github.com/oils-for-unix/oils.vim/blob/main/doc/algorithms.md


    score 1 · canonical