1. 1

    Scheme: The already small ecosystem is deeply Balkanised and writing a large Scheme program that works on multiple implementations is nigh impossible without expending great effort on portability. You have to pick an implementation and stick to it. As a consequence, the library selection is scarce. Even Common Lisp is better than Scheme at cross-implementation compatibility.

    Clojure: I can’t stand the worse-is-better approach that deviates from the Lisp tenet of do-the-right-thing. The “let someone write a library for it” principle puts me off. The majority of useful libraries that do something that really should be in the core library are abandoned on GitHub.
    Edit: Oh and Clojure’s nil punning is a ridiculously bad design pattern and you can’t change my mind about this.

    1. 37

      Although I’m glad this article explicitly distinguishes uses of Go and Rust, I still don’t understand why people keep trying to compare these two languages. They clearly have different approaches to different goals.

      From the panel Systems Programming Languages in 2014 and Beyond:

      When we first announced Go, we called it a systems programming language, and I slightly regret that because a lot of people assumed it was an operating systems writing language. What we should have called it is a server writing language, which is what we really thought of it as.
      —Rob Pike (Go creator)

      Writing client-side applications. The polar opposite of what Go is designed for. In these applications, you have high latency needs, high security requirements, a lot of requirements that don’t come up on the server side.
      —Niko Matsakis (Rust dev)

      1. 26

        I still don’t understand why people keep trying to compare these two languages.

        I think this is very simple. For a long time people dreaded writing C++ and were looking for a(n imperative) language that compiles to native binaries. Then there were (some time apart) Go and Rust [1]. Both languages filled the ‘a more modern language that compiles to native code’-niche. People start to compare them, besides being very different languages.

        Besides that, they have overlapping niches where they excel, such as command-line tools.

        [1] Of course, there were many other alternatives, such as OCaml, Haskell, D, Ada, etc. But they never attained critical mass.

        1. 4

          I’m looking at Crystal currently, as a possible contender in this field (GC, native, fast, and expressive). Looks very promising.

          1. 2

            Of course, there were many other alternatives, such as OCaml, Haskell, D, Ada, etc. But they never attained critical mass.

            What qualifies as critical mass? The languages you cite are all self-sustaining, even if their ecosystems don’t grow at the same speed.

            1. 10

              What qualifies as critical mass?

              Obviously, there is no fixed definition. But it’s clear that a language must have an library ecosystem of a certain size, IDE support, documentation, availability of programmers, etc. before any random given company will seriously consider it for their next project.

              Whether these are well-justified reasons is another question. Whatsapp used Erlang and was a fraction employee-wise from many social network competitors and created a crazy amount of value (for the owners and shareholders).

              1. 8

                Critical mass such that people need to write blog posts clarifying “why go and not x”?

            2. 12

              Go is faster than Python.

              Rust is safer than C, and, once you get the ownership concept down, safer and easier to understand than C++.

              (This post is unapologetically in the style of Paul Graham’s ha-ha-only-serious essay “What Languages Fix” which is still a pretty good read.)

              1. 11

                Go is faster and easier to build large scale systems in than Python or Ruby.

                1. 9

                  and easier to build large scale systems in

                  That’s pretty subjective. Can we stick to quantitatively verified facts instead of playing “my X can beat up your X,” please?

                  1. 9

                    How is “Go is easier to build large scale systems in than Python or Ruby” any more subjective than “Rust is easier to understand C++”? If anything, I’d argue that while both are subjective claims, the former is less subjective, just because static typing is widely considered an advantage when it comes to large scale systems.

                    1. 1

                      How is “Go is easier to build large scale systems in than Python or Ruby” any more subjective than “Rust is easier to understand C++”?

                      It’s not. I should have also replied to the other post, too.

                    2. 6

                      To your meta comment, I am aping the “What Languages Fix” style of language property identification, which is necessarily subjective.

                      To the point itself, I think the notion that a language designed from first principles to support the practice of software engineering in large organizations is better at doing so than dynamically-typed, interpreted, prototyping languages like Python and Ruby is about as noncontroversial as subjective claims can be. And, for the record, reliably borne out by the vast majority of experience reports.

                      1. 4

                        And, for the record, reliably borne out by the vast majority of experience reports.

                        I’ve also seen experience reports suggesting that Ruby and/or Python are the most productive. Unless you can point to a broad study, from an unbiased researcher (spoiler: does not exist), it’s an opinion.

                        BTW, static vs dynamic typing is the most hilarious “it just is, duh” response ever. That’s the pinnacle of flame war arguments on this topic.

                2. 10

                  A long time ago, Rust was actually much more similar to Go. Then the Rust developers decided that they didn’t need green threads and didn’t need a garbage collector because “a memory-safe programming language with no runtime!!!111*” is way cooler than “yet another Ocaml rehash, with this one weird type system trick!!!111”.

                  That and they’re both released by web companies, so web developers have inevitably heard of both.

                  * no additional runtime beyond what C requires, actually

                  1. 12

                    They were completely right, a memory-safe programming language with no runtime is in fact way cooler than yet another Ocaml rehash. In the specific sense that such a language genuinely didn’t exist and huge amounts of systems software were written in memory-unsafe C and C++ for lack of a better alternative.

                1. 23

                  I usually steal, I mean, get inspired by a theme on another site. I then manually edit the CSS and throw 99% out, and combine with CSS from other sites. It’s usually easy to get something that looks roughly like what you want, and very hard to get exactly what you want.

                  Of course, it won’t use the latest framework, but it’s javascript-free, artisanal, and people are usually surprised at how fast it loads.

                  1. 3

                    This is exactly what I did. I copied over a theme that vaguely looked like what I wanted, discarded the parts I didn’t need, then frobbed it until it looked good. (Few original LoC had remained by that time.) Some time later I rewrote the style from scratch using what I’ve learnt.

                    1. 2

                      This is what I did for https://bitemyapp.com/

                      It probably helps that I have some experience typesetting and like minimal/booky themes that focus on the type.

                      1. 2

                        I wouldn’t say that I’m bad at CSS, but I am pretty poor at coming up with originality. So, I end up pretty much doing something similar to you.

                        At the very least, I’ll get inspiration for design from other sites. Right now, I’m working on redoing my personal site as well (primarily my blog), and I’m really into Drew DeVault’s personal website. I also like Medium’s approach to focusing on the story content. I’ll probably end up doing an approach the combines them in some form.

                        I once had a colleague tell me that art is just regurgitation of other art.

                        1. 1

                          I like the site from crafting interpreters a lot, which is also hand-crafted (as it proudly declares in the footer). I checked out the source and it contains a comment along the lines “ is so beautiful it makes me want to cry”. Robert Nystrom seems like a nice guy.

                          Also, I really like the layout that stackedit.io generates.

                      1. 6

                        Rewriting my website to be more accessible and minimal.

                        Also I’ve been playing with neural networks in Clojure with Neanderthal. My desktop is pretty old, so it’s going to be a hassle to get the backends to work right though.
                        First I tried CUDA but realised I don’t have enough storage space. I figured it probably doesn’t support my old card (GeForce GT 630) anyway.
                        Then I tried OpenCL’s drivers for legacy Nvidia, but found out my GPU doesn’t support double precision.
                        I gave up and fell back on my CPU (AMD Phenom — no AVX) with Intel’s proprietary MKL library.
                        Besides these road bumps, it’s been going well. I’m playing with the idea of using deep learning to generate microtonal music.

                        1. 1

                          What do you train the network on? Would be fun to try something like King Gizzard’s Flying Microtonal Banana. Speaking of which (sorry for hijacking your thread) someone did in 8-bit:

                          https://www.youtube.com/watch?v=2J7yMp78_wY

                          (Though I like the 8-bit versions of their other albums more, they remind me more of 80ies/90ies games).

                          1. 2

                            Turkish makam music. (Which, coincidentally, significantly influenced Flying Microtonal Banana — ‘Sleep Drifter’ in particular was inspired by Âşık Veysel’s ‘Kara Toprak’.) So far, my data set is SymbTr, a compilation of makam music scores in machine readable format. There are several papers on identifying and classifying microtonal (specifically makam) music, but I haven’t seen any on producing new music, so I figured I might try and make something to fill that gap.

                            If you’re interested in microtonal music studies, I recommend works of Tolgahan Çoğulu. I was inspired to do this after he gave a talk in my alma mater.

                        1. 1

                          I’ve always used xclock for this task. I especially like the nonstandard catclock mode.

                          1. 3

                            Tangential to the article, I’ve read in many places that ncurses is a bad API (say the unix hater’s book), but what would be a good API for TUIs? Can someome point to me examples?

                            1. 3

                              I believe that following UH, no terminal UI could be good.

                              1. 1

                                what would be a good API for TUIs?

                                There aren’t any, I’m afraid, but there are options better than ncurses, such as slang and termbox.

                              1. 28

                                I really appreciate this. It’s refreshing to see people care about purchasing power in places besides Anglosphere and Western Europe.

                                In my country (Turkey) piracy was so common that there were hardly any companies importing video games and there were hundreds of shops dedicated to selling pirated copies of them. The reason is that nobody wanted to pay 10% of their monthly wage on a single video game.
                                15 years later, this practice is completely dead. Piracy is still common through bittorrent but it declined considerably after Steam, Spotify, Netflix et al began to offer actually affordable legal alternatives with regional pricing.

                                Once again, I want to say I appreciate websites that give me discount coupons based on my IP address, or vendors that ask me to pay for “a dinner for two in a mid-level restaurant based on your current location.”

                                PS: Another pain point regarding online payment is that PayPal is unavailable in Turkey, forcing me to use third-party transfer brokers for PayPal, extremely expensive international wire transfers or even mailing an envelope with banknotes in it.

                                1. 4

                                  I can sympathize with your comment.

                                  The situation is similar in Lebanon, regarding salaries, piracy, the now availability of cheap streaming services, and PayPal having blacklisted the country.
                                  We also have issues with unbearably slow connection, but that’s something else.

                                1. 31

                                  My position has essentially boiled down to “YAML is the worst config file format, except for all the other ones.”

                                  It gets pretty bad if your documents are large or if you need to collaborate (it’s possible to have a pretty good understanding of parts of YAML but that’s not always going to line up with what your collaborators understand).

                                  I keep wanting to say something along the lines of “oh, YAML is fine as long as you stick to a reasonable subset of it and avoid confusing constructs,” but I strongly believe that memory-unsafe languages like C/C++ should be abandoned for the same reason.

                                  JSON is unusable (no comments, easy to make mistakes) as a config file format. XML is incredibly annoying to read or write. TOML is much more complex than it appears… I wonder if the situation will improve at any point.

                                  1. 21

                                    I think TOML is better than YAML. Sure, it has the complex date stuff, but that has never caused big surprises for me (just small annoyances). The article seems to focus mostly on how TOML is not Python, which it indeed is not.

                                    1. 14

                                      It’s syntactically noisy.

                                      Human language is also syntactically noisy. It evolved that way for a reason: you can still recover the meaning even if some of the message was lost to inattention.

                                      I have a mixed feeling about TOML’s tables syntax. I would rather have explicit delimiters like curly braces. But, if the goal is to keep INI-like syntax, then it’s probably the best thing to do. The things I find really annoying is inline tables.

                                      As of user-typed values, I came to conclusion that everything that isn’t an array or a hash should just be treated as a string. If you take user input, you cannot just assume that the type is correct and need to check or convert it anyway, so why even bother having different types at the format level?

                                      Regardless, my experience with TOML has been better than with alternatives, despite its flaws.

                                      1. 6

                                        Human language is also syntactically noisy. It evolved that way for a reason: you can still recover the meaning even if some of the message was lost to inattention.

                                        I have a mixed feeling about TOML’s tables syntax. I would rather have explicit delimiters like curly braces. But, if the goal is to keep INI-like syntax, then it’s probably the best thing to do. The things I find really annoying is inline tables.

                                        It’s funny how the exact same ideas made me make the opposite decision. I came to the conclusion that “the pain has to be felt somewhere” and that the config files are not the worst place to feel it.

                                        I have mostly given up on different config formats and just default to one of the following three options:

                                        1. Write .ini or Java properties-file style config-files when I don’t need more.
                                        2. Write a dtd and XML when I need tree or dependency-like structures.
                                        3. Store the configuration in a few tables inside an RDBMS and drop an .ini-style config file with just connection settings and the name of the config tables when things get complex.

                                        As of user-typed values, I came to conclusion that everything that isn’t an array or a hash should just be treated as a string. If you take user input, you cannot just assume that the type is correct and need to check or convert it anyway, so why even bother having different types at the format level?

                                        I fully agree with this well.

                                      2. 23

                                        Dhall is looking really good! Some highlights from the website:

                                        • Dhall is a programmable configuration language that you can think of as: JSON + functions + types + imports
                                        • You can also automatically remove all indirection in any Dhall code, converting the file to a logic-free normal form for non-programmers to understand.
                                        • We take language security seriously so that your Dhall programs never fail, hang, crash, leak secrets, or compromise your system.
                                        • The language aims to support safely importing and evaluating untrusted Dhall code, even code authored by malicious users.
                                        • You can convert both ways between Dhall and JSON/YAML or read Dhall configuration files directly into a language that supports a native language binding.
                                        1. 8

                                          I don’t think the tooling should be underestimated, too. The dhall executable includes low-level plumbing tools (individual type checking, importing, normalization), a REPL, a code formatter, a code linter to help with language upgrades, and there’s full blown LSP integration. I enjoy writing Dhall so much that for new projects I’m taking a more traditional split between a core “engine”, and then pushing out the logic into Dhall - then compiling it at a load time into something the engine can work with. The last piece of the puzzle to me is probably bidirectional type inference.

                                          1. 2

                                            That looks beautiful! Can’t wait to give it a go on some future projects.

                                            1. 2

                                              Although the feature set is extensive, is it really necessary to have such complex functionality in a configuration language?

                                              1. 4

                                                It’s worth understanding what the complexity is. The abbreviated feature set is:

                                                • Static types
                                                • First class importing
                                                • Function abstraction

                                                Once I view it through this light, I find it easier to convince myself that these are necessary features.

                                                • Static types enforce a schema on configuration files. There is almost always a schema on configuration, as something is ultimately trying to pull information out of it. Having this schema reified into types means that other tooling can make use of the schema - e.g., the VS Code LSP can give me feedback as I edit configuration files to make sure they are valid. I can also do validation in my CI to make sure my config is actually going to be accepted at runtime. This is all a win.

                                                • Importing means that I’m not restricted to a single file. This gives me the advantage of being able to separate a configuration file into smaller files, which can help decompose a problem. It also means I can re-use bits of configuration without duplication - for example, maybe staging and production share a common configuration stanza - I can now factor that out into a separate file.

                                                • Function abstraction gives me a way to keep my configuration DRY. For example, if I’m configuring nginx and multiple virtual hosts all need the same proxy settings, I can write that once, and abstract out my intention with a function that builds a virtual host. This avoids configuration drift, where one part is left stale and the rest of the configuration drifts away.

                                                1. 1

                                                  That’s very interesting, I hadn’t thought of it like that. Do you mostly use Dhall itself as configuration file or do you use it to generate json/yaml configuration files?

                                              2. 1

                                                I finally need to implement Dhall evaluator in Erlang for my projects. I <3 ideas behind Dhall.

                                              3. 5

                                                I am not sure that there aren’t better options. I am probably biased as I work at Google, but I find Protocol Buffer syntax to be perfectly good, and the enforced schema is very handy. I work with Kubernetes as part of my job, and I regularly screw up the YAML or don’t really know what the YAML is so cutty-pasty from tutorials without actually understanding.

                                                1. 4

                                                  Using protobuf for config files sounds like a really strange idea, but I can’t find any arguments against it.
                                                  If it’s considered normal to use a serialisation format as human-readable config (XML, JSON, S-expressions etc), surely protobuf is fair game. (The idea of “compiled vs interpreted config file” is amusing though.)

                                                  1. 3

                                                    I have experience with using protobuf to communicate configuration-like information between processes and the schema that specifies the configurations, including (nested) structs/hashes and arrays, ended up really hacky. I forgot the details, but protobuf lacks one or more essential ingredients to nicely specify what we wanted it to specify. As soon as you give up and allow more dynamic messages, you’re of course back to having to check everything using custom code on both sides. If you do that, you may as well just go back to yaml. The enforced schema and multi language support makes it very convenient, but it’s no picnic.

                                                    1. 2

                                                      One issue here is that knowing how to interpret the config file’s bytes depends on having the protobuf definition it corresponds to available. (One could argue the same is true of any config file and what interprets it, but with human-readable formats it’s generally easier to glean the intention than with a packed binary structure.)

                                                      1. 2

                                                        At Google, at least 10 years ago, the protobuf text format was widely used as a config format. The binary format less so (but still done in some circumstances when the config file wouldn’t be modified by a person).

                                                        1. 3

                                                          TIL protobuf even had a text format. It sounds like it’s not interoperable between implementations/isn’t “fully portable”, and that proto3 has a JSON format that’s preferable.. but then we’re back to JSON.

                                                  2. 2

                                                    JSON can be validated with a schema (lots of tools support it, including VSCode), and it’s possible to insert comments in unused fields of the object, e.g. comment or $comment.

                                                    1. 17

                                                      and it’s possible to insert comments in unused fields of the object, e.g. comment or $comment.

                                                      I don’t like how this is essentially a hack, and not something designed into the spec.

                                                      1. 2

                                                        Those same tools (and often the system on the other end ingesting the configuration) often reject unknown fields, so this comment hack doesn’t really work.

                                                        1. 8

                                                          And not without good reason: if you don’t reject unknown fields it can be pretty difficult to catch misspellings of optional field names.

                                                          1. 2

                                                            I’ve also seen it harder to add new fields without rejecting unknown fields: you don’t know who’s using that field name for their own use and sending it to you (intentionally or otherwise).

                                                        2. 1

                                                          Yes, JSON can be validated by schema. But in my experience, JSON schema implementations are widely diverging and it’s easy to write schemas that just work in your particular parser.

                                                        3. 1

                                                          JSON is unusable (no comments, easy to make mistakes) as a config file format.

                                                          JSON5 fixes this problem without falling prey to the issues in the article: https://json5.org/

                                                          1. 2

                                                            Yeah, and then you lose the main advantage of json, which is how ubiquitous it is.

                                                            1. 1

                                                              In the context of a config format, this isn’t really an advantage, because only one piece of code will ever be parsing it. But this could be true in other contexts.

                                                              I typically find that in the places where YAML has been chosen over JSON, it’s usually for config formats where the ability to comment is crucial.

                                                        1. 5

                                                          Honestly, I think I like APL-style J better than APL itself. It looks much cleaner.

                                                          1. 1

                                                            What is the advantage to a workflow like this, vs running tmux on the host?

                                                            1. 2

                                                              It’s hard to talk in terms of advantages; they are just different. One is very dependent on keybindings; the other can be invoked, say, programatically. But the choice for one or another is down to personal taste.

                                                              1. 1

                                                                The programatic approach as a differentiator makes sense. Tmux is mostly habit for me, having memorized the basic keybindings.

                                                              2. 1

                                                                I like dtach/abduco because my terminal emulator already does everything tmux/screen does, all I need is detachable processes, especially on remote connections. Although I can’t help but wonder why it’s so difficult to un-disown (adopt?) a job on Unix. I remember using reptyr to lasso a nohup job gone wild in production.

                                                              1. 1

                                                                You should know that most of these utilities are heavily configurable through Xresources. (Although documentation is scarce and misconfigured xutils are prone to segfault.)
                                                                For instance, I took the liberty to configure xcalc’s RPN mode for eye-candy.

                                                                1. 1

                                                                  I would like to mention Rackjure here. It ports plenty of Clojure’s syntactic conveniences to Racket.

                                                                  ;; (dict-ref my-dict key)
                                                                  (my-dict key)
                                                                  (key my-dict)
                                                                  
                                                                  ;; (dict-set my-dict key val)
                                                                  (my-dict key val)
                                                                  
                                                                  ;; (dict-ref (dict-ref (dict-ref dict 'a) 'b) 'c)
                                                                  (~> dict 'a 'b 'c)
                                                                  
                                                                  ;; '((key . "value") (key1 . ((key . "value") (key1 . "value1"))))
                                                                  {'key "value"
                                                                   'key1 {'key "value"
                                                                          'key1 "value1"}}
                                                                  
                                                                  1. 8

                                                                    the infinite backlog encourages a culture of catching up rather than setting the expectation that conversations are ephemeral

                                                                    This was a very interesting point I hadn’t even considered before!

                                                                    1. 7

                                                                      An alternative, however, is the option to display to newly joined users the last, say, 25 lines of history in the channel. Many users may think a channel is dead, or struggle to understand the context of the current conversation on join, and this is something that could help alleviate it.

                                                                      It’s something we’re considering, and would likely be opt-in by channel operators via a channel mode - with the added bonus of this meaning that users who are sensitive to such backlog can be warned by their client when it receives the channel modes.

                                                                      1. 2

                                                                        An alternative, however, is the option to display to newly joined users the last, say, 25 lines of history in the channel. Many users may think a channel is dead, or struggle to understand the context of the current conversation on join, and this is something that could help alleviate it.

                                                                        This is how XMPP has worked for years, and is the main reason I chose it over IRC when I was first getting into these things back in the day.

                                                                      2. 4

                                                                        This was a very interesting point I hadn’t even considered before!

                                                                        One interesting thing: XMPP supports “infinite backlog” but some rooms (such as prosody) explicitly do not enable it for the same reason - to keep the discussion ephemeral.

                                                                        1. 3

                                                                          Only with some recent draft extensions does XMPP support infinite backlog. By default it uses a finite backlog to get you some context when you join – which is of course and amazing killer feature by itself and the main reason I originally switched to XMPP.

                                                                          1. 4

                                                                            Only with some recent draft extensions does XMPP support infinite backlog.

                                                                            I know that in XMPP timeline it’s “recent” but I think it’s good to put it into perspective: MAM was initially released in 2012. Prosody module implementing that is 7 years old.

                                                                            1. 1

                                                                              Just as context for people reading the thread and wondering, Prosody’s mod_mam (backlog module) expires messages after one week by default. You can configure it for months, years, or forever, but honestly, one week is a pretty good default.

                                                                          2. 1

                                                                            I don’t think ephemerality is as common as he makes it out to be, but putting the onus of logging on individual users is itself a big deal & desirable. Social norms on irc are that everybody keeps full logs & nobody ever logs off (and bigger channels tend to have logger bots that don’t have anybody on ignore, often keeping public logs), so arbitrary scrollback is generally available if you ask for it.

                                                                            The difference is that, because everybody keeps their own logs, authority with regard to recording history is also distributed: Slack, Inc can rewrite the history of any conversation on Slack any way they like, but it’s much harder for somebody to hack into the machines of everybody on an IRC channel and falsify their logs.

                                                                            The logs we keep on IRC are records of what we see (or what we would see, if we weren’t AFK), reflecting our ignorelist and such, & the absence of a single canonical record is philosophically important.

                                                                            1. 1

                                                                              This is the reason I never really got into web BBSes as general-purpose chatting platforms. (Unlike domain-specific news aggregators like Lobsters, where we’re only commenting on articles.) I love that I can just drop in and drop out any time I like with IRC.

                                                                            1. 8

                                                                              Nice! I’m considering moving away from the Mastodon instance I’m in to a self-hosted Pleroma instance. I like that the frontend can be decoupled from the backend. Theoretically, I should be able to use it exclusively through third-party clients and the gopher interface, if I understand it correctly.

                                                                              1. 2

                                                                                What would happen if someone would try to open a link “from” your instance though if you have no frontend?

                                                                                1. 2

                                                                                  Probably get the json version of the post.

                                                                                  1. 1

                                                                                    Hmm, that’s a good point. I wanted to avoid hosting a web server but I guess there’s nothing to replace that.

                                                                                1. 6

                                                                                  Racket’s is the nicest GUI library I’ve ever had the pleasure of using.

                                                                                  1. 4

                                                                                    I like how convenient it is but I’ve always found the object-based approach a bit awkward. An elm architecture-inspired interface would be interesting and more idiomatic, but I can’t find any library that implements it.

                                                                                    Maybe it’s finally time to learn syntax-parse

                                                                                    1. 2

                                                                                      That’s an interesting idea. racket/gui was inspired by Smalltalk’s OO approach to GUI: traditional message passing style, encouraging you to augment and override (or overment and augride) existing classes to specialise them for your use case. Still, I’d like to see more applications of the Elm-style declarative GUIs, myself.

                                                                                      Do you know of other languages/frameworks using it?

                                                                                      1. 2

                                                                                        Elm was the first GUI “framework” I learned so I guess it’s had a big impact on what I’ve come to expect from these things.

                                                                                        As for other implementations of TEA, the only major one I know if is Elmish for F#, which is used by Fable for browser GUIs and Fabulous for mobile.

                                                                                      2. 2

                                                                                        It’s dated and awkward, and the class system isn’t great. (Modern Racket tends to prefer the interface system instead of classes.) But it’s still dramatically better than any alternative for building conventional GUIs I’ve ever seen.

                                                                                      3. 2

                                                                                        Is it really? It looks to me that it has many shortcomings, like e.g. it lacks tree widget (available externally) or a way to customize model of list.

                                                                                        1. 1

                                                                                          You can do any customisation you want using the class system.

                                                                                          1. 2

                                                                                            I’m not sure how to do that – care to explain?

                                                                                            1. 1

                                                                                              Well, briefly, every send message you see in that list-box% manual page is override-able within a subclass, so you can just substitute a new class with whatever customisations you like (there are very few private or un-overridable behaviours). The class system is very flexible and you can do a lot with it that you can’t in many other languages.

                                                                                              I researched how it works after sending my response (of course) and it uses the platform widget toolkit, so there may be some platform-specific things you can’t directly change.

                                                                                              1. 1

                                                                                                Well, I know that I can derive and override how my class responds to messages. The question is which messages handling should I change to change how entries are stored (and which I can leave as-is). It’s not clear (at least to me) from the code nor from documentation. Furthermore by using subclassing and not agregation/delegation with separate model it makes it hard to reuse same model for different widgets, right?

                                                                                                So I’m not sure that your original claim “Racket’s is the nicest GUI library I’ve ever had the pleasure of using” is correct, if you used cocoa/uikit or qt.

                                                                                                1. 1

                                                                                                  In that case it’s just a matter of using append, get-data, and set-data or just keeping an association of entries alongside - what use case do you have for changing exactly how entries are stored? (Why does this particular point bring into question the veracity of my opinion on the matter?)

                                                                                                  It’s not forcing you to use inheritance; that was just an example. You can substitute any object for any other as long as it implements the right widget interfaces. Classes are first-class objects so you can pass them around between functions. It’s up to you to organise it nicely.

                                                                                        2. 1

                                                                                          agreed, it’s very well designed and a joy to use

                                                                                        1. 6

                                                                                          As much as I would like for this to be true, there have been many claims of decipherment, and all have pretty strong counterarguments. I’m curious to see the responses from the community.

                                                                                          1. 6

                                                                                            Especially claiming that it’s written in an otherwise completely unattested Romance language in a unique orthography that derives from Latin alphabet is… dubious at best. I’d love to be proven wrong, of course.

                                                                                            My pet theory is that it’s a written entirely in some scribe’s own custom shorthand, perhaps purposefully obfuscated. Arbitrary use of abbreviations (and their numerous variant forms) would also make it really difficult to decipher in that case.

                                                                                            1. 3

                                                                                              A completely unattested Romance language that was also apparently a lingua franca of southern Europe, but everyone just sort of…forgot.

                                                                                              1. 2

                                                                                                Something something Albigensian Crusade and gnosticism.

                                                                                                1. 2

                                                                                                  To be fair, the Gnostics were about keeping their stuff secret…

                                                                                          1. 1

                                                                                            This seems like a blurb that reiterates the myth that garbage collected languages are inherently bad for performance, wrapped around a paper that reinvents hardware-assisted garbage collection, an idea that existed since ’80s.

                                                                                            1. 16

                                                                                              The fact that an idea has existed since the ’80s should not be grounds for dismissal.

                                                                                              From the article, regarding prior work:

                                                                                              While the idea of a hardware-assisted GC is not new [5]–[8], none of these approaches have been widely adopted. We believe there are three reasons:

                                                                                              1. Moore’s Law: Most work on hardware-assisted GC was done in the 1990s and 2000s when Moore’s Law meant that next-generation general-purpose processors would typically outperform specialized chips for lan- guages such as Java [9], even on the workloads they were designed for. This gave a substantial edge to non-specialized processors. However, with the end of Moore’s Law, there is now a renewed interest in accelerators for common workloads.
                                                                                              2. Server Setting: The workloads that would have benefitted the most from hardware-assisted garbage collection were server workloads with large heaps. These workloads typically run in data centers, which are cost-sensitive and, for a long time, were built from commodity components. This approach is changing, with an increasing amount of custom hardware in data centers, including custom silicon (such as Google’s Tensor Processing Unit [10]).
                                                                                              3. Invasiveness: Most hardware-assisted GC designs were invasive and required re-architecting the memory system [8], [11]. However, modern accelerators (such as those in mobile SoCs) are typically integrated as memory-mapped devices, without invasive changes.
                                                                                              1. 3

                                                                                                You’re right, I didn’t mean to dismiss the paper, just the article that makes it sound like a novel idea. On the contrary, I’m glad that HWAGC is getting attention at this age.

                                                                                              2. 3

                                                                                                Is it a myth? There seems to be a trend here that the non-garbage-collected languages are faster: https://benchmarksgame-team.pages.debian.net/benchmarksgame/which-programs-are-fast.html

                                                                                                1. 5

                                                                                                  It’s got a bit of truth in it, in that most garbage collectors commonly used are mediocre at best and our modern processors are optimised towards dynamic allocation.

                                                                                                  jwz has a good summary of the GC ordeal.

                                                                                                  1. 3

                                                                                                    I don’t understand your citation. I have read that article, but what does it have to do with dynamic allocation?

                                                                                                    Although I generally like jwz’s writing, I’m not convinced by the second citation either, because it’s over 20 years old and basically saying that at that time the only good GCs were in Lisp implementations. Something that surveys the current state of the art would be more convincing.

                                                                                                    Personally I think GC’s are invaluable, but you can always do better by applying some application-specific knowledge to the problem of deallocation. There are also many common applications and common styles of programming that create large amounts of (arguably unnecessary) garbage.

                                                                                                  2. 8

                                                                                                    Garbage collected environments can—and often do—have higher overall throughout than manually managed memory environments. It’s the classic batch processing trade off, if you do a lot of work at once it’s more efficient, but it won’t have the best latency. In memory management terms, that means memory won’t be freed right away. So GCs need some memory overhead to continue allocating before they perform the next batch free.

                                                                                                    This is one of the reasons iPhones circa 2014 ran smoothly with 1GB RAM, but flagship Androids had 2-3GB. Nowadays both have 4GB, as the RAM needed to process input from high resolution cameras dwarfs the memory concerns of most applications on either phone.

                                                                                                    Note the latency from batching frees (i.e. garbage collection) doesn’t refer to GC pause time. So called “stop the world” collection phases exist only in mediocre GC systems, like Java’s, because they’re relatively easy to implement. ZGC looks promising, 10+ year old GC technology is finally making it to the JVM!

                                                                                                    C/C++ also make it easier to control memory layout and locality, which massively improves performance in some cases. But as jwz points out in the post linked by @erkin, GC languages could provide similar tools to control allocations. No mainstream GC language does, probably since the industry already turns to C/C++ for that by default. Unity comes close, they made a compiler for a C# subset they call HPC#, which allows allocation and vectorization control. And I think D has some features for doing this kind of thing, but I wouldn’t call D mainstream.

                                                                                                    1. 5

                                                                                                      Chicken Scheme, uses stack for the ‘minor’ garbage collection.

                                                                                                      https://www.more-magic.net/posts/internals-gc.html “… This minor GC is where the novelty lies: objects are allocated on the stack. … “

                                                                                                      Stack memory, by itself is typically a contiguous block (an well optimized part of virtual memory). I think in general, the trend in GC is to have ‘categories’ of memory allocation models, where the optimizations is done per category. The determination of categories is done at compile time, with a possibility of a memory allocation to graduate (or move) from one type/category to another (not using ‘categories’ in algebraic sense here).

                                                                                                      1. 1

                                                                                                        I’m not sure I buy that argument, because GC inherently does more work than manual memory management. It has to walk the entire heap (or parts of it for generational GC), and that’s expensive. You don’t need to do that when manually managing memory. Huge heaps are still an “unsolved problem” in GC world, but they aren’t in manual world.

                                                                                                        I’m a fan of GC, but I think the problem is that you can only compare the two strategies with identical/similar big applications, because that’s where GC really shines. But such pairs of applications don’t exist AFAICT.

                                                                                                        1. 4

                                                                                                          It has to walk the entire heap

                                                                                                          No. There are many more interesting strategies than simple generational heaps.

                                                                                                          You don’t need to do that when manually managing memory

                                                                                                          Instead you just call malloc and free all the time, functions that lock, can contend with other threads, and needs to manipulate data structures. Compare to alloc in a GC world: atomic increment of arena pointer.

                                                                                                          Huge heaps are still an “unsolved problem” in GC world

                                                                                                          Azul’s GC manages hundreds of GBs without any global pauses. Huge enough for you? ZGC uses similar strategies, copying many of those ideas that have been around since 2008 (to my knowledge, likely earlier).

                                                                                                          Unimplemented in common open source languages != unsolved.

                                                                                                          But such pairs of applications don’t exist AFAICT

                                                                                                          Compare IntelliJ and Qt Creator. Only it’s not a fair comparison, since IntelliJ runs on Oracle / OpenJDK Java, and that JVM still doesn’t have any good garbage collectors (ZGC is still in development / who knows if it will ever actually ship).

                                                                                                          P.S. I love all the work you’re doing on Oil, and your blog posts are fantastic!

                                                                                                          1. 4

                                                                                                            Eh your reply reads very defensively, like I’m attacking GC. In fact most of my posts on this thread are arguing for GC for lots of applications, and I plan to use it for Oil. (Thanks for the compliment on the blog posts. I’ve been on a hiatus trying to polish it up for general use!)

                                                                                                            I’m just pointing out that GC has to do work proportional to every objects on the heap. What are the other strategies that don’t need to do this? Whether the GC is generational, incremental, or both, you still have to periodically do some work for every single heap object. I think the article points out that incremental GC increases the overhead in exchange for reducing pauses, and I saw a recent retrospective on the new Lua GC where they ran into that same issue in practice.

                                                                                                            (In Go, I think it’s a bit worse than that, because Go allows pointers to the middle of objects. Although Go also has escape analysis, so it’s probably a good engineering tradeoff, like many things Go.)

                                                                                                            I also think you’re comparing the most naive manual memory management with the most sophisticated GC. Allocators in the 90’s weren’t very aware of threads but now they certainly are (tcmalloc, jemalloc, etc.)

                                                                                                            Many (most?) large C applications use some kind of arena allocation for at least some of their data structures. For example, the Python interpreter does for it’s parse tree. It’s not just malloc/free everywhere, which is indeed slow.

                                                                                                            Anyway, my point is that the batch processing argument tells some of the story, but is missing big parts of it. It’s not convincing to me in general, despite my own preference for GC.

                                                                                                            Unsurprisingly, the comparison is very complex and very application-specific. It’s hard to make general arguments without respect to an application, but if you want to, you can also make them against GC because it fundamentally does more work!

                                                                                                            1. 5

                                                                                                              I don’t think you’re attacking GC, but I think you’re wrong about performance. Comparing jemalloc to G1GC, and similar generational collectors in common dynamic languages, you’re spot on. Generational collection shines in web application servers, which allocate loads of young garbage and throw it all away at the end of a request. But for long lived applications like IntelliJ it’s not so hot. Last I checked (which was a while ago) IntelliJ’s launcher forced the concurrent mark and sweep GC. Stuff like Cassandra and Spark are really poorly served by either of those GCs, since neither prevents long pauses when the heap is really large.

                                                                                                              Batching pretty much does cover the argument. Assume you have a page of memory with dozens of small object allocations. Which is faster, individually calling free on 90% of them, or doing a GC scan that wastes work on 10% of them? As long as you can densely pack allocations, GC does very well.

                                                                                                              Arenas are certainly a big win, but in many ways a page in the young generation is like an arena. Yes, manual memory management will always win if you perform all of your allocations in arenas, freeing them in groups as the application allows. Commercial databases do so as much as possible. gRPC supports per-request arenas for request and response protos, a clever answer to the young generation advantage for short stateless request / response cycles.

                                                                                                              I might be wrong, but I don’t think you’re considering that GCs can use MMU trickery just as much as anyone else. Suppose instead of periodically scanning the old generation, you occasionally set 2mb hugeages of old objects as no read no write. If it’s accessed, catch the segfault, enable the page again, and restart the access. If it’s not accessed after a while, scan it for GC. Having access statistics gives you a lot of extra information.

                                                                                                              Now imagine that instead of the random musings of some internet commenters, you have really clever people working full time on doing this sort of thing. There’s a whole world of complex strategies enabled by taking advantage of the memory virtualization meant to emulate a PDP-11 for naive programs. Normal incremental collection has more overhead because the GC has to redo more work. ZGC avoids lots of this because it maps 4 separate extents of virtual memory over the same single contiguous extent of physical RAM, and the GC swaps out pointers it’s looking at for different virtual addresses to the same physical address. Trap handlers then patch up access to objects the GC is moving.

                                                                                                              The whole “GC is linear wrt total heap size” conventional wisdom is a myth, perpetuated by mainstream GCs not doing any better.

                                                                                                              [GC] fundamentally does more work!

                                                                                                              It’s still a win for a GC if executing more instructions results in fewer memory accesses. CPUs are wicked fast, memory is slow. Back when I worked on a commercial database engine, loads of our code paths treated heap memory like most people treat disk.

                                                                                                              1. 1

                                                                                                                The whole “GC is linear wrt total heap size” conventional wisdom is a myth, perpetuated by mainstream GCs not doing any better.

                                                                                                                Which GCs avoid doing work linear in the # objects on the heap? Are you saying that ZGC and Azul avoid this?

                                                                                                                This isn’t something I’m familiar with, and would be interested in citations.

                                                                                                                I still think you’re comparing the most advanced possible GC with the status quo in manual memory management, or more likely lots of old C and C++ code. (There is apparently still work on manual memory management like [1].)

                                                                                                                The status quo in GC is basically what JVM, .NET and various dynamic language VMs have.

                                                                                                                But I’m interested to hear more about the advanced GCs. How do they avoid doing work for every object?

                                                                                                                The permanent generation is something I’ve seen in a few designs, and the idea makes sense, although I don’t know the details. I don’t think it’s free, because whenever you have generations, you have to solve the problem of pointers across them, e.g. with write barriers. Write barriers incur a cost that doesn’t exist in manual management schemes. How much I don’t know, but it’s not zero.

                                                                                                                I’d rather see concrete use cases and measurements, but if we’re making general non-quantitative arguments, there’s another one against GC.

                                                                                                                [1] https://news.ycombinator.com/item?id=19182779


                                                                                                                EDIT: To see another reason why the batch argument doesn’t work, consider Rust. Roughly speaking, the Rust compiler does static analysis and inserts deallocation at the “right” points.

                                                                                                                It does not “batch” the deallocation or allocation, as far as I know. Are you saying that Rust programs are slower than the equivalent garbage collected programs because of that? Maybe they would be if marking the heap were free? But it’s not free.

                                                                                                                Anyway, my goal isn’t to get into a long abstract argument. I’d be more interested in hearing about GC strategies to minimize the total overhead of scanning the heap.

                                                                                                                1. 2

                                                                                                                  Which GCs avoid doing work linear in the # objects on the heap?

                                                                                                                  There are lots of ways to skip work. As you said, the Go GC handles pointers to the middle of objects. Using similar principles a GC can handle pointers to a page of objects, and free the whole page together. You also mentioned Go’s escape analysis at compile time. Do the same escape analysis and count the number of escaped objects for an entire region of memory, dump it when it hits zero. Mark regions that contain external references: if a page never had objects with pointer fields, or if all the pointer fields reference within the page, why scan its pointers before releasing the memory?

                                                                                                                  I still think you’re comparing the most advanced possible GC with the status quo in manual memory management, […] The status quo in GC is basically what JVM, .NET and various dynamic language VMs have.

                                                                                                                  I’m refuting your claims that “GC inherently does more work than manual memory management” and that large heaps are an “unsolved problem.” Large heaps aren’t unsolved. GC doesn’t “inherently” do more work. And regardless, number of operations doesn’t equal efficiency.

                                                                                                                  It does not “batch” the deallocation or allocation, as far as I know. Are you saying that Rust programs are slower than the equivalent garbage collected programs because of that?

                                                                                                                  Of course Rust programs aren’t always slower. But garbaged collected programs aren’t always slower either, that’s my entire point here.

                                                                                                            2. 3

                                                                                                              Instead you just call malloc and free all the time, functions that lock, can contend with other threads, and needs to manipulate data structures. Compare to alloc in a GC world: atomic increment of arena pointer.

                                                                                                              I’m not an expert in GC theory but this looks like a bold statement to me. I think that efficient allocation schemes in multithreaded environment are both doable and rather common, and I think that memory allocation in most GC implementations is far more expensive than a single atomic pointer increment. I totally understand that in some cases, state-of-the-art GC can match the performance of manual memory allocation, but I have yet to see a proof that GC is always better than no GC.

                                                                                                              1. 4

                                                                                                                I’m not saying GC is always better, just that it can be, and often is. Plenty of C/C++ code does ordinary per-object malloc and free, especially C++ when virtual classes come into play. For those applications I claim a sufficiently advanced GC would have higher throughput.

                                                                                                                As I discussed in my other comment, you can optimize manual memory code to only allocate into arenas, and free arenas at exactly the right time. Having domain knowledge about when an arena can be freed will certainly be better than the GC guessing and checking.

                                                                                                                allocation in most GC implementations is far more expensive than a single atomic pointer increment

                                                                                                                Correct. But I also claim most mainstream GC implementations are mediocre. If the environment doesn’t support object relocation by the GC, the allocator needs to fill gaps in a fragmented heap. When the GC can compact a fragmented heap and release large chunks of contiguous memory, the allocator barely has to do anything.

                                                                                                        2. 4

                                                                                                          The problem is that such benchmarks usually compare hand-tuned, optimized-to-death code examples, which are simply not representative of the way code is written in the wild.

                                                                                                          If you have unlimited time to tune and optimize, the fewer amenities the language/runtime has, the better, so non-GC-languages will always have an edge in this scenario.

                                                                                                          BUT: 99.9% of the time, this is not the scenario anyone is operating under.

                                                                                                          1. 2

                                                                                                            I don’t think it’s a myth either – the issue is more complex than than that. It depends a lot on the application, etc.

                                                                                                            But I also don’t think the benchmarksgame is a strong indication either way, because those programs are all 10 or 100 lines long. You can always do better on small programs without garbage collection – i.e. by applying some problem-specific knowledge to the code.

                                                                                                            Large applications are where garbage collection shines, because I think the number/probability of memory bugs like use-after-free or memory leaks scales nonlinearly with application size. But that’s exactly where it’s hard to do any meaningful comparison, because we don’t have 2 independent implementations of large applications.

                                                                                                            My suspicion is that GC / manual memory management isn’t really a useful variable to separate good and bad performance. It’s kind of like how the language doesn’t have too much bearing on how good an application is. There are good and bad apps in C, in Java, in Python, in Lisp, etc. The difference between good and bad apps is very large, and whether they use garbage collection probably isn’t the most salient factor. You can be very sloppy about memory with GC, or you can be disciplined.


                                                                                                            Also, FWIW I have been making a list of C and C++ programs that use some kind of garbage collection / automatic memory management. So far I have

                                                                                                            If anyone knows of others, I’m interested! I’ve been thinking about garbage collection in Oil’s implementation (both for its own structures and user structures, but more of the former right now.)

                                                                                                            1. 3

                                                                                                              You are incorrect about that GCC link. One, it links to a very old version of the docs, ore modern docs are here: https://gcc.gnu.org/onlinedocs/gcc-9.1.0/gcc/Garbage-Collection.html Two, it IS a feature for the programs it compiles, using the Objective C runtime.

                                                                                                              1. 2

                                                                                                                Hm it looks like I have the wrong link, but GCC does do some garbage collection?

                                                                                                                https://dmalcolm.fedorapeople.org/gcc/newbies-guide/memory-management.html

                                                                                                                I’ve never worked on GCC, but I think I read a comment on Hacker News that said it used GC which led me to Google for it.


                                                                                                                Yeah I just checked the source and this looks like it’s in the compiler itself and not the runtime library:

                                                                                                                ~/src/languages/gcc-9.1.0/gcc$ wc -l ggc*
                                                                                                                  1018 ggc-common.c
                                                                                                                   322 ggc.h
                                                                                                                   118 ggc-internal.h
                                                                                                                    74 ggc-none.c
                                                                                                                  2647 ggc-page.c
                                                                                                                   525 ggc-tests.c
                                                                                                                  4704 total
                                                                                                                

                                                                                                                This garbage-collecting allocator allocates objects on one of a set of pages. Each page can allocate objects of a single size only; available sizes are powers of two starting at four bytes. The size of an allocation request is rounded up to the next power of two (`order’), and satisfied from the appropriate page.

                                                                                                                And it looks like it’s used for a lot of core data structures:

                                                                                                                tree-phinodes.c:      phi = static_cast <gphi *> (ggc_internal_alloc (size));
                                                                                                                tree-ssanames.c:      ri = static_cast<range_info_def *> (ggc_internal_alloc (size));
                                                                                                                tree-ssanames.c:  new_range_info = static_cast<range_info_def *> (ggc_internal_alloc (size));
                                                                                                                tree-ssa-operands.c:      ptr = (ssa_operand_memory_d *) ggc_internal_alloc
                                                                                                                

                                                                                                                This isn’t surprising to me because I have found memory management for hueg tree/graph data structures in compilers to be a big pain in the butt, and just this subdir of gcc is 1M+ lines of code. You really do want a garbage collector for that class of problems. However Clang/LLVM appears to use the C++ “ownership” style without GC. It seems very verbose though.

                                                                                                              2. 3

                                                                                                                If anyone knows of others,

                                                                                                                Some game engines have their own garbage collection. I did not use any myself, but check https://wiki.unrealengine.com/Garbage_Collection_%26_Dynamic_Memory_Allocation

                                                                                                                probably other C++ game engines offer something in this area too.

                                                                                                                1. 2

                                                                                                                  Thanks that’s a great example! I found this link to be pretty good:

                                                                                                                  https://wiki.unrealengine.com/Garbage_Collection_Overview

                                                                                                                  I think the commonality is that games have huge graph data structures, just like compilers. On the other hand, scientific programs have more flat arrays. And web servers written in C++ have request-level parallelism / isolation, so memory management can be simpler. So yeah it depends on the app, and for certain apps garbage collection is a huge win, even in C++.

                                                                                                          1. 13

                                                                                                            The behavior this allows for (each window taking over its parent’s window, rather than spawning a new window) has been something I wanted to demonstrate on Wayland for a very long time. This is a good demonstration of how Wayland’s fundamentally different and conservative design allows for some interesting use-cases which aren’t possible at all on X11.

                                                                                                            It’s not entirely impossible. I hacked together something with dwm to allow a terminals to swallow graphical programs: https://dwm.suckless.org/patches/swallow/

                                                                                                            It abuses the X Resource Extension for fun and profit.

                                                                                                            1. 6

                                                                                                              You can achieve the same effect and separation with Xorg, even on the lower levels (3d acceleration). Few distributions enable it by default, but build with ‘Xephyr’ and spawn that instead of Xserver through your outer WM (so dwm in this case) with a kiosk-like WM (ratpoison) that fullscreens the latest connected client. Unlink, randomise -display “number”, preload-interpose or otherwise namespace-out the socket path that DISPLAY=:xx would normally resolve to and there is your client isolation as well.

                                                                                                              1. 4

                                                                                                                Wow, very impressive. I was wondering if this was feasible with X11 after seeing Arcan do it. It seems much more useable than 9wm.

                                                                                                                1. 2

                                                                                                                  Floodgap’s web proxy uses Windows-1252 encoding by default for, what I presume to be, compatibility reasons. Most clients default to UTF-8, however.

                                                                                                                  1. 2

                                                                                                                    In my gopher clients it seems to work as intended: https://i.postimg.cc/dVq5pDVj/Screenshot-20190421-160850-Pocket-Gopher.png and https://i.postimg.cc/C1jDwHvB/Screenshot-20190421-161321-Diggie-Dog.png Lynx on the client as well. Have you tried a Gopher client?

                                                                                                                    The browser expects an encoding and I’m not sure how the floodgap proxy handles that for plain text files that don’t specify one.

                                                                                                                    1. 1

                                                                                                                      Interesting, so gopher clients assume all content is UTF-8 (or whatever encoding you’ve used here)?

                                                                                                                      1. 2

                                                                                                                        I guess so? The python script explicitly does UTF-8 and the clients I test with seem to as well. For the filenames I do strip out all except a-zA-Z.

                                                                                                                        1. 1

                                                                                                                          Why not allow numbers? Right now there are names like Queen_Attends_Easter_Service_on___rd_Birthday.

                                                                                                                          1. 1

                                                                                                                            No specific reason. I changed the regex so numbers are allowed now.

                                                                                                                        2. 1

                                                                                                                          The one I wrote assume UTF-8 as I found more pages using that than ISO-8859-1 or Windows-1252. It’s also pretty clear that UTF-8 is the way forward for encoding.

                                                                                                                          1. 1

                                                                                                                            Hey you’re behind the Boston diaries, but rumor goes, not even from, in or near Boston! I like reading your site and Gopherhole

                                                                                                                            1. 1

                                                                                                                              Thanks. There is a story behind the name.

                                                                                                                              1. 1

                                                                                                                                I’m amused to see a number of people I’ve started following on gopher I’ve already seen on Lobste.rs or Mastodon and didn’t know it.

                                                                                                                      1. 4

                                                                                                                        It is great to see more services supporting dvcs other than git. Can someone who prefers to use Mercurial share some.of their experiences wirh it and what makes it better for them? Not trying to start a flamewar, just being curious about it

                                                                                                                        1. 17

                                                                                                                          I’ll just C&P and update the last time I wrote what was so awesome about hg:

                                                                                                                          Here’s a list of Mercurial features that I think are really cool:

                                                                                                                          • Revsets – a domain-specific language for querying your commits
                                                                                                                          • Filesets – a domain-specific language for selecting files
                                                                                                                          • Templates – a domain-specific language for altering the output of almost every command. Putting these together you can do things like this.
                                                                                                                          • Evolution – a distributed and safe way to share rewrites (think automatically recovering from upstream rebase without any git reset –hard and no git push –force).
                                                                                                                          • Absorb – automatically amends an entire stack of WIP commits at once by picking the right diffs from your working directory based on which commits’ contexts they fit best.
                                                                                                                          • Curses interface for hunk-picking – a unified interface for splitting diffs for any purpose: whether to revert working-directory changes, write a new commit, uncommit parts of a commit, or amend a commit with more diffs. Just add –interactive to any of those commands and start picking hunks!
                                                                                                                          • Curses interface for redrafting your commits – think git rebase -i with a curses interface (this is quite new, in the lastest relase; I’ve made a few UI tweaks to it that should show up in the next release)
                                                                                                                          • A fairly rich built-in web interface – hg serve and point your browser to http://localhost:8000 and you’re good to go.
                                                                                                                          • Lots of support for monorepos – indeed, this is the main reason that Google, Facebook, and Mozilla are all pouring work into hg and are using it.
                                                                                                                          • A consistent UI – this one is more subjective but often-touted feature of Mercurial. If a command accepts a revision/hash/tag/bookmark; it always uses the -r/–rev flag for it (and you can also always use a revset for any command that accepts a revision). If a command allows hunk selection, it always uses the -i/–interactive flag for it. The help for every command fits in about a screenful; no never-ending man pages full of arcane flags and explanations you don’t understand nor care about.

                                                                                                                          Give it a try! Mercurial is neat!

                                                                                                                          1. 4

                                                                                                                            For 90% of your workflow, there’s no big difference. The other 10% can be painful to get used to. For instance, Mercurial does not have Git’s concepts of “staging area” and “tracking branch”, which simplifies things.

                                                                                                                            I’m more comfortable with Git purely because I’m used to it but I’ve recently taken a liking for Mercurial. It feels sturdier and more consistent.

                                                                                                                            Edit: I forgot to mention that Mercurial is very modular. Not only are there various extensions to simplify your workflow, you can write your own extensions to suit the needs of your project.

                                                                                                                            1. 2

                                                                                                                              mostly a sane UI/UX. But also it’s easily extensible with python, and it has neat things like revsets.

                                                                                                                              1. 2

                                                                                                                                I wrote an article about it, to copy/paste some relevant parts:

                                                                                                                                My chief gripe with git is its user interface. With ‘user interface’ I mean the commandline user interface. Let me show by example:

                                                                                                                                $ git help commit | wc -l
                                                                                                                                506
                                                                                                                                $ hg help commit | wc -l
                                                                                                                                59
                                                                                                                                $ hg help commit -v | wc -l
                                                                                                                                96
                                                                                                                                

                                                                                                                                Currently my git installation has 169 “core” commands:

                                                                                                                                $ find /usr/lib/git-core -maxdepth 1 -type f -executable | wc -l
                                                                                                                                169
                                                                                                                                

                                                                                                                                Compare this to mercurial’s 50 built-in commands (from hg help), a number which has remained constant since I wrote this article (whereas git had 160 commands when I first wrote this 2 years ago).

                                                                                                                                “But git commit has so many more features”, well, perhaps. But how many of those are actually used by most users? Mercurial can be easily extended, and most “missing” features are implemented in extensions (many are shipped with the base mercurial install). For better or worse, git is bloatware, and like most bloatware it comes with a [notoriously difficult to understand manual][git-man].

                                                                                                                                Mercurial has a manual and user interface that I understand without too much effort, and this is by far the biggest reason I much prefer mercurial over git. If I need to know something from mercurial I can just read the documentation and go ‘ah’, with git … not so much. There’s a reason so many of the [top Stack Overflow questions][so-top] are about git.

                                                                                                                                Some might say (and indeed, have said) that I’m lazy and just need to spend more time and effort learning git. Well, perhaps, but the thing is, git doesn’t really do anything. Unlike a programming language or API I can’t really build anything with it. It’s merely logistics to facilitate the actual building of stuff.
                                                                                                                                It seems to me that ideally you want to spend as little as possible time on logistics, and as much possible time on actually building stuff. I know enough git to get by, but not enough to deal with rare exceptional situations that occur only a few times a year.

                                                                                                                                1. 1

                                                                                                                                  Broadly, they both have comparable functionality (at least for what I need), but mercurial is more friendly where git is more flexible. By and large, hg stops you from doing things that you probably don’t want to do, and makes the most common actions easy.

                                                                                                                                  That said, I switched to git a few years a back and am happy with the move. It seems trivial, but one thing that I prefer in git to hg is the ability to manipulate branches. In git a branch is just a reference to a commit, and so can be moved, renamed, deleted. In hg branches are a core part of how the repo is structured and can’t be changed. If you use a feature-branch strategy, this leads to either a) a lot of old, essentially dead branches or b) hacky workarounds using bookmarks.

                                                                                                                                  This is somewhat indicative of the overall experience - hg is simple if you use it the expected way, but gets messy otherwise. Git is always a bit fiddly but is far less prescriptive.

                                                                                                                                  1. 2

                                                                                                                                    The hg analog to a git branch is called a bookmark. The difference in nomenclature is unfortunate and an artifact of history but the same functionality exists.

                                                                                                                                    1. 1

                                                                                                                                      Yes, I know. I mentioned bookmarks in my reply. Perhaps it’s just my experience, but bookmarks (especially when used in conjunction with branches) tends to be rather clunky compared to branches in git.

                                                                                                                                      1. 2

                                                                                                                                        I don’t know very many people who actually use the hg branch feature. Pretty much everyone just uses bookmarks. I don’t personally find the clunky but they’ve been improved quite a bit since their first appearance. They are pretty close to a one to one match with a git branch for my needs.

                                                                                                                                        1. 1

                                                                                                                                          In fairness, I haven’t used hg for around 5 years (maybe longer). Back then, hg branch was idiomatic - we tacked on bookmarks to our workflow to handle temporary branches, but it was never smooth.