1. 1

    I tried on my system (which isn’t THAT old) and it took 48s to compile Go :(. It’s mostly a single-core build, so having more cores doesn’t really make a difference, and the latest Intel cores aren’t that much faster. I would guess that WD Black SSD is most of the difference – I have a random off-brand SSD.

    1. 5

      40s on an M1 Pro Mac.

      1. 2

        ./make.bash 278.53s user 44.97s system 374% cpu 1:26.27 total

        45s on a battery powered and fanless Macbook Air. The M1 ARM processors are the most notable performance boost since SSDs made their way into personal computers.

        1. 3

          If that is time output, then it took 1 minute and 26 seconds in total. 45s is the time spent in the kernel for the process (e.g. for handling system calls).

          1. 3

            🙈 You’re absolutely correct, I was confused by the time output. On my Linux machine time has a different output in bash:

            real  0m52.402s
            user  4m8.435s
            sys  0m18.317s
            

            which I prefer. Anyways, the M1 machine is plenty fast for my use case.

            1. 2

              I was confused by the time output.

              Happens :), especially with the different orders.

              Anyways, the M1 machine is plenty fast for my use case.

              I also had an MacBook Air M1 prior to the MacBook Pro 14”. The M1 Air is an awesome machine for development. And I’d say for most people who don’t need >16 GB RAM, lot of cores, or many displays, the MacBook Air M1 is the better machine.

          2. 1

            I’m not sure if the ARM and x86 compilers are really doing the same work unfortunately.

            1. 1

              If people are just compiling for the native target, it will be a bit different at the end, yeah. But typically little time is spent in the backend so it doesn’t matter that much. But this is go which has much less stuff going on in the frontend/middle than something llvm based.

          3. 2

            I also get 40s on a M1 Pro and 35s on a Ryzen 5900X.

            I am still amazed that my laptop that I can put in my backpack, with fans that barely spin up at all, is close to a 105W TDP Ryzen 5900X. Also not even that far away from the Intel Core i9-12900K from the article that has base power use of 125W and maximum turbo power use of 241W.

            My default is now to do all development on the M1 Pro, including training basic machine learning models (the AMX matrix multiplication co-processors make training small networks pretty fast). I only use a headless GPU machine for training/finetuning large models.

            1.  

              I get similar timings on my Ryzen 5600X: 39-40 seconds. My setup is optimized for noise and size though (it’s a SFFPC), and the CPU is deliberately set to limit the temperature to 75C. This way I can keep the fans super quiet, with their speed only increasing when there is prolonged load. I think I also slightly undervolted the CPU, but I’m not entirely sure.

              I did experiment with faster fan speeds, but found it didn’t matter much unless I really crank them up. Even then we’re talking about a difference of maybe a few degrees Celsius. IIRC the Ryzen CPUs simply run a little on the hotter end when under load.

              The M1 is definitely an impressive CPU, and I really hope we start to see some more diversity in the CPU landscape over time.

          4. 2

            49s on a Ryzen 9 3900X and 3x Samsung 860 EVO (built in 2020). But honestly no complaints, that’s not bad for a whole damn compiler and language runtime.

            1. 1

              It should go faster. Was that with PBO, manual OC or stock? What RAM settings?

              1. 1

                RAM is 3200MHz CL16 with XMP settings, don’t remember how I’m fixed for OC but I didn’t push it, these days I’d rather have it work 100% of the time than have it go 5% faster but crash once a week :)

              2. 1

                I had a 3700X before. If your mainboard supports it, it’s worth considering upgrading to a 5900X some time. E.g. it builds Go in 35s, so it’s a nice speedup.

                1.  

                  I’m wondering if it’s time to replace my TR2950x

                  ./make.bash 381.03s user 41.99s system 632% cpu 1:06.84 total

                2. 1

                  It’s not really single-core and storage doesn’t have that much of an impact.

                  NFS share: ./make.bash 193.40s user 36.32s system 690% cpu 33.273 total

                  in-memory tmpfs: ./make.bash 190.17s user 35.55s system 708% cpu 31.843 total

                  (this is not exactly apples-to-oranges, I’m building 1.17.6 with 1.17.4; this is on a 5950X with PBO on and RAM slightly above XMP, and an OS that doesn’t support CPPC; oh and the caches are probably pretty warm for NFS since I’ve extracted the archive on the same client machine)

                  1. 1

                    It’s mostly a single-core build, so having more cores doesn’t really make a difference, and the latest Intel cores aren’t that much faster.

                    Here is a CPU profile for 30s of the ./make.bash build:

                    https://www.dropbox.com/s/jzxklglwze7125i/go-build-cpu-counters.png?dl=0

                    There are lot of concurrent regions during the build, so I definitely wouldn’t say it’s mostly single-core.

                  1. 2

                    Company: GaggleAMP

                    Company site: https://www.gaggleamp.com/

                    Position(s): Ruby on Rails Developer

                    Location: REMOTE, EST/EDT time zone

                    Description: GaggleAMP was the first company in the “Employee Advocacy” space and has led the field in terms of innovation and customer satisfaction. We are a fully remote development team looking to add a talented Ruby on Rails developer working EST/EDT time zone. In this role you will work on our existing codebases to improve outcomes for customers, with whom you would interface directly. Additionally, you will be part of the DevOps team ensuring our systems’ uptime. This position is perfect for developers who like to manage multiple projects at a time, enjoy direct customer interactions, and gain a sense of accomplishment from driving value through the product.

                    Tech stack: Ruby on Rails and React.js

                    Compensation: $60,000 - $90,000; Medical, dental, and vision insurance; Matching 401K

                    Contact: Applications go through the job application page.

                    1. 1

                      GaggleAMP

                      Uhm, is that lawyer proof?

                      1. 1

                        Sorry if i don’t get it, what do you mean by “lawyer proof”?

                        1. 2

                          They are probably referring to Google’s AMP service.

                          1. 1

                            Oh! No, not related at all to Google or Google’s AMP technology. Gaggle defined as flock and “AMP” as the beginning of the word “amplify” :D

                          2. 1

                            It sounds very similar to google AMP

                      1. 8

                        This looks really well done! But I’m always compelled, in response to tutorials like these, to advocate for using parser/lexer generator tools instead of hand-writing them. In my experience writing your own parser is sort of a boiling-the-frog experience, where it seems pretty simple at first and then gets steadily hairier as you add more features and deal with bugs.

                        Of course if the goal is to learn how parsers work, it’s great to write one from scratch. I wrote a nontrivial one in Pascal back in the day (and that’s part of why I don’t want to do it again!)

                        Of the available types of parser generators, I find PEG ones the nicest to use. They tend to unify lexing and parsing, and the grammars are cleaner than the old yacc-type LALR grammars.

                        1. 27

                          This looks really well done! But I’m always compelled, in response to tutorials like these, to advocate for using parser/lexer generator tools instead of hand-writing them. In my experience writing your own parser is sort of a boiling-the-frog experience, where it seems pretty simple at first and then gets steadily hairier as you add more features and deal with bugs.

                          That’s the opposite of my experience. Writing a parser in a parser generator is fine for prototyping and when you don’t care about particularly good error reporting or want something that you can reuse for things like LSP support but then it will hurt you. In contrast, a hand-written recursive descent parser is more effort to write at the start but is then easy to maintain and extend. I don’t think any of the production compilers that I’ve worked on has used a parser generator.

                          1. 8

                            Also once you know the “trick” to recursive descent (that you are using the function call stack and regular control flow statements to model the grammar) it is pretty straightforward to write a parser in that style, and it’s all code you control and understand, versus another tool to learn.

                            1. 3

                              What’s the trick for left recursive grammars, like expressions with infix operators?

                              1. 4

                                Shunting yard?

                                1. 3

                                  You can’t just blindly do left-recursion for obvious reasons, but infix is pretty easy to deal with with Pratt parsing (shunting yard, precedence climbing - all the same).

                                  1. 2

                                    The trick is the while loop. If you have something like A = A '.' ident | ident you code this as

                                    loop {
                                      ident()
                                      if !eat('.') { break }
                                    }
                                    
                                2. 1

                                  Having used and written both parser generators and hand-written parsers, I agree: parser generators are nice for prototypes of very simple formats, but end up becoming a pain for larger formats.

                                3. 7

                                  Thanks! My thought process is normally: handwritten is simple enough to write, easy to explain, and common in real world software, so why learn a new tool when the fun part is what’s after the parser? I just try to focus on the rest.

                                  1. 4

                                    Lua’s grammar is also pretty carefully designed to not put you into weird ambiguous situations, with only one exception I can think of. (The ambiguity of a colon-based method call in certain contexts.)

                                  2. 6

                                    In general that is true, but with Lua there are compelling reasons (which I won’t get into here) to handwrite a single step parser for real implementations.

                                    That’s what the reference implementation does, despite its author being well-known for his research in PEGs (and authoring LPEG).

                                    1. 2

                                      do you have suggestions on PEG parsers that generate JS as well Javascript/Kotlin ?
                                      I was searching for something that I can use on a frontend webapp as well as on a backend (which is in Java).

                                      1. 2

                                        No, sorry; the one I’ve used only generates C.

                                    1. 3

                                      After six years of working for GitLab, this week is my last week. Starting 2022, I’ll be working on Inko full-time (some extra info). What I’ll be doing this week is mostly offboarding, and slowly ramping up work on Inko.

                                      1. 36

                                        I used Arch for years, even before they switched to systemd. I find it a little too hand-holdy now. I use NixOS, by the way.

                                        1. 47

                                          I think it says a lot about both Arch and Nix that I legitimately have no idea whatsoever if you’re being serious or trolling.

                                          1. 31

                                            NixOS users are the vegans of the family

                                            1. 16

                                              As a vegan, I resent this. I never talk about being vegan unless someone asks. Or to take a shot at NixOS users apparently.

                                              1. 3

                                                If food comes up, I tell people. I don’t try to preach to people, but I’ll engage (to some extent) when asked. I do not engage when people ask questions such as “what do you even eat?” or when people are just being dicks about it—not usually worth it.

                                              2. 16

                                                Are you saying NixOS is trendy and less cruel, and better for the environment?

                                                1. 12

                                                  They are probably saying there’s a stereotype of many vegans being absolutely insufferable to be around with, and vilifying anybody that isn’t a vegan. At least in my experience that stereotype (unfortunately) has some truth to it.

                                                  1. 3

                                                    It’s not vegans in general, it’s PETA. PETA knows that they can’t convert anyone who isn’t 95% of the way already, so their strategy is to remain in the public eye through shock marketing, on the “all publicity is good publicity” theory.

                                                    I know lots of vegans who never say anything about other people’s food choices, and only mention their own choice when it comes up.

                                                    1. 2

                                                      How do you tell if someone’s vegan?

                                                      Say “Look, I’m happy to make vegan entrees, sides, and desserts for the party, but you have to tell me now, instead of three hours in when I see you aren’t eating anything and ask if you’re okay.”

                                                      1. 1

                                                        I was a vegetarian for 20 years, including when I met my wife. My wife was never vegetarian but she doesn’t eat cheese.

                                                        We visited a friend and found that they had made a three part pizza for the evening: one part with pepperoni and cheese, one part with cheese but no pepperoni, and one part with pepperoni but no cheese.

                                                        We were very grateful but a bit embarrassed by the effort on our behalf.

                                                        1. 3

                                                          If it helps, they probably saw it as a chance to challenge themselves. Or a chance to flaunt their cooking skills. I def feel both when cooking for restricted diets

                                                    2. 2

                                                      There’s not the same moral dimension to Nix, compared to veganism; people who don’t use Nix are not somehow morally deficient or inappropriate. The main reason that we share Nix is to ease the suffering of users, not the suffering of computers or packages.

                                                      1. 2

                                                        Yeah. I get it. This is me not being confused, and deflecting this stupid comparison.

                                                      2. 8

                                                        Given your homepage declares your veganism in its second sentence, I don’t think you can feign too much indignation about the grandparent jibe.

                                                        1. 1

                                                          Huh? I live a vegan lifestyle, yes. Do you have a problem with that?

                                                          Jesus. Mechanical engineers are insufferable.

                                                          1. 10

                                                            You announce you’re a vegan. That’s literally the reason for the “btw, I’m vegan/arch user” joke. There’s nothing wrong with that, but as you can see the stereotype matches reality.

                                                            1. 2

                                                              They announce it on their webpage… that you chose to go and read…

                                                              1. 1

                                                                I am fully aware.

                                                          2. 2

                                                            If you’ve used NixOS, you’ll know less cruel doesn’t apply

                                                            1. 2

                                                              It’s been a long time, but I gave up pretty quickly. 😀

                                                      1. 2

                                                        What do people prefer between KeePassXC and passwordstore.org? Personally I use the latter but mostly because I found it first and have invested effort into setting it up. But I was thinking of switching because since keepass(xc) stores passwords in a single file it seems easier to manage across devices. (As opposed to pass where files for each website are generally separate.)

                                                        1. 12

                                                          I don’t care for passwordstore.org, because as you mentioned, it leaks the accounts you have to the filesystem. If your threat model includes a multi-user system or cloud storage, then this might be a problem. With KeePassXC, this threat is mitigated as every entry in stored a single encrypted database.

                                                          EDIT: typo

                                                          1. 8

                                                            But I was thinking of switching because since keepass(xc) stores passwords in a single file it seems easier to manage across devices

                                                            It’s multiple files with pass but it can be a single git repo, which I’ve found is a lot more useful since it can detect conflicts and stuff. Running pass git pull --rebase otherlaptop fits a lot better with my mental model and existing tooling than “just put it in and the program performs some unspecified merge algorithm somehow”.

                                                            1. 5

                                                              I’m using Strongbox on iOS these days. When I started using it, I was hesitant to pay for the Pro Lifetime version ($60), dictated by how well it would work for at least a year. I’m happy to say that it’s been exceeding my expectations for well over two years now, and I did end up paying for the lifetime version.

                                                              1. 4

                                                                I used pass for a few years, but recently switched to Bitwarden. I did try KeePassXC, but didn’t like it because:

                                                                • For some reason it was using 200+ MB of memory. I think that’s a bit much for something that has to run in the background.
                                                                • Syncing would be a bit clunky. Technically you can stuff the DB in Git, but it’s not great.
                                                                • Qt applications under GNOME/Gtk WMs always look/feel a bit clunky

                                                                My main issues with pass were the usual ones:

                                                                • It’s free-form nature makes it a bit difficult to keep password files consistent
                                                                • You leak file names. This isn’t the biggest deal for me, but I’d prefer to avoid it if possible
                                                                • Not necessarily a flaw of pass but more of my setup: I had pass auto-unlock upon logging in. This is great for me, but also means any application can just run pass ... and read passwords.

                                                                Bitwarden is OK, though I really hate their CLI. There’s an unofficial one (https://github.com/doy/rbw) that’s nicer to use, but it doesn’t support YubiKey logins (https://github.com/doy/rbw/issues/7), so I can’t use it.

                                                                1. 1

                                                                  Syncing would be a bit clunky. Technically you can stuff the DB in Git, but it’s not great.

                                                                  I do both. I have issues with neither method. My only problem with having the full history available is that there is no rekeying the database, you have to change every password for it to make sense. Or maybe it’s only making me aware of the actual implications of leaking the db.

                                                                  Qt applications under GNOME/Gtk WMs always look/feel a bit clunky

                                                                  Working in a terminal 99% of the time, I have no issue with this. In my barebones i3 setup every GUI is ugly anyway. That irked me at first, but I learned not to care a long time ago.

                                                                  1. 1

                                                                    It depends on your threat model but I sync my KeePass file using cloud sync (Dropbox, Jottacloud, Syncthing).

                                                                    Been doing this for several years and no issues.

                                                                    What I like about KeePass is that it is available on so many platforms. So even using OpenBSD and SailfishOS, I had no issue finding clients.

                                                                  2. 2

                                                                    I’ve found passwordstore to be a great “clearing house” for importing from elsewhere even if it isn’t my final destination. I used it to export from 1Password and the Keepass family (which I tried but didn’t really like). I’m currently polishing off a script to import my password store to Bitwarden.

                                                                  1. 19

                                                                    +1

                                                                    Another useful feature are abbreviations: https://fishshell.com/docs/current/cmds/abbr.html. These are like aliases, except that they expanded in place. That is, you type sw but what you get is git switch. That’s pretty useful to keep the cognitive load low, as what you read are full commands. Also helpful when you want to edit command slightly.

                                                                    1. 3

                                                                      This looks nice as a replacement for some of my Fish functions. Thanks for sharing!

                                                                      1. 1

                                                                        I never know such a thing. I might move some alias to abbrev. To keep the cognitive load low. Thanks.

                                                                      1. 15

                                                                        I’ve been using Fish since 2015, and it’s been great. Fish not being POSIX compatible hasn’t been an issue in practice, though I don’t do a lot of shell scripting to begin with. If somebody is curious about my Fish configuration, you can find it here.

                                                                        1. 4

                                                                          For me the lack of sh-compatible syntax has been a real problem, to the point where I switched to bash at work. Fish does have the best user experience I’ve seen, but the need for specific Fish scripts is a problem, in particular with Nix or any tool that you need to load from your profile. There are wrappersz like bass, but they don’t always work and have overhead.

                                                                          1. 30

                                                                            Just because fish is your interactive shell doesn’t mean that you need to start shell scripts with !/usr/bin/env fish.

                                                                            1. 9

                                                                              I never understood what people is doing all day in their prompt that needs POSIX compatibility. The syntax to call commands is the same.

                                                                              I think it is mostly a meme or a simple matter of running copy pasted scripts from the web and not understanding how interpreter resolution works or that you can manually define it.

                                                                              1. 1

                                                                                Not necessarily whole scripts. Sometimes you want to paste just a couple commands into the interactive prompt.

                                                                              2. 3

                                                                                But for stuff like Nix, don’t you have to run the setup scripts in your interactive shell with source or equivalent, so they can set environment variables and such?

                                                                                1. 3

                                                                                  In Unix, all child processes of a process will inherit the parent’s environment. You should be able to write all your scripts as POSIX compliant (or bash compliant) and run them from inside fish without an issue, as long as you specify the interpreter like so: bash myscript.sh

                                                                                  1. 8

                                                                                    The problem, if I understood it right (I’ve never used things like Nix) is that these are not things you’re supposed to run, but things you’re supposed to source. I.e. you source whatever.sh so that you get the right environment to do everything else. Sort of like the decade-old env.sh hack for closed-source toolchains and the like, which you source so that you can get all the PATH and LD_LIBRARY_PATH hacks only for this interactive session instead of polluting your .profile with them.

                                                                                    1. 1

                                                                                      I see, that makes sense. I guess I didn’t consider that, wonder how the activate script generated with a Python virtual environment would work with Fish. Even a relatively fancy .profile file might be incompatible with Fish.

                                                                              3. 8

                                                                                I usually just switch to bash when I need to run a command this way. And honesty I’m more annoyed at commands like these that modify your shell environment and thus force you to use a POSIX-compatible shell, than I am at fish for deliberately trying something different that isn’t POSIX.

                                                                                1. 1

                                                                                  Fortunately some commands are designed to output a shell snippet to be used with eval

                                                                                  eval $(foo) # foo prints 'export VAR=bar'
                                                                                  

                                                                                  In that case you can pipe output of foo to Fish’s source

                                                                                  foo | source
                                                                                  
                                                                                  1. 2

                                                                                    No, that’s exactly what you can’t do, the code won’t be valid for source-ing (unless those commands specifically output csh-style rather than posix-style script)

                                                                                    Though apparently these days fish does support the most common POSIX-isms

                                                                                    1. 1

                                                                                      I mean only the case where you set env variables (like luarocks path)

                                                                                2. 4

                                                                                  I also had problems with bass. It was too slow to run in my config.fish. However, I switched to https://github.com/oh-my-fish/plugin-foreign-env and it’s worked perfectly for me. And you don’t need oh-my-fish to use it — I installed it with the plugin manager https://github.com/jorgebucaran/fisher.

                                                                                  1. 2

                                                                                    Ah, I hadn’t seen this one, if it succeeds to setup Nix then it’s party time!

                                                                                    1. 3

                                                                                      Not a fish user, but since you’re a Nix user I would also recommend checking out direnv which has fish support. For nix in direnv specifically I would also recommend something like nix-direnv (and several others) which caches and also gcroots environments so overheads are next to negligible when things remain unchanged.

                                                                                    2. 1

                                                                                      That looks good enough to make me want to try fish again. I had not seen it last time I tried fish. Thanks for pointing it out.

                                                                                1. 19

                                                                                  Looks like he hit 56 GB/s when it was run on the AMD 5950x. The author of the code said he spent months working on this. Incredible dedication.

                                                                                  1. 5

                                                                                    Yeah but can they invert a binary tree on a whiteboard? If not this person doesn’t stand a chance of getting hired anywhere /s

                                                                                    1. 1

                                                                                      It’s a shame as the inverted binary tree presentation task is well known and less-skilled devs can just practice it ahead of time. I can’t imagine being asked to write FizzBuzz while avoiding the heap while being given the freedom to use Linux API calls that would crash the app if its output is not piped into another application. The author of the answer potentially found a Kernel bug while working on this. Even after seeing this a few days ago, I’m still seriously impressed with this person’s work.

                                                                                  1. 17

                                                                                    Pattern matching has been available in functional programming languages for decades now, it was introduced in the 70s. (Logic programming languages expose even more expressive forms, at higher runtime cost.) It obviously improves readability of code manipulating symbolic expressions/trees, and there is a lot of code like this. I find it surprising that in the 2020s there are still people wondering whether “the feature provides enough value to justify its complexity”.

                                                                                    (The fact that Python did without for so long was rather a sign of closed-mindedness of its designer subgroup. The same applies, in my opinion, to languages (including Python, Go, etc.) that still don’t have proper support for disjoint union types / variants / sums / sealed case classes.)

                                                                                    1. 45

                                                                                      Pretty much every feature that has ever been added to every language ever is useful in some way. You can leave a comment like this on almost any feature that a language may not want to implement for one reason or the other.

                                                                                      1. 14

                                                                                        I think it makes more sense in statically typed languages, especially functional ones. That said, languages make different choices. For me, Python has always been about simplicity and readability, and as I’ve tried to show in the article, at least in Python, structural pattern matching is only useful in a relatively few cases. But it’s also a question of taste: I really value the simplicity of the Go language (and C before it), and don’t mind a little bit of verbosity if it makes things clearer and simpler. I did some Scala for a while, and I can see how people like the “power” of it, but the learning curve of its type system was very steep, and there were so many different ways to do things (not to mention the compiler was very slow, partly because of the very complex type system).

                                                                                        1. 22

                                                                                          For the record, pattern-matching was developed mostly in dynamically-typed languages before being adopted in statically-typed languages, and it works just as well in a dynamically-typed world. (In the ML-family world, sum types and pattern-matching were introduced by Hope, an experimental dynamically-typed language; in the logic world, they are basic constructs of Prolog, which is also dynamically-typed – although some more-typed dialects exist.)

                                                                                          as I’ve tried to show in the article, at least in Python, structural pattern matching is only useful in a relatively few cases

                                                                                          Out of the 4 cases you describe in the tutorial, I believe your description of two of them is overly advantageous to if..elif:

                                                                                          • In the match event.get() case, the example you show is a variation of the original example (the longer of the three such examples in the tutorial), and the change you made makes it easier to write an equivalent if..elif version, because you integrated a case (from another version) that ignores all other Click() events. Without this case (as in the original tutorial example), rewriting with if..elif is harder, you need to duplicate the failure case.
                                                                                          • In the eval_expr example, you consider the two versions as readable, but the pattern-version is much easier to maintain. Consider, for example, supporting operations with 4 or 5 parameters, or adding an extra parameter to an existing operator; it’s an easy change with the pattern-matching version, and requires boilerplate-y, non-local transformations with if..elif. These may be uncommon needs for standard mathematical operations, but they are very common when working with other domain-specific languages.
                                                                                          1. 1

                                                                                            the change you made makes it easier to write an equivalent if..elif version

                                                                                            Sorry if it appeared that way – that was certainly not my intention. I’m not quite sure what you mean, though. The first/original event example in the tutorial handles all click events with no filtering using the same code path, so it’s even simpler to convert. I added the Button.LEFT filtering from a subsequent example to give it a bit more interest so it wasn’t quite so simple. I might be missing something, though.

                                                                                            In the eval_expr example, you consider the two versions as readable, but the pattern-version is much easier to maintain. Consider, for example, supporting operations with 4 or 5 parameters, or adding an extra parameter to an existing operator;

                                                                                            I think those examples are very hypothetical – as you indicate, binary and unary operators aren’t suddenly going to support 4 or 5 parameters. A new operation might, but that’s okay. The only line that’s slightly repetitive is the “attribute unpacking”: w, x, y, z = expr.w, expr.x, expr.y, expr.z.

                                                                                            These may be uncommon needs for standard mathematical operations, but they are very common when working with other domain-specific languages.

                                                                                            You’re right, and that’s part of my point. Python isn’t used for implementing compilers or interpreters all that often. That’s where I’m coming from when I ask, “does the feature provide enough value to justify the complexity?” If 90% of Python developers will only rarely use this complex feature, does it make sense to add it to the language?

                                                                                            1. 3

                                                                                              that was certainly not my intention.

                                                                                              To be clear, I’m not suggesting that the change was intentional or sneaky, I’m just pointing out that the translation would be more subtle.

                                                                                              The first/original event example does not ignore “all other Click events” (there is no Click() case), and therefore an accurate if..elif translation would have to do things differently if there is no position field or if it’s not a pair, namely it would have to fall back to the ValueError case.

                                                                                              You’re right, and that’s part of my point. Python isn’t used for implementing compilers or interpreters all that often.

                                                                                              You don’t need to implement a compiler for C or Java, or anything people recognize as a programming language (or HTML or CSS, etc.), to be dealing with a domain-specific languages. Many problem domains contain pieces of data that are effectively expressions in some DSL, and recognizing this can very helpful to write programs in those domains – if the language supports the right features to make this convenient. For example:

                                                                                              • to start with the obvious, many programs start by interpreting some configuration file to influence their behavior; many programs have simple needs well-served by linear formats, but many programs (eg. cron jobs, etc.) require more elaborate configurations that are DSL-like. Even if the configuration is written in some standard format (INI, Yaml, etc.) – so parsing can be delegated to a library – the programmer will still write code to interpret or analyze the configuration data.
                                                                                              • more gnerally, “structured data formats” are often DSL-shaped; ingesting structured data is something we do super-often in programs
                                                                                              • programs that offer a “query” capability typically provide a small language to express those queries
                                                                                              • events in an event loop typically form a small language
                                                                                          2. 14

                                                                                            I think it makes more sense in statically typed languages, especially functional ones.

                                                                                            In addition to the earlier ones gasche mentioned (it’s important to remember this history), it’s used to pervasively in Erlang, and later Elixir. Clojure has core.match, Racket has match, as does Guile. It’s now in Ruby as well!

                                                                                            1. 3

                                                                                              Thanks! I didn’t know that. I have used pattern matching in statically typed language (mostly Scala), and had seen it in the likes of Haskell and OCaml, so I’d incorrectly assumed it was mainly a statically-typed language thing.

                                                                                              1. 1

                                                                                                It is an important feature of OCaml.

                                                                                                1. 3

                                                                                                  I am aware - was focusing on dynamically typed languages.

                                                                                              2. 7

                                                                                                For me, it is the combination of algebraic data types + pattern matching + compile time exhaustiveness checking that is the real game changer. With just 1 out of 3, pattern matching in Python is much less compelling.

                                                                                                1. 1

                                                                                                  I agree. I wonder if they plan to add exhaustiveness checking to mypy. The way the PEP is so no hold barred makes it seem like the goal was featurefulness and not an attempt to support exhaustiveness checking.

                                                                                                  1. 2

                                                                                                    I wonder if they plan to add exhaustiveness checking to mypy.

                                                                                                    I don’t think that’s possible in the general case. If I understand the PEP correctly, __match_args__ may be a @property getter method, which could read the contents of a file, or perform a network request, etc.

                                                                                              3. 11

                                                                                                I find it surprising that in the 2020s there are still people wondering whether “the feature provides enough value to justify its complexity”.

                                                                                                I find it surprising that people find this surprising.

                                                                                                Adding features like pattern matching isn’t trivial, and adding it too hastily can backfire in the long term; especially for an established language like Python. As such I would prefer a language take their time, rather than slapping things on because somebody on the internet said it was a good idea.

                                                                                                1. 3

                                                                                                  That’s always been the Scheme philosophy:

                                                                                                  Programming languages should be designed not by piling feature on top of feature, but by removing the weaknesses and restrictions that make additional features appear necessary.

                                                                                                  And indeed, this pays off: in the Scheme world, there’s been a match package floating around for a long time, implemented simply as a macro. No changes to the core language needed.

                                                                                                  1. 4

                                                                                                    No changes to the core language needed.

                                                                                                    I’m sure you recognize that this situation does not translate to other languages like in this case Python. Implementing it as a macro is just not feasible. And even in Scheme the usage of match macros is rather low. This can be because it is not that useful, but also might be because of the hurdle of adding dependencies is not worth the payoff. Once a feature is integrated in a language, its usage “costs” nothing, thus the value proposition when writing code can be quite different.

                                                                                                    1. 7

                                                                                                      This is rather unrelated to the overall discussion, but as a user of the match macros in Scheme, I must say that I find the lack of integration into the base forms slightly annoying. You cannot pattern-match on a let or lambda, you have to use match-let and match-lambda, define/match (the latter only in Racket I think), etc. This makes reaching for pattern-matching feel heavier, and it may be a partial cause to their comparatively lower usage. ML-family languages generalize all binding positions to accept patterns, which is very nice to decompose records for example (or other single-case data structures). I wish Scheme dialects would embrace this generalization, but they haven’t for now – at least not Racket or Clojure.

                                                                                                      1. 2

                                                                                                        In the case of Clojure while it doesn’t have pattern matching built-in, it does have quite comprehensive destructuring forms (like nested matching in maps, with rather elaborate mechanisms) that works in all binding positions.

                                                                                                        1. 2

                                                                                                          Nice! I suppose (from your post above) that pattern-matching is somehow “integrated” in the Clojure implementation, rather than just being part of the base macro layer that all users see.

                                                                                                          1. 2

                                                                                                            I think the case is that Clojure core special forms support it (I suppose the implementation itself is here and called “binding-forms”, which is then used by let, fn and loop which user defined macros often end up expanding to). Thus it is somewhat under the base layer that people use.

                                                                                                            But bear in mind this is destructuring, in a more general manner than what Python 2.x already supported, not pattern matching. It also tends to get messy with deep destructuring, but the same can be said of deep pattern matches through multiple layers of constructors.

                                                                                                2. 8

                                                                                                  I agree about pattern matching and Python in general. It’s depressing how many features have died in python-ideas because it takes more than a few seconds for an established programmer to grok them. Function composition comes to mind.

                                                                                                  But I think Python might be too complicated for pattern matching. The mechanism they’ve settled on is pretty gnarly. I wrote a thing for pattern matching regexps to see how it’d turn out (admittedly against an early version of the PEP; I haven’t checked it against the current state) and I think the results speak for themselves.

                                                                                                  1. 6

                                                                                                    But I think Python might be too complicated for pattern matching. The mechanism they’ve settled on is pretty gnarly.

                                                                                                    I mostly agree. I generally like pattern matching and have been excited about this feature, but am still feeling out exactly when I’ll use it and how it lines up with my intuition.

                                                                                                    The part that does feel very Pythonic is that destructuring/unpacking is already pretty pervasive in Python. Not only for basic assignments, but also integrated into control flow constructs. For example, it’s idiomatic to do something like:

                                                                                                    for key, val in some_dictionary.items():
                                                                                                        # ...
                                                                                                    

                                                                                                    Rather than:

                                                                                                    for item in some_dictionary.items():
                                                                                                        key, val = item
                                                                                                        # ...
                                                                                                    

                                                                                                    Or something even worse, like explicit item[0] and item[1]. So the lack of a conditional-with-destructuring, the way we already have foreach-with-destructuring, did seem like a real gap to me, making you have to write the moral equivalent of code that looks more like the 2nd case than the 1st. That hole is now filled by pattern matching. But I agree there are pitfalls around how all these features interact.

                                                                                                  2. 2
                                                                                                    for i, (k, v) in enumerate(d.items(), 1): pass
                                                                                                    

                                                                                                    looks like pattern matching to me

                                                                                                    1. 2

                                                                                                      Go aims for simplicity of maintenance and deployment. It doesn’t “still don’t have those features”. The Go authors avoided them on purpose. If you want endless abstractions in Go, embedding Lisp is a possibilty: https://github.com/glycerine/zygomys

                                                                                                      1. 5

                                                                                                        Disjoint sums are a basic programming feature (it models data whose shape is “either this or that or that other thing”, which ubiquitous in the wild just like pairs/records/structs). It is not an “endless abstraction”, and it is perfectly compatible with maintenance and deployment. Go is a nice language in some respects, the runtime is excellent, the tooling is impressive, etc etc. But this is no rational excuse for the lack of some basic language features.

                                                                                                        We are in the 2020s, there is no excuse for lacking support for sum types and/or pattern matching. Those features have been available for 30 years, their implementation is well-understood, they require no specific runtime support, and they are useful in basically all problem domains.

                                                                                                        I’m not trying to bash a language and attract defensive reactions, but rather to discuss (with concrete examples) the fact that language designer’s mindsets can be influenced by some design cultures more than others, and as a result sometimes the design is held back by a lack of interest for things they are unfamiliar with. Not everyone is fortunate to be working with a deeply knowledgeable and curious language designer, such as Graydon Hoare; we need more such people in our language design teams. The default is for people to keep working on what they know; this sort of closed-ecosystem evolution can lead to beautiful ideas (some bits of Perl 6 for example are very nice!), but it can also hold back.

                                                                                                        1. 3

                                                                                                          But this is no rational excuse for the lack of some basic language features.

                                                                                                          Yes there is. Everyone has a favorite feature, and if all of those are implemented, there would easily be feature bloat, long build times and projects with too many dependencies that depend on too many dependencies, like in C++.

                                                                                                          In my opinion, the question is not if a language lacks a feature that someone wants or not, but if it’s usable for goals that people wish to achieve, and Go is clearly suitable for many goals.

                                                                                                      2. 3

                                                                                                        Ah yes, Python is famously closed-minded and hateful toward useful features. For example, they’d never adopt something like, say, list comprehensions. The language’s leaders are far too closed-minded, and dogmatically unwilling to ever consider superior ideas, to pick up something like that. Same for any sort of ability to work with lazy iterables, or do useful combinatoric work with them. That’s something that definitely will never be adopted into Python due to the closed-mindedness of its leaders. And don’t get me started on basic FP building blocks like map and folds. It’s well known that Guido hates them so much that they’re permanently forbidden from ever being in the language!

                                                                                                        (the fact that Python is not Lisp was always unforgivable to many people; the fact that it is not Haskell has now apparently overtaken that on the list of irredeemable sins; yet somehow we Python programmers continue to get useful work done and shrug off the sneers and insults of our self-proclaimed betters much as we always have)

                                                                                                        1. 25

                                                                                                          It is well-documented that Guido Van Rossum planned to remove lambda from Python 3. (For the record, I agree that map and filter on lists are much less useful in presence of list comprehensions.) It is also well-documented that recursion is severely limited in Python, making many elegant definitions impractical.

                                                                                                          Sure, Python adopted (in 2000 I believe?) list comprehensions from ABC (due to Guido working with the language in the 1980s), and a couple of library-definable iterators. I don’t think this contradicts my claim. New ideas came to the language since (generators, decorators), but it remains notable that the language seems to have resisted incorporating strong ideas from other languages. (More so than, say, Ruby, C#, Kotlin, etc.)

                                                                                                          Meta: One aspect of your post that I find unpleasant is the tone. You speak of “sneers and insults”, but it is your post that is highly sarcastic and full of stray exagerations at this or that language community. I’m not interested in escalating in this direction.

                                                                                                          1. 7

                                                                                                            less useful in presence of list comprehension

                                                                                                            I’m certainly biased, but I find Python’s list comprehension an abomination towards readability in comparison to higher-order pipelines or recursion. I’ve not personally coded Python in 8-9 years, but when I see examples, I feel like I need to put my head on upsidedown to understand it.

                                                                                                            1. 6

                                                                                                              It is also well-documented that recursion is severely limited in Python, making many elegant definitions impractical.

                                                                                                              For a subjective definition of “elegant”. But this basically is just “Python is not Lisp” (or more specifically, “Python is not Scheme”). And that’s OK. Not every language has to have Scheme’s approach to programming, and Scheme’s history has shown that maybe it’s a good thing for other languages not to be Scheme, since Scheme has been badly held back by its community’s insistence that tail-recursive implementations of algorithms should be the only implementations of those algorithms.

                                                                                                              You speak of “sneers and insults”, but it is your post that is highly sarcastic and full of stray exagerations at this or that language community.

                                                                                                              Your original comment started from a place of assuming – and there really is no other way to read it! – that the programming patterns you care about are objectively superior to other patterns, that languages which do not adopt those patterns are inherently inferior, and that the only reason why a language would not adopt them is due to “closed-mindedness”. Nowhere in your comment is there room for the (ironically) open-minded possibility that someone else might look at patterns you personally subjectively love, evaluate them rationally, and come to a different conclusion than you did – rather, you assume that people who disagree with your stance must be doing so because of personal faults on their part.

                                                                                                              And, well, like I said we’ve got decades of experience of people looking down their noses at Python and/or its core team + community for not becoming a copy of their preferred languages. Your comment really is just another instance of that.

                                                                                                              1. 8

                                                                                                                I’m not specifically pointing out the lack of tail-call optimization (TCO) in Python (which I think is unfortunate indeed; the main argument is that call stack matters, but it’s technically fully possible to preserve call stacks on the side with TC-optimizing implementations). Ignoring TCO for a minute, the main problem would be the fact that the CPython interpreter severely limits the call space (iirc it’s 1K calls by default; compare that to the 8Mb default on most Unix systems), making recursion mostly unusable in practice, except for logarithmic-space algorithms (balanced trees, etc.).

                                                                                                                Scheme has been badly held back by its community’s insistence that tail-recursive implementations of algorithms should be the only implementations of those algorithms.

                                                                                                                I’m not sure what you mean – that does not make any sense to me.

                                                                                                                [you assume] that the programming patterns you care about are objectively superior to other patterns [..]

                                                                                                                Well, I claimed

                                                                                                                [pattern matching] obviously improves readability of code manipulating symbolic expressions/trees

                                                                                                                and I stand by this rather modest claim, which I believe is an objective statement. In fact it is supported quite well by the blog post that this comment thread is about. (Pattern-matching combines very well with static typing, and it will be interesting to see what Python typers make of it; but its benefits are already evident in a dynamically-typed context.)

                                                                                                                1. 4

                                                                                                                  and I stand by this rather modest claim, which I believe is an objective statement.

                                                                                                                  Nit: I don’t think you can have an objective statement of value.

                                                                                                                  1. 4

                                                                                                                    Again: your original comment admits of no other interpretation than that you do not believe anyone could rationally look at the feature you like and come to a different conclusion about it. Thus you had to resort to trying to find personal fault in anyone who did.

                                                                                                                    This does not indicate “closed-mindedness” on the part of others. They may prioritize things differently than you do. They may take different views of complexity and tradeoffs (which are the core of any new language-feature proposal) than you do. Or perhaps they simply do not like the feature as much as you do. But you were unwilling to allow for this — if someone didn’t agree with your stance it must be due to personal fault. You allowed for no other explanation.

                                                                                                                    That is a problem. And from someone who’s used to seeing that sort of attitude it will get you a dismissive “here we go again”. Which is exactly what you got.

                                                                                                                2. 4

                                                                                                                  This is perhaps more of a feeling, but saying that Rust isn’t adopting features as quickly as Ruby seems a bit off. Static type adoption in the Python community has been quicker. async/await has been painful, but is being attempted. Stuff like generalized unpacking (and this!) is also shipping out!

                                                                                                                  Maybe it can be faster, but honestly Python probably has one of the lowest “funding amount relative to impact” of the modern languages which makes the whole project not be able to just get things done as quickly IMO.

                                                                                                                  Python is truly in a funny place, where many people loudly complain about it not adopting enough features, and many other loudly complain about it loudly adopting too many! It’s of course “different people have different opinions” but still funny to see all on the same page.

                                                                                                                  1. 3

                                                                                                                    It is well-documented that Guido Van Rossum planned to remove lambda from Python 3

                                                                                                                    Thank you for sharing that document. I think Guido was right: it’s not pythonic to map, nor to use lambdas in most cases.

                                                                                                                    Every feature is useful, but some ecosystems work better without certain features. I’m not sure where go’s generics fall on this spectrum, but I’m sure most proposed features for python move it away from it’s core competency, rather than augmenting a strong core.

                                                                                                                    1. 1

                                                                                                                      We have previously discussed their tone problem. It comes from their political position within the Python ecosystem and they’re relatively blind to it. Just try to stay cool, I suppose?

                                                                                                                      1. 6

                                                                                                                        I really do recommend clicking through to that link, and seeing just what an unbelievably awful thing I said that the user above called out as “emblematic” of the “contempt” I display to Python users. Or the horrific ulterior motive I was found to have further down.

                                                                                                                        Please, though, before clicking through, shield the eyes of children and anyone else who might be affected by seeing such content.

                                                                                                                    2. 5

                                                                                                                      To pick one of my favorite examples, I talked to the author of PEP 498 after a presentation that they gave on f-strings, and asked why they did not add destructuring for f-strings, as well as whether they knew about customizeable template literals in ECMAScript, which trace their lineage through quasiliterals in E all the way back to quasiquotation in formal logic. The author knew of all of this history too, but told me that they were unable to convince CPython’s core developers to adopt any of the more advanced language features because they were not seen as useful.

                                                                                                                      I think that this perspective is the one which might help you understand. Where you see one new feature in PEP 498, I see three missing subfeatures. Where you see itertools as a successful borrowing of many different ideas from many different languages, I see a failure to embrace the arrays and tacit programming of APL and K, and a lack of pattern-matching and custom operators compared to Haskell and SML.

                                                                                                                    3. 1

                                                                                                                      I think the issue is more about pattern matching being a late addition to Python, which means there will be lots of code floating around that isn’t using match expressions. Since it’s not realistic to expect this code to be ported, the old style if … elif will continue to live on. All of this adds up to a larger language surface area, which makes tool support, learning and consistency more difficult.

                                                                                                                      I’m not really a big fan of this “pile of features” style of language design - if you add something I’d prefer if something got taken away as well. Otherwise you’ll end up with something like Perl 5

                                                                                                                    1. 7

                                                                                                                      A GUI toolkit that is easy as html to use but as memory efficient as native.

                                                                                                                      1. 5

                                                                                                                        For some reason I’m reminded of XUL. And I think I just heard a Firefox developer cry out in terror.

                                                                                                                        1. 2

                                                                                                                          the big question there would be what features do you consider essential from html?

                                                                                                                          1. 2

                                                                                                                            This is an idea I’ve been toying with for some time. Basically an HTML rendering engine meant for GUIs, like Sciter. But instead of Javascript, you’d control everything using the host language (probably Rust). If you’d want JS you’d have to somehow bind that to Rust.

                                                                                                                            I think this could really work out. However: I’ve dealt with XML and HTML parsers for years in the past, and I’m not sure I’m ready yet to dive into the mess that is HTML again.

                                                                                                                          1. 6

                                                                                                                            This sounds similar to how Pony does things

                                                                                                                            1. 3

                                                                                                                              Yup, though Pony takes it a bit further by introducing many different reference types/capabilities.

                                                                                                                            1. 4

                                                                                                                              I’ve had my fair share of both parser generators (even wrote one myself), consumption of those parsers (e.g. for a Ruby based XML/HTML parser), and hand-written recursive descent parsers (e.g. for Inko).

                                                                                                                              I’ve grown to really prefer hand-written parsers. Parser generators are great if you have a reasonable and well established grammar and language to parse. However, you can hit walls quickly, and often there are no escape hatches. They also complicate your build process, which was a big issue for me in the past due to the use of Ragel for my lexers. I also really hate debugging parser generators, as the generated code is often a total mess.

                                                                                                                              Parsing combinators are nice when you don’t want to separate lexing and parsing, you don’t want a separate build phase, and you can’t be bothered writing a recursive descent parser from scratch. For example, I used a Ruby parsing combinator to write a parser for a templating language GitLab uses for generating changelogs (parser here). Debugging parsing combinators can be a pain though, so I generally prefer hand-written parsers. I opted not to use one here to make it easier for others to maintain the parsing code.

                                                                                                                              When evaluating what parsing approach to use, I would recommend the order: hand-written recursive descent > parsing combinator > parsing generator. Hand-written parsers just work much better in the long term, but parsing combinators can be easier to grok/maintain (if you don’t care about webscale performance). Parsing generators I would just avoid if you can.

                                                                                                                              1. 1

                                                                                                                                Even when I use a parser combinator approach which is often I still separate the lexing and parsing phases. I think it’s just a lot cleaner and easier to reason about. I personally don’t think there is a large amount of distance between parser combinators and hand rolled recursive descent parsing but everyone is a little different in their opinions on that I think. Either way I generally find most people I talk to end up gravitating to recursive descent and parser combinators being in their top two and parser generators getting used really only to prove out a grammar when you are playing with the syntax or when the grammer is already known available in a format the generator can already parse.

                                                                                                                              1. 5

                                                                                                                                A similar (but smaller) list is found here. Mind you these are only languages active on the /r/ProgrammingLanguages subreddit IIRC.

                                                                                                                                1. 3

                                                                                                                                  For the last few months I’ve been hard at work to change the memory model/type system of Inko from the usual (garbage collection and no clear ownership) to a single ownership model (based on this paper).

                                                                                                                                  For the last two weeks I’ve been working on the allocator, and specifically the strategy for reclaming memory. So far I have an idea that I’m in the process of writing tests for. However, I need to give this some more thought, as I’m not entirely sold on my idea just yet.

                                                                                                                                  1. 3

                                                                                                                                    The second co-author of the paper is David F. Bacon. I can’t recommend this highly enough for anyone who is interested in reading memory management: read everything that he has ever written.

                                                                                                                                  1. 2

                                                                                                                                    Always nice to see more people build programming languages. I will say this: be prepared to change a lot of your assumptions, implementation, etc 1-2 years from now. As you start working on the language you’ll likely find certain ideas won’t work anymore, or you realise you just prefer to replace one particular feature with something else :)

                                                                                                                                    1. 1

                                                                                                                                      That’s partially why I wanted to write the goals upfront and not include many specifics in this post. The language syntax and semantics will evolve as I build things out, but the goals should be relatively static.

                                                                                                                                    1. 11

                                                                                                                                      I find these kind of articles exhausting. They usually come down to the same: pattern X seen in paradigm Y is bad, therefor Y is bad. The alternatives proposed usually aren’t really good either. Basically once you’ve read one of these, you’ve read all of them.

                                                                                                                                      For example:

                                                                                                                                      If it looks like a candidate for a class, it goes into a class. Do I have a Customer? It goes into class Customer. Do I have a rendering context? It goes into class RenderingContext.

                                                                                                                                      Then the “solution” presented in this article:

                                                                                                                                      The data itself will be in form of an ADT/PoD structures, and any references between the data records will be of a form of an ID (number, uuid, or a deterministic hash). Under the hood, it typically closely resembles or actually is backed by a relational database: Vectors or HashMaps storing bulk of the data by Index or ID, some other ones for “indices” that are required for fast lookup and so on.

                                                                                                                                      Now there’s nothing wrong with plain old data structures. But eventually those data structures are going to need a bunch of associated functions. And then you pretty much have a class. In other words, the solution is basically the same as the problem.

                                                                                                                                      The real problem isn’t unique to OOP and can just as easily occur in say functional programming languages. That is, the problem is people over-applying patterns without thinking “Hey, do we actually need this?”. Traditional OOP languages may promote this in some way, but again that’s a problem with those languages. The concept of OOP has nothing to do with any of this.

                                                                                                                                      Random example: in any language that has support for macros, inevitably some will start abusing macros. But that doesn’t mean the entire language or its paradigm is bad and should be avoided.

                                                                                                                                      As an aside, every time I see a quote from Dijkstra I can’t help but feel this man must have been absolutely insufferable to work with. Yes, he was very smart and made many contributions. But holy moly, his “I am right and everybody else is wrong” attitude (at least that’s how it comes across to me) is off putting to say the least.

                                                                                                                                      1. 5

                                                                                                                                        Now there’s nothing wrong with plain old data structures. But eventually those data structures are going to need a bunch of associated functions. And then you pretty much have a class. In other words, the solution is basically the same as the problem.

                                                                                                                                        It is the other way around. With OOP, you pretty much end up jamming into data structure definitions what essentially are functions. The concept of class is fuzzy and it’s not a clear well define starting point for a thought process.

                                                                                                                                        Notice that you said “associated functions”. I think it’s all the OOP non sense cornering you into that unclear language. What exactly are those? Functions that accept the type you are defining? Functions that manipulate the state of said data structure? Functions that return a reference to it?

                                                                                                                                        If you think about this questions and find clear answers for them, you will realize that there is absolutely no reason to make functions have all sorts of tricky behaviours based on state or even “belonging to an instance”. At which point the concept of class becomes pointless.

                                                                                                                                        Relational algebra was developed with solid theory behind it. To my knowledge, OOP was just something thrown together “because it is a good idea”.

                                                                                                                                        Records, as in compound types, are very useful in many fields even outside programming languages. Hooking functions to them is just a strange idea whose motivation I am yet to discover.

                                                                                                                                        1. 2

                                                                                                                                          Notice that you said “associated functions”. I think it’s all the OOP non sense cornering you into that unclear language. What exactly are those?

                                                                                                                                          When I say “associated function” I mean that in the most basic sense: it simply does something with the data, regardless of how the code is organised, named, etc.

                                                                                                                                          If you think about this questions and find clear answers for them, you will realize that there is absolutely no reason to make functions have all sorts of tricky behaviours based on state or even “belonging to an instance”. At which point the concept of class becomes pointless.

                                                                                                                                          I’m not sure what tricky behaviour have to do with anything. That just seems like you’re inventing problems to justify your arguments.

                                                                                                                                          even “belonging to an instance”

                                                                                                                                          Perhaps this comes as a surprise, but this exists in functional programming too. For example, if you have a String module with a to_lowercase() function, and that function only operates on strings, then that function basically “belongs to an instance”. How exactly you store that function (in the instance, elsewhere, etc) doesn’t matter; the concept is the same. Whether the data is mutable is also completely unrelated to that, as you can have OOP in a completely immutable language.

                                                                                                                                          Relational algebra was developed with solid theory behind it. To my knowledge, OOP was just something thrown together “because it is a good idea”.

                                                                                                                                          I suggest you do some actual research into the origins of OOP, instead of spewing nonsense like this. It’s frankly embarrassing.

                                                                                                                                        2. 4

                                                                                                                                          Have you ever stumbled upon good OOP code that actually looked OOP?

                                                                                                                                          I haven’t. The good code I’ve seen was inevitably a mix of procedural, modular, and functional code, with a heavy slant towards either procedural or functional, with maybe a couple instances of inheritance, for polymorphism’s sake (and even then, sometimes we just pass functions directly).

                                                                                                                                          The most distinguishing characteristic I see in OOP is how it stole almost every features to other paradigms or languages. ADT, encapsulation? Modular programming, from Modula. Generics? Parametric polymorphism from ML and Miranda. Lambdas? From every functional language ever. The only things left are inheritance, which was added in Simula to implement intrusive lists (which were needed because there was no C++ like templates), and subtype polymorphism, which is often better replaced by good old closures.

                                                                                                                                          And guess what, inheritance is now mostly discouraged (we prefer composition). The only thing left is subtype polymorphism. OOP is an empty husk, that only survives by rebranding other programming styles.

                                                                                                                                          1. 2

                                                                                                                                            ADT, encapsulation? Modular programming, from Modula.

                                                                                                                                            ADTs come from Barbara Liskov’s CLU, which cites Simula’s inheritance as inspiration.

                                                                                                                                            1. 1

                                                                                                                                              Hmm, didn’t know, thanks. I looked Modula up as well, it seems both languages appeared at rather the same time.

                                                                                                                                            2. 1

                                                                                                                                              Have you ever stumbled upon good OOP code that actually looked OOP?

                                                                                                                                              This depends on what one would consider OOP, as the opinions/interpretations differ. Have I seen good OOP? Yes. Was that Java-like OOP as I would imagine most people think OOP is like? No. But just because something is OOP doesn’t mean it can’t have elements from other paradigms.

                                                                                                                                              The most distinguishing characteristic I see in OOP is how it stole almost every features to other paradigms or languages. ADT, encapsulation? Modular programming, from Modula. Generics? Parametric polymorphism from ML and Miranda. Lambdas? From every functional language ever

                                                                                                                                              Ah yes: functional languages invented everything, and every other language using elements from this is “stealing” them.

                                                                                                                                              I’m honestly not sure what point you’re trying to make. X sharing elements with Y doesn’t mean somehow X isn’t, well, X. Just as how X having flaw Y doesn’t completely invalidate X. Having such a single minded (if that’s the right term) attitude isn’t productive.

                                                                                                                                              1. 3

                                                                                                                                                Ah yes: functional languages invented everything, and every other language using elements from this is “stealing” them.

                                                                                                                                                Not just functional. Modules did not come from functional languages, that I recall.

                                                                                                                                                To some extent though, yes: functional languages invented a lot. Especially the statically typed ones, whose inventors realise this fundamental truth that often gets me downvoted in programming forums if I voice it: that programming is applied mathematics, and by treating it as such we can find neat ways to make programs better (shorter, clearer, or even faster). Dijkstra was right. Even Alan Kay recognises now through his STEPS project that “math wins”. (Of course, it’s very different from calculus, or most of what you were taught in high school. If anything, it’s even more rigorous and demanding, because at the end of the day, a program has to run on a dumb formal engine: the computer.)

                                                                                                                                                I’m honestly not sure what point you’re trying to make.

                                                                                                                                                That to many OOP proponents, “OOP” mostly means “good”, and as we learn how to program better over the decades, they shift the definition of “OOP” to match what they think is good. It takes a serious break, like data oriented programming, to realise that there are other ways. To give but an example: back in 2007, I designed some over-complicated program in C++, with lots of stuff from the <algorithm> header so I could pretend I was using OCaml (I was an FP weenie at the time). My supervisor look at the code (or maybe I was outlying my design to them, I don’t remember), and said “well, this is very OO and all, but maybe it’s a bit over-complicated?”

                                                                                                                                                That’s how pervasive OOP is. Show a programmer functional patterns (with freaking folds!), they will see OOP.

                                                                                                                                                OOP is no longer a paradigm. It devolved into a brand.

                                                                                                                                            3. 2

                                                                                                                                              But eventually those data structures are going to need a bunch of associated functions. And then you pretty much have a class.

                                                                                                                                              Running in the risk of taking your quote out of context, I think the mindset OOP is simply data structures with encapsulated functions is actually one of the biggest real dangers of OOP, because it hides its biggest flaw: pervasive proliferation of (global) states.

                                                                                                                                              Thus, I understand where you are leading your argument, but I disagree with it.

                                                                                                                                              As an aside, every time I see a quote from Dijkstra I can’t help but feel this man must have been absolutely insufferable to work with. Yes, he was very smart and made many contributions. But holy moly, his “I am right and everybody else is wrong” attitude (at least that’s how it comes across to me) is off putting to say the least.

                                                                                                                                              I happen to know a lot of people who directly worked (or had classes) with him, and unanimously I hear both adjectives: genius and pretentious.

                                                                                                                                              Of course those are just others’ opinions, not mine, but I share your (and those people) feelings.

                                                                                                                                              1. 1

                                                                                                                                                Running in the risk of taking your quote out of context, I think the mindset OOP is simply data structures with encapsulated functions is actually one of the biggest real dangers of OOP, because it hides its biggest flaw: pervasive proliferation of (global) states.

                                                                                                                                                I agree a lot of OOP languages/projects suffer from too much (global) mutable state. But I’m not sure if that’s necessarily due to OOP. I think this is a case of “correlation is not causation”. Perhaps a silly example: if functional languages had mutable state, I think they would have similar issues. In other words, I think the issue is mutability being “attractive”/tempting, not so much the code organisation paradigm.

                                                                                                                                                Another example: I think if you take away the ability to assign non-constant types (basically anything but an int, float, string, etc) to constants/globals, and maybe remove inheritance, you already solve a lot of the common issues seen in OOP projects. This is basically what I’m doing with Inko (among other things, such as replacing the GC with single ownership).

                                                                                                                                                I do think for such languages we need a better term for the paradigm. Calling it X when it mixes properties from A, B, and C is confusing. Unfortunately, I haven’t found a good alternative term.

                                                                                                                                              2. 2

                                                                                                                                                I view OOP as an organizing principle—when you have few types, but lots of actions, then procedural is probably the way to organize the program (send the data to the action). When you have a few actions, but lots of types, then OOP is the way to organize the program (send the action to the data). When you have few actions, few types, then it doesn’t matter. It’s that last quadrant, lots of types, lots of actions, there is currently no good method to handle.

                                                                                                                                                1. 2

                                                                                                                                                  When you have X types and Y actions, unless you have many of both, I believe your program is already mostly organised. Many types and few actions? It will end up looking OOP even if you write it in C. Few types and many actions? It will end up looking procedural even if you write it in Java.

                                                                                                                                              1. 38

                                                                                                                                                One tidbit I found interesting in the April 2021 update is this (paraphrased for brevity)

                                                                                                                                                After only three weeks of having a Discord server, we have over 1,400 members, ten times as many as we’ve ever had in the IRC channel. This led to a ton of new development projects.

                                                                                                                                                I think this says a lot about IRC, the ease of use of Discord, and disproves the notion that eager contributors are willing to overcome any friction necessary to participate in a given community. While I’m hopeful that Matrix will eventually supplant Discord as the chat-platform-of-choice for open source software projects, it’s still nice to hear that SerenityOS was able to pull in more interested folks by using Discord.

                                                                                                                                                1. 11

                                                                                                                                                  I’m just very very glad people aren’t using Slack. Discord is at least made by people who understand the idea that harassment exists and therefore haven’t deliberately left out table-stakes features like letting one individual block messages from another.

                                                                                                                                                  1. 4

                                                                                                                                                    Slack assumes it’s an HR issue and that if you’re working with someone who’s harassing you, you have bigger problems (and solutions) to the issue.

                                                                                                                                                    1. 12

                                                                                                                                                      That’s their excuse, and it’s shit.

                                                                                                                                                      Aside from that, it’s wildly inappropriate for places where you don’t have HR, such as communities with open admission.

                                                                                                                                                      1. 6

                                                                                                                                                        That’s not what slack is for. Don’t use slack for that.

                                                                                                                                                        1. 6

                                                                                                                                                          Yeah, I agree, just relaying the excuse. Slack outside of closed-room workspaces feels awkward to me.

                                                                                                                                                    2. 4

                                                                                                                                                      I think one issue with Matrix is the lack of a good, stable and accessible client. Element is probably the easiest to start with, and it’s still confusing to use. Discord at least nailed that: it’s easy to invite people, group related channels, etc.

                                                                                                                                                    1. 53

                                                                                                                                                      Here’s two things I noticed about this benchmark:

                                                                                                                                                      1. A minor issue, but the Go program has a data race. The i loop variable is captured in the spawned goroutines while it is mutated by the outer loop. Fixing it doesn’t change the results of the program. It’s also immediately caught when built with the -race flag. Rust being data race free by construction is a super power.

                                                                                                                                                      2. Changing the amount of spawned goroutines/threads to 50,000 has a noticeable difference between the two on my machine. The Go program still completes in a timely fashion with ~5x the rss and no negative impacts on the rest of my system:

                                                                                                                                                      real 11.25s
                                                                                                                                                      user 41.49s
                                                                                                                                                      sys  0.70s
                                                                                                                                                      rss  135136k
                                                                                                                                                      

                                                                                                                                                      but the Rust version immediately causes my system to come to a crawl. UIs stop responding, audio starts stuttering, and eventually it crashes:

                                                                                                                                                      thread 'main' panicked at 'failed to spawn thread: Os { code: 11, kind: WouldBlock, message: "Resource temporarily unavailable" }', src/libcore/result.rs:1189:5
                                                                                                                                                      note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
                                                                                                                                                      Command exited with non-zero status 101
                                                                                                                                                      real 16.39s
                                                                                                                                                      user 23.76s
                                                                                                                                                      sys  98.50s
                                                                                                                                                      rss  288132k
                                                                                                                                                      

                                                                                                                                                      So while it may not be significantly lighter than threads as far as this one measure is concerned, there is definitely some resource that threads are taking up that goroutines are not. I checked on some production monitoring systems to see how many active goroutines they had, and they were sitting comfortably in the 20-30k area. I wonder if they were using threads how they would fare.

                                                                                                                                                      1. 8

                                                                                                                                                        Rust being data race free by construction is a super power.

                                                                                                                                                        Well, it also necessarily prohibits entire classes of useful and productive patterns… it was a design decision, with pros and cons, but certainly not strictly better.

                                                                                                                                                        1. 4

                                                                                                                                                          Strong plus +1. I wish, for application development, it was possible to remove lifetimes, borrow-checker and manual memory management (which are not that useful for this domain) and to keep only fearless concurrency (which is useful even (more so?) in high-level languages). Alas, it seems that Rust’s thread-safety banana is tightly attached to the rest of the jungle.

                                                                                                                                                          1. 7

                                                                                                                                                            FWIW. Ponylang has exactly this:

                                                                                                                                                            • no lifetimes, data is either known statically via simple escape analysis or traced at runtime
                                                                                                                                                            • no borrow checker, although it does have a stricter reference capability system
                                                                                                                                                            • no manual memory management: uses a deterministically invoked (excluding shared, send data) Mark-and-no-sweep GC
                                                                                                                                                            • has the equivalent Send and Sync traits in its reference capability system which provide the same static guarantees

                                                                                                                                                            As with everything though it has its own trade offs; Whether that be in its ref-cap system, lack of explicit control in the system, etc.

                                                                                                                                                        2. 4

                                                                                                                                                          To prevent that Rust error, I believe you need to change vm.max_map_count: https://github.com/rust-lang/rust/issues/78497#issuecomment-730055721

                                                                                                                                                          1. 4

                                                                                                                                                            That seems to me like the kind of thing Rust should do to some extent on its own!

                                                                                                                                                          2. 3

                                                                                                                                                            I’d be interested to see how many threads ended up scheduled with the Go example. My guess is not many al all: IIRC the compiler recognizes those sleeps as a safe place to yield control from the goroutines. So I suspect you end up packing them densely on to threads.

                                                                                                                                                          1. 2

                                                                                                                                                            I use a Gergoplex. I’ve gone through various keyboards over the years, but this is an entirely different level. The switches are super sensitive compared to MX Browns, which definitely takes some getting used to, but it’s less tiring on the fingers.