Threads for jonahx

  1. 6

    Because capabilities are linear, they are not copyable.

    Capabilities were originally studied in the Cartesian-closed context, where they are copyable. Today, cryptographic capabilities, which are difficult-to-guess (“unguessable”) rather than unforgeable or uncopyable, are commonplace.

    Capabilites are, by default, irrevocable.

    This isn’t a limitation, but a good design choice. Revoking any sort of built-in capability is something that must be done via runtime API, rather than inside user code; users can build revocable tokens themselves using a single mutable cell, and Capability Myths Demolished claims that this pattern was known in 1974, around the time of the Lambda Papers.

    Every programming language needs a escape hatch. When interacting with the outside world, you have to do unsafe things.

    One of the goals of E was to show that this isn’t true. In Monte, a flavor of E that I helped build, there are no escape hatches; every foreign and unsafe feature of the outside world is carefully given a handcrafted wrapper, a process known as taming. We didn’t implement FFI. Network access, filesystem access, system timers and clocks, cryptographic routines, subprocessing, even examining caught exceptions was privileged, and capabilities have to be explicitly imported. The least safe thing in the prelude was access to the unit-test and benchmark runners!

    1. 1

      I want some kind of capability system for JS so bad…. just… by default don’t let code do anything and I have to explicitly pass in (or otherwise grant) capabilities for network access, fs access, etc. Even a rough, flawed system would be a huge boon. Do you have any recommendations?

      1. 2

        You want to search for “Secure ECMAScript”, often just called SES. E’s authors have been steadily improving ECMAScript for nearly a decade, too. Outside of SES, common style improvements are actually also capability-safety improvements: Use modules, freeze immutable objects, ponder WeakMap, etc.

        1. 1

          There was Caja developed by Mark Miller at Google. I gather it failed because it was too difficult to tame the browser APIs into a capability-secure subset.

          1. 1

            That’s part of the elevator pitch for Deno.

            1. 2

              Deno’s permissions seem to be too coarse to me. AIUI they apply to the entire program, so they don’t help with things like restricting third party libraries.

              1. 1

                I agree, but it’s an important first step.

                I’m not a JS expert, but given how dynamic it is, it might not be possible to create and enforce real capabilities in it (that sort of concern was raised in the article too.)

        1. 66

          * for some stuff[1]

          i am the creator of htmx & obviously glad to see it get some attention, but I also don’t want to overpromise what it can achieve. I think it makes a lot more possible in within the hypermedia paradigm of the web but, of course, there are times when it’s the right choice and times when it isn’t.

          i have been working on a free book on hypermedia-based systems with a few other authors here:

          https://hypermedia.systems

          [1] - https://htmx.org/essays/when-to-use-hypermedia/

          1. 2

            I don’t get why htmx allow other http verb than GET and POST. from my point of view it add a layer of complexity without real benefit.

            1. 13

              Are you saying DELETE and PUT should be replaced by POST? The idempotence property of these operations would be lost if you did that.

              1. 6

                Yes. Other verbs are a waste of effort. They don’t benefit anything and it adds another design decision you don’t need to make.

                1. 1

                  I would say that in 99% (or more) of the existing http request DELETE and PUT are replaced by POST, and using something different is likely to break something, for little benefit

                  for exemple if you make two DELETE which should be idempotent and that your backend doesn’t treat them in a non idempotent way, your app is suddenly having a bug which can be hard to reproduce.

                  1. 17

                    Not sure I get your point. If your backend is treating deletes as not idempotent you’re already wrong. And deletes in particular seem like a quite easy to make idempotent, just check if it has been deleted already before deleting.

                2. 11

                  Being limited to get and post was the biggest mistake forms ever made and held the web back for years with shitty hacks like ?_method=DELETE

                  1. 4

                    What does it mean to delete something? Should I use DELETE if it’s a soft delete? What if can be undone for three hours? What if it deletes one thing but adds an audit record somewhere else?

                    DELETE adds nothing. The point is “can an intermediary cache this?” If yes then use GET. If not, POST.

                    1. 2

                      But then how are you going to indicate a delete action? Just make up something to stuff in the post body? How is that any better?

                      1. 1

                        URL paths are function names. The arguments to a GET function are query parameters. The arguments to POST functions are a JSON body (or form fields if you’re doing AJAX). You make up requests and responses that fit the domain instead of assuming everything is a resource with the same verbs. I’m also against putting resource IDs into URLs for APIs (you can do it for stuff end users see to make the URLs pretty, but not for APIs).

                        1. 10

                          URL paths are function names.

                          What does the R stand for

                          1. 11

                            clearly the R stands for RPC ;)

                            1. 2

                              Right tool for the job.

                            2. 6

                              You make up requests and responses that fit the domain instead of assuming everything is a resource with the same verbs.

                              Aren’t you just stating that you prefer RPC, without actually engaging with the argument for hypermedia?

                              The argument is that “Uniform Interface Constraint” (resources with a standard set of methods) allows you to make general clients that can interact with your resources with no out of band information (like API docs), a la web browsers + html.

                              Admittedly, what you describe is, in fact, how the majority of most APIs today work, and there is an interesting discussion about why that is if hypermedia supposedly has so many advantages.

                              I think your argument would be more interesting if you stated why you think that goal doesn’t have value, especially given that the web itself works that way, that it solves problems like API versioning, and so forth.

                              I’m also against putting resource IDs into URLs for APIs

                              Why do you not like this specifically, out of curiosity? What do you prefer?

                              1. 1

                                Second question first, resource IDs belong in query parameters. HTTP has many overlapping ways of sending data from client to server and server to client. The client can send information as a method verb, a URL path, a query parameter, a header, or a request body. There has to be some system to organize the arbitrary choices. The system is:

                                • Verb is for read vs write.
                                • URL path is the function to call.
                                • Query parameters are the arguments to reads. Bodies are the arguments to writes.
                                • Header is for authentication.

                                IDs are prettier in the URL path, but for an API, that doesn’t matter. You just need a convention that is easy to follow.

                                As for Hypermedia, I just care that the website is good for users and developers. Whatever the theory is behind it isn’t very important. It’s great that web browsers are universal tools, but that’s true for JSON APIs too, so “hypermedia-ness” only matters if it makes development easier or harder. I think probably HTMX is easier for most web apps, so that’s why I like it. Even then, I’m more partial to Alpine.JS because I feel like the core motivation for a lot of the HTMX partisans is just wanting to avoid learning JS.

                                1. 2

                                  Thanks for explaining.

                                  I feel like the core motivation for a lot of the HTMX partisans is just wanting to avoid learning JS.

                                  I know this is a selling point, but fwiw I have a lot of JS experience, consider myself good with it, have used React and other similar frameworks, but still like the simplicity of the old MPA model – htmx being for me just an upgrade. Having just the single data model of the resources on the server to think about it.

                                  The system is:….

                                  Agree with your point about “overlapping ways of sending data from client to server,” and also agree that having any clear system is more important than “the best system,” if there is one. I guess I’m not seeing why the classic system of “url path to describe resource”, “http verb to describe action” is not good enough… It can be stilted and noun-y, yes, but imo that’s not enough reason to throw away a perfectly good existing “system,” as it were.

                                  1. 1

                                    I don’t like the classic “everything is a noun” system because it ends up needing a lot of requests to get anything done, and requests are the slowest thing you can do with a computer.

                                    I’m working with the MailChimp V3 API this week, and to send a campaign takes three requests: 1. Create campaign 2. Set content 3. Send. In MailChimp API V2, it’s a single request, but they’re finally shutting it down at the end of the month, so I’m being forced to make the change. Because it’s three requests instead of one, I probably need to put it into a queue now because it won’t be reliably fast enough to get done in one request for my users, so now I have to deal with all the complications of asynchrony, and for what? The old API was better.

                                    1. 1

                                      Seems like a reasonable complaint but orthogonal to the naming/noun-ness of the system. They could continue to support the version you prefer with something like POST “api.mailchimp.com/one-shot-emails” or “outbox” or whatever. That is, from a pure naming persepective, you can always transform back and forth between the two systems.

                                      To your point, classic REST typically has aggregate endpoints return a list of ids, and then you have to make requests (possibly parallel) to each id resource to get the details, which is cumbersome. But nothing forces you to follow that if it doesn’t suit your use-case.

                              2. 3

                                I call this “BrowserTP” since it’s a squished down version of HTTP based on what browsers supported in the early 00’s.

                                I would say thusly: HTTP is an RPC protocol where the method name (or function or procedure name if you wish) is the method (sometimes called the verb). The URL path is the object that you are calling the method on. The arguments are query string + body as you say.

                                And sure I can say “please create a deletion for the element in this collection with id 1” it’s not wrong per se, but why wouldn’t I just say “please delete element 1”

                        2. 7

                          because those are part of the HTTP spec and have reasonable meanings useful for implementing resource-oriented url schemes:

                          DELETE /comments/33

                          vs

                          POST /comments/33/delete

                          1. 2

                            I agree that they aren’t really useful, but it takes very little effort for the author to add them and a lot of people want them.

                            Aside from the obviously minor difference of sending POST /thing/delete vs DELETE /thing, other HTTP verbs can introduce additional overhead with CORS:

                            Additionally, for HTTP request methods that can cause side-effects on server data (in particular, HTTP methods other than GET, or POST with certain MIME types), the specification mandates that browsers “preflight” the request, soliciting supported methods from the server with the HTTP OPTIONS request method […]

                            - MDN: Cross-Origin Resource Sharing (CORS)

                            1. 3

                              I was going to argue the opposite with approximately the very same line quoted. If you and your webapp rely on the browser for some of the protection against some level of cross-site request forgery attacks, you can use the verbs as they were intended and rely on the browser to enforce them to be usable according to CORS rules.

                              Guess why https://fetch.spec.whatwg.org/#forbidden-header-name lists the X-HTTP-Method-Override header (and friends) to forbidden headers in CORS? Lots of vulnerable web pages, that’s why :(

                              1. 1

                                CORS still works with GET and POST, it just doesn’t require multiple requests.

                            2. 2

                              I disagree, they actually simplify things by disentangling POST from update and deletion actions.

                              Edit: in other words, they add a couple terms to our vocabulary…I don’t see how they add an entire layer.

                              1. 1

                                layer is maybe a wrong term (i’m french)

                                i want to say that it add complexity: if you have a reverse proxy, it has to support the new verbs, if you have logs it should be aware of this verbs, if you have something in your infrastructure which used to ignore DELETE, and suddenly support it, it suddenly delete unwanted things

                          1. 40

                            If all the author needed was a blog, maybe the problem is that his tech stack is way too big for his need? A bunch of generated HTML file behind a Nginx server would not have required this amount of maintenance work.

                            Is the caching of image at the edge really necessary? So what if it take a little while to load them. Just by not having to load a front end framework and making 10 API call before anything is displayed, the site will already load faster than many popular site.

                            If the whole point is to have fun and learn stuff, the busy work is the very point of course. Yet all this seems to be the very definition of non value added work.

                            1. 13

                              At the end he says

                              I know that I could put this burden down. I have a mentor making excellent and sober use of Squarespace for his professional domain - and the results look great. I read his blog posts myself and think that they look good! It doesn’t have to be like this. […]

                              And that’s exactly why I do it. It’s one of the best projects I’ve ever created.

                              So I think the whole point is to have fun and learn stuff.

                              1. 7

                                Inventing your own static site generator is also a lot of fun. And because all the hard work is done outside the serving path, there’s much less production maintenance needs.

                                1. 14

                                  Different people find different things fun

                                  1. 1

                                    IMO if you do it right, inventing your own static site generator is only fun for about half a day tops. Because it only takes a couple hours. :)

                                    1. 2

                                      Not if you decide to write your own CommonMark compliant Markdown parser :]

                                      1. 2

                                        Pandoc is right there.

                                        1. 1

                                          I’ve been seriously considering dropping Markdown and just transforming HTML into HTML by defining custom tags. Or finally learning XSLT and using that, and exposing stuff like transforming LaTeX math into MathML via custom functions.

                                  2. 9
                                    • Node.js or package.json or Vue.js or Nuxt.js issues or Ubuntu C library issues
                                    • CVEs that force my to bump some obscure dependency past the last version that works in my current setup
                                    • Debugging and customizing pre-built CSS frameworks

                                    All of these can be done away with.

                                    I understand that the point may be to explore new tech with a purposefully over-engineered solution, but if the point is learning, surely the “lesson learned” should be that this kind of tech has real downsides, for the reasons the author points out and more. Dependencies, especially in the web ecosystem, are often expensive, much more so than you would think. Don’t use them unless you have to.

                                    Static html and simple CSS are not just the preference of grumpy devs set in their ways. They really are easier to maintain.

                                    1. 5

                                      There’s several schools of thought with regards to website optimization. One of them is that if images load quickly, you have a much lower bounce-rate (or people that run away screaming), meaning that you get more readers. Based on the stack the article describes, it does seem a little much, but he’s able to justify it. A lot of personal sites are really passion projects that won’t really work when scaled to normal production workloads, but that’s fine.

                                      I kinda treat my website and its supporting infrastructure the same way, a lot of it is really there to help me explore the problem spaces involved. I chose to use Rust for my website, and that seems to have a lot less ecosystem churn/toil than the frontend ecosystem does. I only really have to fix things when bumping packages about once per quarter, and that’s usually about when I’m going to be improving the site anyways.

                                      There is a happy medium to be found, but if they wanna do some dumb shit to see how things work in practice, more power to them.

                                      1. 4

                                        A bunch of generated HTML file behind a Nginx server would not have required this amount of maintenance work.

                                        Sometimes we need a tiny bit more flexibility than that. To this day I don’t know how to enable content negotiation with Nginx like I used to do with Apache. Say I have two files, my_article.fr.html, and my_article.en.html. I want to serve them under https://example.com/my_article, English by default, French if the user’s browser prefers it over English. How do I do that? Right now short of falling back to Apache I’m genuinely considering writing my own web server (though I don’t really want to, because of TLS).

                                        This is the only complication I would like to address, it seems pretty basic (surely there are lots of multilingual web site out there), and I would have guessed the original dev, not being American, would have thought of linguistic issues. Haven’t they, or did I missed something?

                                        1. 4

                                          Automatic content negotiation sucks though? It’s fine as a default first run behavior, but as someone who lived in Japan and often used the school computers, you really, really need there to also be a button on the site to explicitly pick your language instead of just assuming that the browser already knows your preference. At that point, you can probably just put some JS on a static page and have it store the language preference in localStorage or something.

                                          1. 1

                                            There’s a way to bypass it: in addition to

                                            https://example.com/my_article
                                            

                                            Also serve

                                            https://example.com/my_article.en
                                            https://example.com/my_article.fr
                                            

                                            And generate a bit of HTML boilerplate to let the user access the one they want. And perhaps remember their last choice in a cookie. (I would like to avoid JavaScript as much as possible.)

                                            1. 1

                                              If JS isn’t a deal breaker, you can make my_article a blank page that JS redirects to a language specific page. You can use <noscript> to have it reveal links to those pages for people with JS turned off.

                                            2. 1

                                              Browsers have had multiple user profiles with different settings available, for more than a decade now (in the case of Firefox I distinctly remember there being a profile chooser box on startup in 2001–2).

                                              1. 2

                                                Which is fine if you can actually make a profile to suit your needs. If you cannot make a profile, you are stuck with whatever settings the browser has, and you get gibberish in response as you might not understand the local language.

                                                1. 1

                                                  Look, the browser is a user agent. It’s supposed to work for the user and be adaptable to their needs. If there are that many restrictions on it, then you don’t have a viable user agent in the first place and there’s nothing that web standards can do about that.

                                                2. 1

                                                  The initial release of Firefox was 2004. Did you typo 2011 or mean one of its predecessor browsers?

                                                  1. 2

                                                    Yeah I’m probably thinking of Phoenix.

                                              2. 3

                                                There’s no easy way, AFAIK - you either run a Perl server to get redirects or add an extra module (although if you were doing that, I’d add the Lua module which gives you much more freedom to do these kinds of shenanigans.)

                                                1. 1

                                                  Caddy allows you to match HTTP headers, and you can probably achieve what you want with a bunch of horrible rewrite rules.

                                                  You can always roll your own HTTP server and put it behind Caddy or whatever TLS-capable HTTP server.

                                                  1. 1

                                                    You could put Apache behind Nginx; I’ve done that before, and I might do it again.

                                                    • I prefer nginx for high load; it’s great with static files.
                                                    • apache config for some things - redirects, htaccess, I think? - feels easier.

                                                    It’s been quite a while since I delved in on these.

                                                1. 4

                                                  It seems like there is real tension between the goals of supporting accessibility and supporting noscript.

                                                  1. 1

                                                    If you need widgets that HTML doesn’t have, there is indeed. However, progressive enhancement can resolve the tension (put the CSS-only widget in the HTML, then have JS find it and replace it with a properly implemented one). The problem then is layout shift.

                                                  1. 25

                                                    Great big shit always starts life as a demo

                                                    And every Einstein was once a child..

                                                    All you crazy MFs are completely overlooking

                                                    <Rant mode disengaged… but lurking>

                                                    Suggesting rant

                                                    So apparently sourcegraph is the solution to all modern Coding-AIs because it allows them to faster steal index real sourcecode, such that they become better at their job. And apparently we’re just witnessing a second coming of christAWS/google, and all these AIs need is the global sourcecode, and then they’re good enough for most things. (See: must only be better than the human coder)

                                                    I’ll tell you what: Yes I am fearing the day that people think they can just throw random bullshit at some coding AI and run what ever comes out of that. Because most people don’t even know what they want. It’s not about “write me a program that prints out a character highlighted”. It’s about what do I need to make an application, that does X, including the backend, frontend, database (which one? how many? seach?), to decisions possibly changing the exact goal.

                                                    I seriously hope this whole AI wave dies down as quickly as it came. It looks like I’m becoming the “old man yells at cloud”, before even getting old. If anything I can see AI shifting the slogan “there is always someone better at it on the planet” to “there are always 200 AIs doing it faster and better”. Faust will have a field day with the existential crisis of humans after the AI subscription arrived. Maybe in ten years we will look back at AI, in the same way many people do think that brain reading or changing should never become a thing. Wall-E wasn’t a role model.

                                                    1. 9

                                                      I think of AI in the same way I think of OOP and FP. They both came with big hype waves that said that they’d completely transform the industry. They both provided a set of tools that, now, are so embedded in most project that you’d barely even think of them as part of a change that happened in the past. They both had a lot of over-enthusiastic companies adopt them in totally inappropriate situations and end up with complete monstrosities.

                                                      1. 4

                                                        I seriously hope this whole AI wave dies down as quickly as it came…. Maybe in ten years we will look back at AI, in the same way many people do think that brain reading or changing should never become a thing.

                                                        Slow train coming….

                                                        In addition, I keep thinking about the wonderful short documentary “Farewell - ETAOIN SHRDLU”.

                                                        We – in our current incarnations, at least – are the linotype operators. Make no mistake.

                                                        1. 3

                                                          Except we’re not replacing one process with another. We’re replacing everything where we thought we needed a human, or we could make their job easier, with something trained by BigCorp (at least they want to sell us that). Be it creativity, problem solving, interaction or knowledge. The only limit is our limited rare-earth elements, preventing any further chip development at one point. Coding is the easy starting point, because it’s already a digital thing. But that’s just a starting point. Meanwhile people in Japan are trying to build comforting robots for the elderly. Anyone who thinks that people will have less to work by that is blind. You will have to work harder, to make up for all the stuff the AI can do. (see service industry) And you won’t be the one owning the AIs. You’ll just pay subscriptions to use them.

                                                          And just in case: I do not fear anything called “singularity”. We don’t need that to touch ethically very questionable grounds. At least an AI post-singularity isn’t a mindless robot simulating a conversation. I can already see the people with para social relationships (to youtubers & co) sinking their time into ChatGPTBots.

                                                          1. 3

                                                            I was arguing neither the pro nor con case for dystopia. I think dystopia is a distinctly possible outcome.

                                                            But I think it’s a forgone conclusion this is happening, and the industry as we know it will be upended. Basically, Yegge’s take on the “meh” crowd is spot on.

                                                            1. 9

                                                              But I think it’s a forgone conclusion this is happening, and the industry as we know it will be upended. Basically, Yegge’s take on the “meh” crowd is spot on.

                                                              We just spent the past few years being told exactly this about blockchains and cryptocurrencies. The world was going to be completely upended! The skeptics better have fun staying poor, because they’re ngmi! But it turned out to be a bunch of slick marketing hype and no real lasting use case (and that’s the charitable version), and the whole thing collapsed.

                                                              So. Here you are, and here Steve Yegge is, and both of you are making the same mouth noises that the blockchain/crypto people were making. Why should your mouth noises be treated as more reliable then theirs were? Especially since many of the people pouring money and marketing into this are the same people who poured money and marketing into the blockchain/crypto stuff?

                                                              1. 6

                                                                There is a very, very big difference:

                                                                I can actually use this product, and see with my own eyes that it can do many things I spent years learning how to do well, instantly. Writing prose and writing code, to name the big ones. No, it’s not perfect, but it works, right now. I already use it. I already can’t imagine going back.

                                                                Fwiw, I was not a crypto booster, I prefer old, boring technology, and am not happy that my skills just got devalued.

                                                                1. 4

                                                                  People told me cryptocurrencies had use cases that they were using right then and there. Fast, low-fee money transfers! Decentralized lending! Decentralized investing! Banking the unbanked! It’s a revolution!

                                                                  So. Once again, you’re making the same noises they were. What’s different?

                                                                  Or, let’s just shortcut to the end of the argument: I’ve been in and around tech for decades, and my experience is that the thing being hyped from all corners as the inevitable any-day-now revolution… basically never is. This is because genuine world-changing revolutionary things don’t need to be hyped and marketed – they just need to be.

                                                                  1. 1

                                                                    This is because genuine world-changing revolutionary things don’t need to be hyped and marketed – they just need to be.

                                                                    It is the fastest growing product in history

                                                                    When I show it to non-technical people, they cannot believe it’s real.

                                                                    It seems that you aren’t evaluating the factual differences, but merely noticing a parallel in the rhetoric between two things (and that many people from crypto are also excited about this) that has convinced you both are pure hype.

                                                                    Fast, low-fee money transfers! Decentralized lending! Decentralized investing!

                                                                    I have never used any of these things and don’t know anyone who has. Tons of people I know, including non-technical ones, are using chatGPT

                                                                    I don’t think there’s much point in arguing more, time will tell who’s right. I’d be happy to make a friendly 5 or 10 year longbet about it if you can think of verifiable terms that would make sense to you, i.e., what in your mind would be evidence of your current position being wrong in the long term?

                                                                    1. 4

                                                                      When I show it to non-technical people, they cannot believe it’s real.

                                                                      When you show them a demo controlled by someone who is marketing/hyping it. And not telling them about all the ongoing issues with it, like just flat-out giving you wrong information with fake sources/citations, or flat-out wrong code, or…

                                                                      Again: real, really revolutionary stuff doesn’t need that kind of carefully controlled scenario by a person who’s invested in marketing it.

                                                                      I have never used any of these things and don’t know anyone who has. Tons of people I know, including non-technical ones, are using chatGPT

                                                                      And yet during the cryptocurrency boom there were huge numbers of posts insisting that adoption was going through hockey-stick exponential rises, that everyone was migrating to “DeFi” and other buzzwords, that you should move your money now before you miss out… and you know that. You would have to have been living not just under a rock, but literally out of range of all forms of communication technology for something like multiple years in order not to know that was going on.

                                                                      And here you are, marketing and hyping your revolutionary earth-shattering universe-changing thing exactly the way they marketed theirs. While all the more balanced evaluations are that it’s basically good at a couple parlor tricks, but starts showing its very real limitations very quickly once you try digging a little deeper into the “use cases” that are supposedly going to completely upend all of human society and industry overnight.

                                                                      If you don’t like the cryptocurrency analogy, here’s another one: I’ve been around long enough to remember when the Segway was going to completely change the way we design and use cities and totally upend and revolutionize transportation and transit forever.

                                                                      On average, being skeptical of anything hyped this much is a winning strategy. Not a perfect strategy, but winning on average, and I don’t think you can meaningfully rebut that.

                                                                      1. 1

                                                                        And here you are, marketing and hyping your revolutionary earth-shattering universe-changing thing exactly the way they marketed theirs.

                                                                        You are free to disagree with me, but not to accuse me of things that are entirely false. I have no connection with openai, I am not working on an AI startup, and I have no financial investments of any kind in AI. I am simply a user who is flabbergasted by what I see. I think it is telling that you feel the need to paint a genuine and organic reaction as “marketing and hyping”.

                                                                        When you show them a demo controlled by someone who is marketing/hyping it. And not telling them about all the ongoing issues with it,

                                                                        You are pulling these accusations out of thin air, just as you are lambasting chatGPT for doing. I have told every person I’ve shown it to that while it is useful, it cannot actually think, and will often make stuff up out of thin air.

                                                                        On average, being skeptical of anything hyped this much is a winning strategy. Not a perfect strategy, but winning on average, and I don’t think you can meaningfully rebut that.

                                                                        On average, yes. Just not in this case. You realize the internet had a lot of hype, too, right?

                                                                2. 2

                                                                  Sadly, you cannot necessarily tell the quality of an idea just from a reductive rephrasing of the mouth noises of its fans.

                                                                  1. 2

                                                                    Not necessarily, no, but it’s still a useful heuristic.

                                                                3. 4

                                                                  but just because we can, we shouldn’t stop asking if we actually should

                                                                  1. 2

                                                                    It’s not clear to me that the tech world is, or will ever be, ready to hear that

                                                              2. 1

                                                                If the AI boosters are right, we may soon be the linotypes.

                                                            1. 5

                                                              Surely there is an interesting new discussion of the nature of “rationality” happening somewhere, now that we have an example system that can “explain its chain of thought” in a (usually plausible) way when asked, that we know for a fact is entirely based on probabilistic associations between word fragment sequences and no specific “reasoning” mechanism. Does anyone know where to find this?

                                                              1. 7

                                                                It kinda goes the other way around. When prompted to reason step by step LLM answers are more accurate. If you ask afterwards it’ll start doing mental gymnastics to defend whatever answer it gave.

                                                                1. 2

                                                                  Interesting. I would have thought this commitment bias to be limited to humans. I would have thought ChatGPT rather immune to this, for I have seen it change its mind¹ rather easily when corrected.

                                                                  [1]: please forgive the anthropomorphism

                                                                  1. 8

                                                                    The model behind ChatGPT has been primed to do chain of thought reasoning. When asking complex question you’ll often notice it’ll first give an explanation and then the answer. The model didn’t think of the answer first and then thought it would be useful to lead with some introductory information, it’s how it gets to the answer in the first place.

                                                                    Furthermore, ChatGPT is not a chatbot whom you ask questions to, it is a text generator simulating a chat log. It takes quite a bit of postprocessing work to stop an LLM from completing the “human” part of the conversation. It’ll take what you say for granted because it doesn’t know the difference between what you type or what it generated, it’s all just text to complete. What you type becomes part of the reasoning, so to speak.

                                                                    I don’t think it’s too far fetched to draw parallels to human reasoning. When you go over an idea in your head you’re not doing deductive reasoning. Unlike LLMs though we can do that if we decide to, or we can test in the real world what we came up with, and we can generally tell the difference between things someone just told us and our own opinions and knowledge.

                                                                    1. 4

                                                                      It’s emulating a human’s commitment bias, because it was trained on examples that show commitment bias.

                                                                      1. 2

                                                                        I think it’s more because of how it works: it’s an autocomplete based on previous tokens, so when adding text after an answer, it already has it as a reference and it influences the prediction. Not that it causes itself to emulate humans explaining themselves, but rather that there are already topics and statements to talk about.

                                                                      2. 2

                                                                        Here’s an example I had of ChatGPT getting stuck on answer and doing a bad job of justifying it:

                                                                        Me: What has three legs in the morning, two legs in the afternoon, and four legs at night?

                                                                        ChatGPT: The answer to this classic riddle is “a human being.”

                                                                        The riddle is a reference to the stages of life. In the morning of life, which is considered to be childhood, a human crawls on hands and knees, hence having three “legs.” In the afternoon of life, which represents adulthood, a human walks upright on two legs. Finally, in the evening of life, which represents old age, a human may require the assistance of a cane, hence having four “legs.”

                                                                        This riddle has been around for centuries and was famously posed by the Sphinx in Greek mythology to travelers who sought to enter the city of Thebes. Oedipus was able to solve the riddle by answering “man,” causing the Sphinx to destroy itself in frustration.

                                                                        It’s not weird to get stuck on thinking I asked the riddle of sphinx when I didn’t, but it is weird (from a human POV) to misexplain the riddle.

                                                                        1. 5

                                                                          GPT4 seems to handle it:

                                                                          Me: What has three legs in the morning, two legs in the afternoon, and four legs at night?

                                                                          GPT4: This riddle is a variation of the famous riddle of the Sphinx from Greek mythology. The original riddle goes: “What has four legs in the morning, two legs in the afternoon, and three legs at night?” The answer to the original riddle is “a human being,” which refers to the stages of a person’s life. In the morning (infancy), a human crawls on all fours; in the afternoon (adulthood), a human walks on two legs; and at night (old age), a human walks with the aid of a cane, which represents the third leg.

                                                                          However, your riddle has a different sequence of leg numbers. While it may be an intentional twist on the original riddle, there isn’t a clear answer that fits the description.

                                                                          Me: What about Benjamin Button?

                                                                          GPT4: Ah, I see what you’re getting at. Benjamin Button is a fictional character from the short story “The Curious Case of Benjamin Button” by F. Scott Fitzgerald, which was later adapted into a movie. The character ages in reverse, being born as an old man and growing younger throughout his life.

                                                                          Using the Benjamin Button scenario in the context of your riddle, it could work as follows:

                                                                          In the morning (old age), Benjamin would have three legs, including a cane for support. In the afternoon (adulthood), he would have two legs, as he would no longer need the cane. At night (infancy), he would have four legs, because he would crawl like a baby.

                                                                          In this context, the answer to the riddle could be “Benjamin Button.”

                                                                          1. 3

                                                                            Humanity is doomed. :-)

                                                                            1. 2

                                                                              …well that’s alarming.

                                                                              1. 2

                                                                                Try prompting it with some other answers and see if it justifies them all

                                                                          2. 1

                                                                            Relatable.

                                                                          3. 7

                                                                            It’s a pretty old idea that humans spontaneously generate stories justifying their actions or beliefs on the spot instead of those pre-existing justifications motivating the action or belief. I think there’s a lot of credence to this idea, I often discover my own opinions about things in the course of writing them down in comments or blog posts or a journal or whatever else. Writing is nature’s way of letting you know how sloppy your thinking is and all that.

                                                                          1. 1

                                                                            I was thinking about settling on Rust for a web app, but I got stuck on the number of things that I would need to build from scratch or replace because they weren’t done right. For example, this project encrypts data into a cookie for sessions instead of putting a nonce session id in a cookie and keeping the necessary information on the server.

                                                                            I’m still debating whether I take the plunge and build this stuff out correctly or go use a mature stack like Spring.

                                                                            1. 4

                                                                              For example, this project encrypts data into a cookie for sessions instead of putting a nonce session id in a cookie and keeping the necessary information on the server.

                                                                              That is a standard practice for saving on database load, and depending on a few things (what you’re storing, strength of your secret, algorithm being used) doesn’t fall under a blanket “wrong” label. Not saying it’s right for every use case, but what were your specific concerns?

                                                                              1. 1

                                                                                It can’t save on database load, though, because I still have to check for session revocation.

                                                                                If I have to hit the database anyway, then on one hand I have keeping an encryption key secure and getting it deployed to my servers and making sure I get my crypto right. On the other hand I have generating a uuid or similar and sticking it in a cookie with no encryption necessary. One of these is drastically safer and less error prone than the other.

                                                                            1. 3

                                                                              … in the video, there’s text on his shirt, and it reads the correct way, and he writes in front of him, and it also reads the correct way, although he’s viewing the text from the opposite site that the viewer is viewing it from. If it’s correct for us, it’s backwards for him, and vice versa. Is he writing backwards, or did he get a backwards shirt specifically for this and flips the whole video?

                                                                              1. 3

                                                                                The shirt is printed backwards. He’s a righty, but appears to write with his left hand.

                                                                                1. 2

                                                                                  Yes, he’s writing backwards on a pane of glass.

                                                                                  1. 3

                                                                                    No, he just flips he video (as if using a mirror)… and has a backwards printed shirt.

                                                                                    1. 2

                                                                                      Funny, I just assumed because I’ve seen other people do it the backwards writing way. Getting the backwards printed just for this instead of a wearing a solid one is dedication.

                                                                                1. 4

                                                                                  I like the conclusion – don’t push away small ideas, don’t get discouraged, etc – but the leftPad story doesn’t strike me as an ideal homily for this lesson.

                                                                                  Meaning, had I been the author of leftPad (anyone on this site could have been) I would not have taken its use by millions as any kind of reflection of my impact or worth. It’s just a quirk of node culture, the happenstance of String not having something built in, and some coincidence of viral spread. That it was used by so many doesn’t actually change its worth in my eyes… I still wouldn’t be proud of the code or feel I had accomplished something meaningful with it.

                                                                                  Small things can lead to big things, meaningfully – “a journey of a thousand step starts with….”. Or maybe you will publish something that is meaningful to a small audience, or even one person. Or maybe you just need to publish it, to at least see, even if you fail to touch anyone else. Those seem like more substantial reasons not to feel insignificant.

                                                                                  1. 3

                                                                                    To me the funny thing about left-pad is the fact that it appears to have caused padStart to finally get added to the language. Turns out that at least one extremely high chaos way of influencing the tc39 committee does exist and work.

                                                                                  1. 2

                                                                                    I found myself nodding along to almost all but the first:

                                                                                    Browsing the source is almost always faster than finding an answer on StackOverflow.

                                                                                    Not only is this false some of the time, it is false the majority of the time, and it is even more false if we add ChatGPT to the mix. Some very large percentage of my questions during the day (easily over half) are answered immediately (between 20 and 60 seconds) by SO or, lately, ChatGPT. Source browsing, which I do regularly when needed, cannot compete with that.

                                                                                    1. 6

                                                                                      I posit that this is highly dependent on the popularity of the codebase in question. My experience for most tech is much closer to the original author’s.

                                                                                      I work on virtualisation, Qemu, device drivers on macOS/iPadOS, and the occasional bit of embedded development, and I have to be very lucky for something to be covered on SO. (In the case of DriverKit and related tech, I probably have seen 95%+ of tagged questions/answers, in part because I wrote a majority of the answers.)

                                                                                      But when it comes to shell scripting or sysadmin/devops type stuff, SO and its sister sites are extremely effective.

                                                                                      1. 1

                                                                                        Are you using ChatGPT to answer questions about code that isn’t on the open web? If so, I’m super curious how!

                                                                                        1. 1

                                                                                          My most frequent use-case is as a search assistant, a more efficient google. However, that makes it sound less game-changing than it is. For example, we use AWS, and I often need to write a script using the CLI to accomplish some task, which may be multiple commands across 1 or more services. Previously, this would require docs search / SO searching, and a simple task might take 20 minutes, simply because I am not familiar with the many sub-commands and options.

                                                                                          Now, I ask ChatGPT, and it will return a fully functional bash script doing exactly what I want. Yes, sometimes it requires a back and forth where I clarify things, but the total time is still much less and the experience is more pleasant.

                                                                                          questions about code that isn’t on the open web?

                                                                                          I am not sure what you mean, but it is not merely copy / pasting snippets. It will even respond to commands like “can you rewrite that in a more functional style” and so on. Of course, the domain of the questions is about things on the open web: AWS, JS, bash, etc.

                                                                                      1. 1

                                                                                        That was mesmerizing.

                                                                                        Even if you have no interest in voice control I recommend it just to witness this other kind of fluency.

                                                                                        1. 1

                                                                                          @hwayne, I have heard the “package resolution is NP complete” before. I don’t doubt that it’s true, but curious if have any references / further reading which explains what this means. I’m interested in it.

                                                                                          1. 4

                                                                                            So, for what this means in general, I think links in the end of the post should be a good overview. But the TL;DR version is

                                                                                            “dependency resolution is NP complete” means that, if you have an efficient (polynomial, something like O(n^20), rather than O(2^n)) algorithm for resolving dependencies, you can construct an efficient algorithm for solving boolean satisfiability (SAT), and efficiently solving that allows you to solve all kinds of hard problems in polynomial time.

                                                                                            We will prove that dependency resolution is NP complete constructively. Namely, we will show how to, given an arbitrary formula, construct a set of constraints for dependencies, which has a solution only if the given formula has a solution.

                                                                                            The precise formulation of SAT is given in the post. You have a logical formula like

                                                                                            (A or !B or C) and (D or E or F) and (!A or !E or !C)
                                                                                            

                                                                                            Each variable can be either true or false, and you are wondering if there’s a variable assignment which makes the whole formula true.

                                                                                            “dependency resolution” is a bit more vague, and actually depends on a specific package manager we are talking about. Indeed, some formulations of these problem can be solved efficiently. But most cases can’t.

                                                                                            In particular, Cargo’s version is definitely NP complete. Cargo has a rather rich language for specifying dependencies(https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html), but we’ll use a tiny subset here. Namely, we only allow exact version requirements, and we always will use 1.x.0 version (only minor version varies).

                                                                                            First, we have versions of packages, like A 1.0.0, A 1.1.0, B 1.2.0. Each version of the package specifies dependencies as version requirements. For example, A 1.0.0 can specify

                                                                                            B = "=1.0.0"
                                                                                            C = "=1.0.0, =1.1.0"
                                                                                            

                                                                                            This requirement means that, if we select A 1.0.0, wee must also select B 1.0.0 and either C 1.0.0 or C 1.1.0. That is, each package version can require a bunch of packages, and for each required package, it can require one of the specific versions.

                                                                                            Not that different versions of the same package can have different dependencies.

                                                                                            Now, here’s the actual dependency resolution problem: given the universe with different packages and versions, and a single root package version, is it possible to select a subset of package versions such that:

                                                                                            • root package version is selected
                                                                                            • dependencies of every selected package version are satisfied
                                                                                            • for each package, there’s at most one version selected (Cargo allows selecting package multiple times with different major versions, but our major versions are always fixed at 1)

                                                                                            ?

                                                                                            I claim that this problem is not easier than SAT. I will reduce an arbitrary SAT formula to our dependencies problem.

                                                                                            Let’s use (A or !B or C) and (!A or B) as our example formula.

                                                                                            First, for each variable (V), I make two package versions, V 1.0.0 and V 1.1.0:

                                                                                            A 1.0.0, A 1.1.0
                                                                                            B 1.0.0, B 1.1.0
                                                                                            C 1.0.0, C 1.1.0
                                                                                            

                                                                                            The semantics I am thinking about here is that A=true corresponds to selecting A 1.0.0, and A=false (!A) corresponds to A 1.1.0.

                                                                                            To the root package, I add a requirement for each variable: V = "=1.0.0, =1.1.0". This way, I model the requirement to assign true or false (but not both) to each variable.

                                                                                            Next, I create a package for each clause of the sat formula (clause is a bunch of (possibly negated) variables ored together. The whole formula is an and of a bunch of clauses. You can write arbitrary logic formula that way). If the clause consists of n variables, the corresponding package would have n versions. ith version would correspond to the case where the clause is true because its ith variable is true.

                                                                                            So for clause A or !B or C I create a package c1 with the following versions and dependencies:

                                                                                            c1 1.0.0:
                                                                                              A = "=1.0.0"
                                                                                            
                                                                                            c1 1.1.0:
                                                                                              B = "=1.1.0"
                                                                                            
                                                                                            c1 1.2.0
                                                                                              C = "=1.0.0"
                                                                                            

                                                                                            I can now say that, for each clause, my root package requires one of its versions.

                                                                                            All together, for (A or !B or C) and (!A or B) formula, I get the following set of packages:

                                                                                            // _the_ root package
                                                                                            root 1.0.0:
                                                                                              // variables
                                                                                              A = "=1.0.0, =1.1.0"
                                                                                              B = "=1.0.0, =1.1.0"
                                                                                              C = "=1.0.0, =1.1.0"
                                                                                              // clauses
                                                                                              c1 = "=1.0.0, =1.1.0, =1.2.0"
                                                                                              c2 = "=1.0.0, =1.1.0"
                                                                                            
                                                                                            A 1.0.0: // empty set of deps
                                                                                            A 1.1.0: 
                                                                                            
                                                                                            B 1.0.0: 
                                                                                            B 1.1.0: 
                                                                                            
                                                                                            C 1.0.0: 
                                                                                            C 1.1.0: 
                                                                                            
                                                                                            // first clause
                                                                                            c1 1.0.0:
                                                                                              A = "=1.0.0"
                                                                                            
                                                                                            c1 1.1.0:
                                                                                              B = "=1.1.0"
                                                                                            
                                                                                            c1 1.2.0
                                                                                              C = "=1.0.0"
                                                                                            
                                                                                            // second clause
                                                                                            c2 1.0.0:
                                                                                              A = "=1.1.0"
                                                                                            
                                                                                            c2 1.1.0:
                                                                                              B = "=1.0.0"
                                                                                            

                                                                                            Now, if I find a solution to this dependency problem (a selection of package versions), I can extract a solution to the formula from it. For example, (A=false, B=true, C=true) corresponds to selecting root 1.0.0, A 1.1.0, B 1.0.0, C 1.0.0, c1 1.2.0, and c2 1.1.0. Or, generalizing, if I have a polynomial time algorithm which solves arbitrary dependency problem, I can use that to solve, in polynomial time, arbitrary SAT problem.


                                                                                            An important thing to note here is that the dependency setup here is super-contrived, and looks nothing like real deps in real projects. This makes sense – dependency specifications that people actually write are usually easily solved.

                                                                                            For example, most of the time people use semver open constraints ^1.2.3. If all constraints are semver open, then a gready algorithm which always picks the maximal versions always finds a solution!

                                                                                            1. 2

                                                                                              Turns out, I don’t know how Cargo’s requirements work :-) Comma separated requirements in Cargo mean and rather than or. So while the above is correct (I hope) with respect to reduction of two stated problem, it’s incorrect that dependency problem models how Cargo works. It’s easy to fix though: rather than writing "=1.0.0, =1.1.0" one can just write "*", which is even simpler. In this cases, we always want any of the existing versions.

                                                                                              1. 1

                                                                                                Great answer, thanks!

                                                                                              2. 4

                                                                                                I first heard this ~10 years ago … I wondered why I was having so much trouble installing Ubuntu packages – i.e. shit would randomly break – and why there was seemingly no notion of correctness at all.

                                                                                                Also I remember trying to reverse engineer Debian’s packaging then, and realizing there are actually some base packages hard-coded in the code! i.e. there is no clear separation between Debian’s package lists and the package manager!


                                                                                                I stumbled across the EDOS project, which studied Linux distros in a formal way:

                                                                                                https://www.mancoosi.org/edos/references/

                                                                                                I think this may have been the paper I found:

                                                                                                Managing the Complexity of Large Free and Open Source Package-Based Software Distributions

                                                                                                https://hal.science/file/index/docid/149566/filename/ase.pdf

                                                                                                Section 3.1 is “Encoding the Installability Problem as a SAT Problem”, which proves its NP-complete.


                                                                                                There are some more references at the end here, EDOS project and otherwise:

                                                                                                https://research.swtch.com/version-sat

                                                                                              1. 3

                                                                                                This is very good. Presumably if we do go down this route, humans will have to get really good at writing formal specs to automate the “proofreading”.

                                                                                                1. 10

                                                                                                  Writing a specification is the incredibly hard part and implementing a proof is usually the boring and tedious part. We’ve had simple proof searches in proof assistants for a long time, having an AI based proof search is an obvious win!

                                                                                                  If programming starts to look like that, it’s going to be a fundamentally different skill to what most programmers have today. Implementing a sorting algorithm is very different to fully specifying that algorithm.

                                                                                                  And I know that getting requirements from a business can even be impossible. I’m not sure how many people could specify even small parts of the system they work on. I’d love to see it though, I just imagine things will have to drastically change as an industry. I hope we get there.

                                                                                                  1. 3

                                                                                                    One thing I have always wondered about formal proof specifications… being only surface acquainted with them….

                                                                                                    Doesn’t this just push the burden of error onto the specification step?

                                                                                                    Meaning, say I am a business owner and hire a FM expert to specify and formally prove some algorithm for part of my business. We write the spec, and it passes all the formal tests. Great, the spec is proved correct!

                                                                                                    But was the specification itself correct? The expert I hired could have messed up that step, or something failed in our communication. My overall confidence is the system is only as good as my trust that these still-human-bound steps had no errors. Now perhaps that is higher than it would be with typical software development, perhaps even much higher. But still… maybe not that high in an absolute sense?

                                                                                                    Am I missing something?

                                                                                                    1. 9

                                                                                                      Doesn’t this just push the burden of error onto the specification step?

                                                                                                      This is more or less what I remind people when talking about formal verification: it is a tool for ensuring that all of your bugs are present in your specification.

                                                                                                      That doesn’t mean that it’s worthless, for two very important reasons:

                                                                                                      • The spec defines requirements and not implementation details and so can be a lot (orders of magnitude) simpler. I have more confidence that something is correct when it’s short because it’s easier to think about the whole thing.
                                                                                                      • The spec is held in some tool that is designed for proving properties. Once you have a spec that says ‘these five things must be possible’, you can start posing questions like ‘is there a mechanism for an attacker to do this sixth undesirable thing?’ Often automated proof assistants are able to either say ‘no’ or ‘yes, with this sequence of steps’. If they’re not, you still have a good starting point for constructing such a proof.

                                                                                                      The second one of these is critical to your question. The spec is something that you can prove universally quantified properties over, the implementation is (usually) not.

                                                                                                      1. 1

                                                                                                        Thanks for this answer.

                                                                                                        I have more confidence that something is correct when it’s short because it’s easier to think about the whole thing.

                                                                                                        Indeed.

                                                                                                        Only short programs have any hope of being correct. ― Arthur Whitney

                                                                                                      2. 4

                                                                                                        I have some limited experience with a formal method called “cleanroom development” which was developed by a professor at my alma mater. An acolyte of his became a coworker of mine for a while. A fairly simple project which I would have estimated at being 3-6 months of effort got spun out into an 18 month process because of this and ultimately got finished by his successor who did not retain the method (in about 6 months). My experience is in-line with your hypothesis.

                                                                                                        The argument in favor of this particular formal method, based on studies done at large corporations, was that you spend more time up-front in the specification phase, but that you don’t suffer very many bugs (“defects”) later on, so the maintenance burden is greatly diminished.

                                                                                                        I’ve studied software architecture a bit since then. One of the concepts in software architecture is quality attributes. Knowing what the quality attributes are for your project informs what software architecture and development process you can or should use. I would absolutely recommend using cleanroom development or other heavy-weight formal methods for projects that prioritize correctness over cost and time-to-develop: aerospace projects for instance. You typically aren’t going to be able to quickly fix a bug that affects a satellite or autonomous robot on another planet. You have to get it right the first time. So in situations that prioritize correctness, you would want to choose one of these methods.

                                                                                                        Most of the time, the quality attributes you care about are cost or flexibility or something other than correctness. In those regimes, formal methods are overkill. Although the FM experts (paging Hillel) will say that the costs are not as bad as they are perceived to be. In my experience the customers don’t quite know what they want until they see what you’ve done. I think FM are not going to be a great fit for those situations because of exactly what you’re saying, that the specification has to be very well-understood at the outset.

                                                                                                        1. 3

                                                                                                          The difference is how largely readable and terse the spec is.

                                                                                                          Terseness because there’s a strong correlation between lines of code and big count.

                                                                                                          Readability because it doesn’t concern itself with petty details required to make it actually run.

                                                                                                          1. 5

                                                                                                            But isn’t this just an argument for terseness and readability for languages? That is, if we consider:

                                                                                                            1. Errors of specification
                                                                                                            2. Errors of implementation given a spec

                                                                                                            We can rule out 2 with a provable spec, but are still subject to 1. If the only saving us from 1 is terseness and readability, any language equally terse and readable will as good with the 1 errors. 1 errors being equal, we still have an advantage with a provable spec by this reasoning, but unless the argument is that specification languages are better w.r.t those qualities than all other languages, then we might still be overall better off with a standard language that excelled in terseness and readability?

                                                                                                          2. 3

                                                                                                            The main thing is that specification can be much higher level than the program needs to be, since it doesn’t need to be concerned with implementation details. Take the statement “two people can’t reserve the same room at the same time”. The implementation can be arbitrarily complicated:

                                                                                                            • How are reservations represented in the system?
                                                                                                            • How do we query them?
                                                                                                            • At what part of the reservation flow do we check this?
                                                                                                            • How do we show the user a time is unavailable?
                                                                                                            • What do we tell the user if they try to reserve an unavailable time, anyway?
                                                                                                            • How do we avoid race conditions?

                                                                                                            On the other hand, the high-level spec is pretty simple: all p1, p2: p1 != p2 => !(some loc, time: Reserved(p1, loc, time) && Reserved(p2, loc, time)). The code that implements reservation can also be spread across multiple models, which their own local specifications, and it’s possible that the local specs could all be proved correct but the global spec fails. So proving the global spec correct is still useful.

                                                                                                            1. 1

                                                                                                              Given these two sets of bugs:

                                                                                                              • Implementations which don’t do what the implementer thought
                                                                                                              • Implementations which don’t do what the business needed

                                                                                                              Specifications won’t always solve the latter but a perfect specification will always solve the former. I think I see the former a lot more often, but I definitely do see the latter too much.

                                                                                                              1. 2

                                                                                                                Maybe this didn’t answer things well. Why do we trust a software specification being correct more than the implementation?

                                                                                                                • More abstract (e.g. a full functional spec for reverse is forall x. reverse [x] = [x]; forall xs ys. reverse (xs ++ ys) = reverse ys ++ reverse xs)
                                                                                                                • More broad (e.g. this whole program does not contain an out of bounds error)
                                                                                                                • If you make a mistake in the specification, you’ll have to follow through with that mistake in implementation (on topic: AI probably wouldn’t help with this - I imagine it would just do as requested)
                                                                                                                • Implementations often change, specifications change less frequently
                                                                                                                1. 1

                                                                                                                  It sounds like you are validating what I thought. It is interesting to me that, even with all the mathematical machinery, we are still, at bottom, subject to the human brain’s ability to reason.

                                                                                                                  1. 3

                                                                                                                    we are still, at bottom, subject to the human brain’s ability to reason.

                                                                                                                    But, that’s because the problem set being described is subject to human factors; if there’s a business out there that needs an algorithm to “determine the set of shops to visit in optimal order, given my priorities”, that’s still dependent on some ability to translate from “priorities given by business”, through requirements gathering processes into “priorities understood by developer”, into “priorities encoded in specification”.

                                                                                                                    Even if you were able to automate out the “getting understanding into the developer” step, you’d still have a human brain going from abstract business priority into specification.

                                                                                                                    There’s, imo, no way to automate out human reasoning; math may be platonically ideal, but we still have to project into that space before doing things.

                                                                                                          1. 6

                                                                                                            https://cs.nyu.edu/~davise/papers/WinogradSchemas/WS.html

                                                                                                            Can a machine can create a Winograd Schema, yet?

                                                                                                            When run against ChatGPT, it answered with, “A dog chased a cat up a tree and a cat came down.”

                                                                                                            1. 2

                                                                                                              If you feed ChatGPT novel Winograd statements, it only gets them right by chance.

                                                                                                              1. 4

                                                                                                                I just tried a few from here and it got them all correct, including adding correct logical explanations. Are you saying it’s memorized these as part of the training data?

                                                                                                                EDIT: I tried a handful more that I invented, and it got those correct too.

                                                                                                                1. 4

                                                                                                                  Are you saying it’s memorized these as part of the training data?

                                                                                                                  That sounds perfectly reasonable to me.

                                                                                                                  1. 2

                                                                                                                    Yes, anything that can be scraped is in the belly of the beast now. :-)

                                                                                                                  2. 2

                                                                                                                    I made some up a few weeks ago and it got them wrong. Maybe it turned rampant since then.

                                                                                                                  3. 1

                                                                                                                    If you feed ChatGPT novel Winograd statements, it only gets them right by chance.

                                                                                                                    Does it not get them right from statistical inference?

                                                                                                                    If the word “shatter” is associated with “glass” more often than “iron” (throughout its training corpus), then doesn’t it follow that it would correctly “guess” that when a glass ball falls on an iron table then the glass ball shatters, and not the iron table?

                                                                                                                1. 26

                                                                                                                  This definitely is not congruent with why I didn’t adopt Elm more deeply. To me, Elm was too limiting; it was ossified, locking in bad design decisions and making them impossible to revisit or even experiment with alternatives. There’s also the compilation model; I don’t want to invoke any ECMAScript-specific compilation workflow if I can avoid it, since they’re usually not hermetic and they want to generate lots of scaffolding code. As with many other users, the showstopping misfeature was the inability to add native ECMAScript to bridge to some portion of the browser API which Elm hadn’t yet wrapped or typed.

                                                                                                                  If we’re thinking retrospectively, I would also mention the mistake of tying a language exclusively to Web browsers. It is fine to support browsers as a platform, but I feel like Elm always treated non-browsers, including its development REPL, as second-class platforms.

                                                                                                                  1. 15

                                                                                                                    Wouldn’t you say that puts you in the category of users who generally disagreed with the goals of Elm? In which case Elm was never going to be the language for you. Definitely a contributing factor to reduced adoption, because it turned you away to other options. I think there’s probably multiple sets of people when it comes to niche languages:

                                                                                                                    1. Users who aren’t interested in any part of the language
                                                                                                                    2. Users who are interested in some part of the language, but not the whole thing 2.1) Users who find the missing parts a deal breaker 2.2) Users who are fine with the missing parts
                                                                                                                    3. Users who are interested in the whole language

                                                                                                                    which then has overlap with:

                                                                                                                    a) Users who have their needs met by technologies they already use

                                                                                                                    b) Users who have their needs met but are curious in alternatives

                                                                                                                    c) Users who don’t have their needs met

                                                                                                                    This blog post mostly covered 2.2/3 b/c, but there’s definitely a lot to be said for the 1/2.1 a/b/c groups too.

                                                                                                                    1. 7

                                                                                                                      I agreed strongly with the design goals of Elm: first-order data, total functions with static types, etc. Elm was one of several MLs that I evaluated because I didn’t want to write ECMAScript directly. I recall that I gave up on using Elm for a project because I needed to fetch and parse binary data from a URL, and there was neither a satisfactory way of doing it nor a way of adding it myself. This evaluation was several years ago, and I expect that my particular issue has now been overcome, but I can’t operate in high-control communities like that.

                                                                                                                      In contrast, I’ve had issues with PureScript and OCaml, and I deliberately avoid e.g. using spago, but I was able and allowed to write my own hacks and build scripts in order to satisfy both their tools and my design requirements.

                                                                                                                      1. 1

                                                                                                                        Out of curiosity, what do you currently use for client side web development?

                                                                                                                        1. 3

                                                                                                                          I currently have a few hand-written ECMAScript stubs which use Preact, and then the bulk of the application code is written in Cammy and compiled first to PureScript and then to browser-friendly code. In the future, I plan to compile Cammy directly to WASM. I’m fully aware that it’s unreasonable to ask other people to write in Cammy, so I don’t.

                                                                                                                          1. 2

                                                                                                                            Link: Cammy, a language designed by @Corbin

                                                                                                                            1. 1

                                                                                                                              Is the Esolang page the only introduction?

                                                                                                                              1. 2

                                                                                                                                Probably. The bibliography might be enlightening. Cammy is only meaningful in that it approximates the pseudocode seen in many category-theory papers; otherwise, it’s really not a good language for anything.

                                                                                                                    1. 11

                                                                                                                      But all the old WATs like ["10", "10", "10"].map(parseInt) are still there.

                                                                                                                      Could someone explain this to me? What the holy hell happens to make it produce the crazy result [10, NaN, 2] ⁉️

                                                                                                                      I had never seen this before and just had to try typing it in to see what happened … I guess I don’t know JS as well as I thought I did.

                                                                                                                      1. 18

                                                                                                                        I think map passes the value AND index of the array element to the mapper function, so you get the result of “10” in base 0 (defaults to base 10), base 1 (error because 1 is not a valid digit in base 1), and base 2 (which is 2).

                                                                                                                        1. 14

                                                                                                                          In general in JS, if you see [].map(funcName), it’s going to bite you in the ass, and you should change it to [].map(x=>funcName(x)) as soon as possible. And do it even faster if it involves this.

                                                                                                                          1. 7

                                                                                                                            I understand why, but this shouldn’t be necessary though because it’s verbose and doesn’t meet expectations coming from many languages–introducing a point and needing arguments to get around what sometimes feels like a bug. This is why you’ll see separate functions like indexedMap, mapWithIndex, mapi, and the like in other languages so you’re not overloading the function arity.

                                                                                                                            1. 1

                                                                                                                              Oh yeah, it’s inarguably a bug in javascript, it’s just many decades too late to fix it.

                                                                                                                            2. 2

                                                                                                                              Is there are Clippy-like linter for JS/TS that could warn against mistakes like this one? Deno itself has lint, but that doesn’t seem to catch this one. Nor does eslint apparently.

                                                                                                                              1. 5

                                                                                                                                Neither do TS/flow. And there’s a reason they don’t: https://github.com/microsoft/TypeScript/wiki/FAQ#why-are-functions-with-fewer-parameters-assignable-to-functions-that-take-more-parameters

                                                                                                                                It’s unfortunate but there’s not much to be done here. You’d have to craft a very strict, one-off eslint rule to prevent this error in your codebase at the cost of some performance and convenience (eg prevent passing anything but an arrow function to Array.map)

                                                                                                                                An in-depth description of the problem is here, for anyone having trouble following along: https://jakearchibald.com/2021/function-callback-risks/

                                                                                                                                1. 2

                                                                                                                                  Linters cannot rule out cases when the argument function is actually supposed to take an element and its index. But at least they could warn about a possible gotcha.

                                                                                                                              2. 2

                                                                                                                                this is typically why I favour lodash/fp versions as they are strictly limited to one argument for easy composition!

                                                                                                                              3. 10

                                                                                                                                Love letters like this make me think I should give JS another shot. Warnings like that remind me that I don’t want to. It’s an abusive relationship.

                                                                                                                                1. 6

                                                                                                                                  See I disagree here - it’s very much a “know the APIs you’re using”.

                                                                                                                                  It is reasonable - and can be useful - for map() to pass things like the index as argument to the mapped function.

                                                                                                                                  It is reasonable - and absolutely useful - for parseInt to take a base argument.

                                                                                                                                  What we’re seeing here is when you try to use these two together.

                                                                                                                                  Imagine a statically typed language:

                                                                                                                                  int parseInt(string, base = 10);
                                                                                                                                  
                                                                                                                                  class Array<A> {
                                                                                                                                      Array<B> map<B>(B(*f)(A)) {
                                                                                                                                          Array<B> result = [];
                                                                                                                                          for (int i = 0; i < length; i++) {
                                                                                                                                              result.append(f(this[i]))
                                                                                                                                          }
                                                                                                                                          return result
                                                                                                                                      }
                                                                                                                                      Array<B> map<B>(B(*f)(A, int))
                                                                                                                                          Array<B> result = [];
                                                                                                                                          for (int i = 0; i < length; i++) {
                                                                                                                                              result.append(f(this[i], i))
                                                                                                                                          }
                                                                                                                                          return result
                                                                                                                                      }
                                                                                                                                  };
                                                                                                                                  

                                                                                                                                  here if you did [“10”, “10”, “10”].map(parseInt) you would call the second map, and so would get [parseInt(“10”, 0), parseInt(“10”, 1), parseInt(“10”, 2)]

                                                                                                                                  1. 11

                                                                                                                                    Of course, if you know you know, but for non-JS programmers this is very surprising because:

                                                                                                                                    • map passes multiple arguments
                                                                                                                                    • it’s not an error to call a function with the wrong number of arguments
                                                                                                                                    1. 8

                                                                                                                                      I get that it’s not the common map api in other languages, but coming in with “this is the API in some other unrelated language, therefore this is WAT” is simply not reasonable.

                                                                                                                                      For the latter: not needing exact parameter count is a fairly fundamental part of the language. Saying it’s surprising that map(parseInt) invokes the same behavior as anywhere else in the language is “surprising” is again not reasonable.

                                                                                                                                      JS has quirks, but labeling basic language semantics as WAT is tiresome.

                                                                                                                                      1. 13

                                                                                                                                        I get that it’s not the common map api in other languages, but coming in with “this is the API in some other unrelated language, therefore this is WAT” is simply not reasonable.

                                                                                                                                        It is still a reasonable criticism because map exists in a broader social context with widely known conventions. The criticism is that JS doesn’t obey what people would expect. And the resulting confusion is the empirical proof of the problem.

                                                                                                                                        In some cases, you might say, “Well ok, we know people will expect such and such, but such and such is actually a poor design because of X, so we’re going to fix it even if it’s going to cause some confusion”. That is, you can break with convention if you have a good reason. In the case of JS, this defense doesn’t hold up imo.

                                                                                                                                        Ramda’s solution to the problem, which is to add indexing only on explicit request, results in a cleaner, more composable API. Generously, you could argue that “just add i to every function” has practical convenience, despite wtfs like map(parseInt). But that is a debatable counterargument to the criticism. The criticism is at minimum reasonable, even if you don’t think it’s correct.

                                                                                                                                      2. 3

                                                                                                                                        Also, the fact that map() takes a function that expects 3 args (IIRC) but is commonly passed a function with one argument and things don’t blow up (neither at runtime nor at compile time in TypeScript) is pretty strange and probably the cause of a lot of these kinds of bugs. In general, JS/TS’s approach to “undefined” is difficult for me to intuit about and I’ve been using JS on and off for about 15 years.

                                                                                                                                        1. 1

                                                                                                                                          map passes multiple arguments

                                                                                                                                          It’s vaguely reasonable to not know this, but also the signature of map’s functor is on the first line or two of any documentation.

                                                                                                                                          it’s not an error to call a function with the wrong number of arguments

                                                                                                                                          Because variadic arguments (and the arguments array) are first class language features. This is where we get into “this is a core JS language feature, you really need to know it exists”

                                                                                                                                          1. 1

                                                                                                                                            Variadic functions are fine, the confusing thing is that all functions can receive 0-N args instead of only those that opt in. Yes this has been in JS from the start, but it’s unusual in casual JS use and in other popular languages.

                                                                                                                                        2. 4

                                                                                                                                          It is reasonable - and can be useful - for map() to pass things like the index as argument to the mapped function.

                                                                                                                                          It is not. You shouldn’t concern yourself with indices at all if you’re using map et al, and if you need that index, just zip the collection with its indices before mapping.

                                                                                                                                          1. 1

                                                                                                                                            Or you can remember that other languages have other idioms, and that the index can be useful in principle. There’s also an additional parameter which is the array being enumerated. Together these can be useful.

                                                                                                                                            You my have a functional language puritanical belief about what the API should be, but that’s a subjective opinion, hence it is reasonable that the functor receive additional information about the iteration, especially in a language like JS where variadic functions are first class.

                                                                                                                                            1. 2

                                                                                                                                              I have the utmost respect for different languages having different idioms (I’ve used quite a lot of OSes and languages throughout the years and am myself bothered when people raised on a blend of Windows, Linux and C-style languages complain that things are just different to what they are used to.) but in this case, it’s just a fractal of bad design.

                                                                                                                                              It’s not just because the map API is misleading, it’s because the extra arguments are thoroughly superfluous and tries to fit imperative idioms into a functional one.

                                                                                                                                              But first and foremost, it’s a bad design because it never took into account how it would match the default parameter convention of JS.

                                                                                                                                              One could also remark that parseInt is a strange global function with a strange name in an object-oriented language with some FP features.

                                                                                                                                          2. 1

                                                                                                                                            You are right. These are totally reasonable APIs. parseInt in particular is totally fine. For map, it’s a little quirk that’s different than maps in other languages, but it’s forgivable because it is useful.

                                                                                                                                            It really bothers me because of how Javascript functions are called. As roryokane says, you can get around the API by defining an extra function that only takes one argument:

                                                                                                                                            [“10”, “10”, “10”].map(n => parseInt(n))

                                                                                                                                            And that works because Javascript functions will ignore extra arguments instead of throwing an error. Ultimately, it’s that looseness that bothers me.

                                                                                                                                            1. 5

                                                                                                                                              You’re complaining about dynamic typing then, not JS.

                                                                                                                                              Plenty of languages have varargs, plenty of languages have default parameters. The reason map(parseInt) works is because there is no type checking beyond “can be called”.

                                                                                                                                              If you do want “arguments must match exactly”, then all your common calls to map would need function wrappers, because they’d trigger errors from not handling all three arguments.

                                                                                                                                              1. 11

                                                                                                                                                You’re complaining about dynamic typing then, not JS.

                                                                                                                                                No, I’m not. Python is dynamically typed, but it will throw an error if you provide an extra argument. Python also has varargs, but it’s opt in which I find reasonable. I want dynamic checks at run time, which this behavior doesn’t give me. (Or checks at compile time. Mostly I want to know if I screwed up.)

                                                                                                                                                1. 3

                                                                                                                                                  Right, but parseInt taking an optional base argument is reasonable, and that makes the arity match; python wouldn’t raise an error there.

                                                                                                                                                  1. 4

                                                                                                                                                    Again, parseInt is fine. Default arguments are fine. I don’t like how you can pass extra arguments to a function and they get ignored. I want them to throw an error.

                                                                                                                                                    1. 3

                                                                                                                                                      parseInt takes 2 args, map provides 3, so it would error in python.

                                                                                                                                                    2. 1

                                                                                                                                                      There are a bunch of problems. First variadic functions are a first class and relatively fundamental concept in JS, so you’ve got a different language style. That’s just a basic language choice - you can disagree with it, but given that fact you can’t then say it’s unreasonable when variadic nature of calls comes into play.

                                                                                                                                                      Second, I could make a JS style map() function, and pass python’s int() function to it, and it would be called just as JS’s is, because the additional parameter is optional, and hence would be fine. The only difference is that python bounds checks the base and throws an exception.

                                                                                                                                                  2. 1

                                                                                                                                                    The issue here is that variadic functions are core to JS from day 1. We’ve generally decided that that is “bad” nowadays, but given the functions have always been variadic in JS, large swathes of APIs are designed around it.

                                                                                                                                                    1. 1

                                                                                                                                                      Yes, that’s why I try to avoid JavaScript. There are lots of decisions that were made that seemed reasonable in the past, but turned out to have negative consequences that persist. I’ve been burned by some of them and have a negative opinion of the language.

                                                                                                                                              2. 6

                                                                                                                                                map passes the index as a second argument; parseInt accepts a second argument.

                                                                                                                                                1. 5

                                                                                                                                                  This is just not a WAT. What it is, is a classic example of people pretending reasonable behaviour and acting as though it is WAT. If you pass a function that takes multiple parameters (parseInt is in modern syntax: function parseInt(string, base=10)), and passing it to another function that will call it with multiple parameters, and then acting like the result is a weird behavior in the language, rather than a normal outcome that would occur in any language.

                                                                                                                                                  Start with:

                                                                                                                                                  function parseInt(string, base=10) -> int; // which is a fairly standard idiom across many languages for defining this function
                                                                                                                                                  

                                                                                                                                                  and then say “map passes the value and the index to the mapping function”, and ask what the outcome would be.

                                                                                                                                                  What we’re seeing here is a person saying “I am blindly assuming the same map API as other languages”, and then acting like the API not being identical is somehow a language WAT. It’s right up with the WATs claiming “’{}’ is undefined and ‘+{}’ is NaN”, or “typeof NaN == ‘number’”, etc

                                                                                                                                                  1. 11

                                                                                                                                                    Then again, your reply is a classic example of a language afficiando taking a clear WAT and explaining it as reasonable behaviour – even though it quite clearly is a bit of a problem for users of the standard map function coming from practically every other language.

                                                                                                                                                    Granted, like almost every other WAT, it’s a rather minor one for anyone who’s been writing JS/TS for more than a week. Still, I’d very much like a linter to automatically catch these for me. Even experienced people make dumb mistakes sometimes, and it’s just a complete waste of time and energy. Rust, a much stronger typed language (whose type checker already wouldn’t allow this), contains a linter that does catch problems similar to this one.

                                                                                                                                                    1. 1

                                                                                                                                                      Then again, your reply is a classic example of a language afficiando taking a clear WAT and explaining it as reasonable behaviour – even though it quite clearly is a bit of a problem for users of the standard map function coming from practically every other language.

                                                                                                                                                      I’m unsure what to say here. map in JS passes the index of the iteration, and the array being iterated. That is what it does. If you pass any function to map it will get those parameters. If the function you pass has default parameters, those will be filled out.

                                                                                                                                                      Similarly, parseInt takes an optional base that defaults to 10.

                                                                                                                                                      I get that people are quite reasonably tempted to do map(parseInt), but I cannot work out what JS is meant to do here different, unless people are saying map should explicitly check for parseInt being passed in?

                                                                                                                                                      1. 1

                                                                                                                                                        I suppose the simplest way to fix this would for map’s type to be like it is in Haskell, i.e.

                                                                                                                                                        (a -> b) -> [a] -> [b]

                                                                                                                                                        So the function map takes as argument takes just one argument, and map does not pass an index of the iteration.

                                                                                                                                                        I don’t doubt that there are valid reasons why this would be cumbersome in Javascript/Typescript, but I’m not familiar with them. Index of the iteration is not typically needed in functional style, so it’s kind of redundant and as shown here, potentially harmful.

                                                                                                                                                    2. 4

                                                                                                                                                      Start with:

                                                                                                                                                      function parseInt(string, base=10) -> int;
                                                                                                                                                      // which is a fairly standard idiom across many languages for defining this function
                                                                                                                                                      

                                                                                                                                                      and then say “map passes the value and the index to the mapping function”, and ask what the outcome would be.

                                                                                                                                                      Alas, that’s backwards. Things are surprising not when they are inexplicable in hindsight, but when they are not expected in advance. You have to start from what the user sees, then follow the network of common associations and heuristics to identify likely conclusions.

                                                                                                                                                      If the common associations lead to the correct conclusion, the interface is probably fine. If common associations lead to the wrong conclusion, there will be many mistakes — even by users who also know the correct rules.

                                                                                                                                                      So in our case, the user starts by seeing ths:

                                                                                                                                                      [10, 10, 10].map(parseInt)
                                                                                                                                                      

                                                                                                                                                      Now the user has to remember relevant facts about map and parseInt and come to the correct conclusion. Here’s a list of common associations that lead to the wrong answer.

                                                                                                                                                      • I can use parseInt(mystring) to mean parseInt(mystring, 10)
                                                                                                                                                      • I can use parseInt(mystring) without needing to remember parseInt(mystring, base) exists
                                                                                                                                                      • f is simply another way to write x => f(x)
                                                                                                                                                      • If the inputs to a .map() are all the same, the outputs are all the same
                                                                                                                                                      • [10, 10, 10].map(f) is normal code that does not require special attention.
                                                                                                                                                      1. 1

                                                                                                                                                        Alas, that’s backwards. Things are surprising not when they are inexplicable in hindsight, but when they are not expected in advance. You have to start from what the user sees, then follow the network of common associations and heuristics to identify likely conclusions.

                                                                                                                                                        parseInt takes a base argument. map provides the base. the semantics of both are reasonable. The same thing would happen in any other language.

                                                                                                                                                        Now the user has to remember relevant facts about map and parseInt and come to the correct conclusion.

                                                                                                                                                        Yes. the user should know the APIs that they’re using. The problem here is that many modern languages have a version of map that has a different API, and end users blindly assume that is the case.

                                                                                                                                                        1. 2

                                                                                                                                                          Array.map() provides a third argument. Other languages would blow up when parseInt() was called with two arguments. You seem to argue elsewhere that JavaScript’s parseInt() accepts more than 2 arguments (because all functions in JavaScript accept ~arbitrarily large numbers of parameters), but that’s precisely what’s bizarre (and as many contend, error prone) about JavaScript–that we can call a function whose signature is function(a, b) with 3 arguments and it doesn’t blow up.

                                                                                                                                                          The issue isn’t that people don’t understand map()‘s signature, it’s that JavaScript is unusually permissive about function calls which makes it easy (even for people who understand that JavaScript is unusually permissive about function calls) to make mistakes where they wouldn’t in other languages.

                                                                                                                                                          1. 1

                                                                                                                                                            No, you want the over application to work, because that’s how JS works, hence how APIs are designed. The alternative is that you would have to do (for example)

                                                                                                                                                            someArray.map((value,a,b)=>value*2)
                                                                                                                                                            

                                                                                                                                                            I get that people don’t like JS functions being variadic, but they are, and that means APIs are designed around that variadic nature.

                                                                                                                                                            1. 1

                                                                                                                                                              I mean, the obvious alternative is to make map()’s functor accept one argument, but that’s beside the point. We were debating about whether Javascript was uniquely confusing and the answer is “yes, Javascript functions are (uniquely) variadic by default, and this seems to result in many bugs and WATs”. To add to the confusion, it also has a syntax for expressing that the programmer intends for the function to be variadic: function(…args).

                                                                                                                                                      2. 2

                                                                                                                                                        If you pass a function that takes multiple parameters (parseInt is in modern syntax: function parseInt(string, base=10)), and passing it to another function that will call it with multiple parameters, and then acting like the result is a weird behavior in the language, rather than a normal outcome that would occur in any language.

                                                                                                                                                        It seems like the Go compiler disagrees with you:

                                                                                                                                                        func CallWithThreeArgs(f func(int, int, int)) {
                                                                                                                                                        	f(0, 0, 0)
                                                                                                                                                        }
                                                                                                                                                        
                                                                                                                                                        func TakesTwoArgs(int, int) {}
                                                                                                                                                        
                                                                                                                                                        func main() {
                                                                                                                                                                // cannot use TakesTwoArgs (value of type func(int, int)) as func(int, int, int) value in argument to CallWithThreeArgs
                                                                                                                                                        	CallWithThreeArgs(TakesTwoArgs)
                                                                                                                                                        }
                                                                                                                                                        

                                                                                                                                                        https://go.dev/play/p/BY7rRRqRMwt

                                                                                                                                                        As does the Rust compiler:

                                                                                                                                                        fn call_with_three_args(f: fn(i64, i64, i64)) {}
                                                                                                                                                        
                                                                                                                                                        fn takes_two_args(a: i64, b: i64) {}
                                                                                                                                                        
                                                                                                                                                        fn main() {
                                                                                                                                                            //  note: expected fn pointer `fn(i64, i64, i64)`
                                                                                                                                                            //              found fn item `fn(i64, i64) {takes_two_args}`
                                                                                                                                                            call_with_three_args(takes_two_args);
                                                                                                                                                        }
                                                                                                                                                        

                                                                                                                                                        https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=93d4aead97995330669c6e48cf8c657a

                                                                                                                                                        Here’s Python:

                                                                                                                                                        def call_with_three_args(f):
                                                                                                                                                          f(0, 0, 0)
                                                                                                                                                          
                                                                                                                                                        def takes_two_args(a, b):
                                                                                                                                                          pass
                                                                                                                                                        
                                                                                                                                                        // TypeError: takes_two_args() takes exactly 2 arguments (3 given) on line 2 in main.py
                                                                                                                                                        call_with_three_args(takes_two_args)
                                                                                                                                                        

                                                                                                                                                        https://trinket.io/python/63d966b40e

                                                                                                                                                        1. 1

                                                                                                                                                          You’re right, calling a function with an incorrect number of parameters does fail. So let’s try what I said: calling a function assuming one API, when it has another. It’s a bit harder in statically typed languages because (A)->X and (A,B=default value)->X are actually different types. In C++

                                                                                                                                                          The problem is you’ve misunderstood the claim. The claim isn’t “I can pass a function that takes N and expect it to be called with M arguments” it is “I can pass a function that takes a variable number of arguments, and that will work”. Referencing rust isn’t relevant as it has no concept of variadic functions or pseudo variadic with default parameters. C++ does, and I can make that happen with [](std::string, int = 10){...} which could be passed to a map the passes an index or one that does not, and both will work.

                                                                                                                                                          Your example of python however is simply wrong. If python’s map passed the index:

                                                                                                                                                          def map(array, fn):
                                                                                                                                                            result = []
                                                                                                                                                            for i in range(0, len(array)):
                                                                                                                                                              result.append(fn(array[i], i))
                                                                                                                                                            return result
                                                                                                                                                          

                                                                                                                                                          you could call that map function, passing int() as the functor, and it would be called. The only reason it would fail is int() bounds checks the base. The behaviour and language semantics are the same as in JS.

                                                                                                                                                          Now you can argue about details of the map() API, but the reality is the JS is a language that allows variadic calling, so it is a reasonable choice to provide those additional parameters, You can argue much more reasonably that parseInt should be bounds checking the base and throwing an exception, but again the language semantics and behaviour are not weird.

                                                                                                                                                          1. 1

                                                                                                                                                            The problem is you’ve misunderstood the claim.

                                                                                                                                                            Your claim was that any language would behave as JavaScript does when passing multiple parameters to a multiple parameter function.

                                                                                                                                                            I can pass a function that takes a variable number of arguments, and that will work

                                                                                                                                                            Ok, so you’re arguing that unlike other languages, all functions in JavaScript take a variable number of arguments which is just rephrasing the criticism that JavaScript is unusual (thus more programmer errors) and contradicting your claim that it’s behaving as any other language would do (e.g., “but again the language semantics and behaviour are not weird”).

                                                                                                                                                            Your example of python however is simply wrong. If python’s map passed the index:

                                                                                                                                                            Respectfully, you’re mistaken. Array.map() passes a third parameter to fn. If we update your Python example accordingly, it blows up as previously discussed:

                                                                                                                                                            def map(array, fn):
                                                                                                                                                              result = []
                                                                                                                                                              for i in range(0, len(array)):
                                                                                                                                                                result.append(fn(array[i], i, array)) // TypeError: int() takes at most 2 arguments (3 given)
                                                                                                                                                              return result
                                                                                                                                                            
                                                                                                                                                        2. 1

                                                                                                                                                          I’ve never heard the acronym WAT before, but I would call JS’s “map” function a footgun for sure. It’s named after a classic/ubiquitous functional, uh, function dating back to early LISP, and has the same purpose, but passes different parameters. Yow.

                                                                                                                                                          (But I have no problem with parseInt, or JS’s parameter passing in this instance. It’s all on map.)

                                                                                                                                                        3. 4

                                                                                                                                                          Here’s a detailed answer adapted from a chat message I once sent to a coworker.

                                                                                                                                                          Starting from this JavaScript console transcript, in which I’ve split out a strs variable for clarity:

                                                                                                                                                          > const strs = ['10', '10', '10']
                                                                                                                                                          > strs.map(parseInt) // gives the wrong result?
                                                                                                                                                          [10, NaN, 2]
                                                                                                                                                          

                                                                                                                                                          The correct way to write this is to wrap parseInt in a single-argument anonymous function:

                                                                                                                                                          > strs.map(x => parseInt(x))
                                                                                                                                                          [10, 10, 10]
                                                                                                                                                          

                                                                                                                                                          strs.map(parseInt) gives unexpected results because of three factors:

                                                                                                                                                          1. Array.prototype.map calls the passed function with multiple arguments:

                                                                                                                                                            > strs.map((a, b, c) => [a, b, c])
                                                                                                                                                            [
                                                                                                                                                                ['10', 0, strs],
                                                                                                                                                                ['10', 1, strs],
                                                                                                                                                                ['10', 2, strs],
                                                                                                                                                            ]
                                                                                                                                                            

                                                                                                                                                            The arguments are element, index, array.

                                                                                                                                                          2. The parseInt function takes up to two arguments – string, radix:

                                                                                                                                                            > parseInt('10') // parse with inferred radix of 10. That is, '10' in base 10 is…
                                                                                                                                                            10
                                                                                                                                                            > parseInt('10', 10) // parse with explicit radix of 10
                                                                                                                                                            10
                                                                                                                                                            
                                                                                                                                                          3. When calling a function in JavaScript, any extra arguments are ignored.

                                                                                                                                                            > const plusOne = (n) => n + 1
                                                                                                                                                            > plusOne(1)
                                                                                                                                                            2
                                                                                                                                                            > plusOne(1, null, 'hello', {a: 123})
                                                                                                                                                            2
                                                                                                                                                            

                                                                                                                                                          Thus, the incorrect version was calling parseInt like this:

                                                                                                                                                          > parseInt('10', 0, strs) // parse with explicitly assumed radix due to `0`
                                                                                                                                                          10
                                                                                                                                                          > parseInt('10', 1, strs) // parse with invalid radix of 1
                                                                                                                                                          NaN
                                                                                                                                                          > parseInt('10', 1, strs) // parse with radix 2. That is, '10' in base 2 is…
                                                                                                                                                          2
                                                                                                                                                          
                                                                                                                                                          1. 3

                                                                                                                                                            Yeah, uh, much as I love JavaScript, parseInt() is probably the worst place to look for elegance in the design of its equivalent of a standard library. It doesn’t even necessarily default to a radix of 10.

                                                                                                                                                          1. 18

                                                                                                                                                            It’s not really surprising that using node ecosystem from deno is hard. Idealistically (but maybe not maximally practically) deno initially set to create a different, better ecosystem.

                                                                                                                                                            But, if you are in “dependencies are generally a liability” camp, you probably will find deno production ready at this point, and quite delightful. I’ve recently migrated my blog from Jekyll to a hand-written deno script, and deno does seem like a dependable scripting environment, something that “Python as a glue language” should have been.

                                                                                                                                                            1. 4

                                                                                                                                                              What can Deno do in term of dependency packaging that a docker container can’t do?

                                                                                                                                                              1. 6

                                                                                                                                                                Work without docker?

                                                                                                                                                              2. 4

                                                                                                                                                                But, if you are in “dependencies are generally a liability” camp, you probably will find deno production ready at this point, and quite delightful.

                                                                                                                                                                I am definitely in this camp. Can you elaborate on why I will like Deno?

                                                                                                                                                                1. 16

                                                                                                                                                                  Sadly, this text area is a bit too small for this, so

                                                                                                                                                                  https://matklad.github.io/2023/02/12/a-love-letter-to-deno.html

                                                                                                                                                                  :)

                                                                                                                                                                  1. 2

                                                                                                                                                                    My guy I beg you to left-align your text on your blog. Full width justification is frustrating to read.

                                                                                                                                                                    1. 2

                                                                                                                                                                      Reads fine to me.

                                                                                                                                                                      1. 1

                                                                                                                                                                        I will consider doing that after browsers ship Kunth-Plass or otherwise fix horrible line breaking.

                                                                                                                                                                    2. 4

                                                                                                                                                                      Speaking for myself, I find the compile step from TypeScript to JavaScript a frequent source of friction in Node projects. I appreciate working in an environment that handles that for me in a way that feels as if I’m running my TypeScript directly. Subjectively, I’ve also found that it tends lives up to its performance claims of being faster than Node when, for example, reading large amounts of data from disk or over a network.

                                                                                                                                                                      1. 4

                                                                                                                                                                        The magic of Deno is being able to start a programming in Typescript by creating a single .ts file.

                                                                                                                                                                        It has a built in formatter, LSP, test runner, and benchmarking system. It has all the web APIs like fetch built in without having to polyfill them.

                                                                                                                                                                        1. 1

                                                                                                                                                                          As of node 18, node finally has fetch too.

                                                                                                                                                                          1. 2

                                                                                                                                                                            That is good, and the work the unidici team is doing is great. But fetch is just one item in a long list of Web APIs these kinds of runtimes can support: https://deno.land/manual@v1.30.3/runtime/web_platform_apis

                                                                                                                                                                    1. 21

                                                                                                                                                                      The world is boring enough as is. Let’s add more whimsy and cuteness through our service and project names.

                                                                                                                                                                      I find that I have more time for whimsy when I’m not fielding the umpteenth “what was the purpose of omega star again?” request. I’m not at work for cuteness–I’m there to get paid, support my family, and reduce the annoyance of the lives of my coworkers.

                                                                                                                                                                      There’s also the unfortunate thing about whimsy: team composition changes over time, and what you find funny today may not be funny later to other folks. Consider the issues you might run into with:

                                                                                                                                                                      • fargo as the name for a service for removing user objects
                                                                                                                                                                      • gestapo for the auditing system
                                                                                                                                                                      • dallas as a name for the onboarding service (since everybody does it)
                                                                                                                                                                      • kali as a name for a resource management and quota enforcement engine
                                                                                                                                                                      • miniluv for your customer service back-office suite
                                                                                                                                                                      • hyrda2 because hydra sucks but version 2 needs to coexist for a while yet with it
                                                                                                                                                                      • Quetzalcoatl after a character from that silly anime Kobayashi’s Dragon Maid (bonus points if you are concerned about second-hand cultural appropriation)
                                                                                                                                                                      • basically any character from Neon Genesis Evangelion
                                                                                                                                                                      • fido (or whatever your dog’s name is) for the fetching service might not be so pleasant after the namesake is sunset from production
                                                                                                                                                                      • 2consumers1queue for a data ingest worker pool probably isn’t gonna go over well if anybody on staff has any ranks in knowledge (cursed)

                                                                                                                                                                      And so on and so forth. I’m put in mind of an old article by Rachel Kroll talking about some logging service or format that was named rather blatantly in reference to either a porno or a sexual act–while this might be a source of chuckles for the team at launch, later hires may object.

                                                                                                                                                                      As an industry we haven’t gotten over the whimsy of blacklists and whitelists, master and slave, female and male connectors–or hell, even the designation of “user”. If we can’t handle those things, what chance do we think we have with names that seem entertaining in the spur of the moment?

                                                                                                                                                                      If you still doubt me, consider that AWS seems to engage in both conventions. Which is the easier product to identify, Kinesis or Application Load Balancer? Athena or Secrets Manager? IOT Core or Cognito?

                                                                                                                                                                      ~

                                                                                                                                                                      I’ll grant that for hobby projects, sure, go nuts. I enjoy thematic character names from anime for my home lab. I used to use names from a particularly violent action movie for cluster nodes.

                                                                                                                                                                      I’ll also grant that for marketing purposes (at least at a project level) it isn’t bad to have a placeholder name sometimes while things are getting hashed out–though those names often stick around and end up serving as inside baseball for folks to flaunt their tenure.

                                                                                                                                                                      Lastly, I’ll totally grant that if you by design are trying to exclude people, then by all means really just go hog wild. There are all kinds of delightfully problematic names that function like comic sans to filter folks. Just don’t be surprised if you get called on it.

                                                                                                                                                                      1. 9

                                                                                                                                                                        Lastly, I’ll totally grant that if you by design are trying to exclude people, then by all means really just go hog wild. There are all kinds of delightfully problematic names that function like comic sans to filter folks. Just don’t be surprised if you get called on it.

                                                                                                                                                                        Meh. The problem with this is that doing gratuitously offensive stuff, like deliberately making your presentations harder to look at, also attracts a bunch of people who think being gratuitously offensive is, like, the coolest thing ever. And when those people find a home in the tech world they soon set about being offensive in the wider community.

                                                                                                                                                                        Having helped moderate a once fairly significant FOSS thing, I’m pretty convinced that the assholery-positive branding is a bad thing for all of us. It breeds a culture of assholery that we all have to live with no matter where we are.

                                                                                                                                                                        With all of that said, some cute names don’t concern any sensitive subjects, so I feel like you’re tearing down a straw man, or at least the more strawy half of a composite man. At a previous job we created a service called “counter”, which did have a serious job, but we liked to describe it to management—mostly truthfully—as just being for counting things. You know, like, one apple, two apples… I don’t know if this is funny in anyone’s mind but mine, but the name certainly wasn’t chosen to be a useful description.

                                                                                                                                                                        1. 9

                                                                                                                                                                          It is not only about being offensive.

                                                                                                                                                                          Homebrew seem to be using beer brewing names and metaphors throughout. As someone who doesn’t know brewing beer nothing makes sense there. It feels to me like they’re taking a subject I know something about (packaging software) and deliberately make it obscure by renaming everything.

                                                                                                                                                                          I’m similarly put off Kubernetes. Why invent a whole new vocabulary to name existing concepts? I don’t care enough about Kubernetes to try deciphering their jargon.

                                                                                                                                                                          If you take an existing domain and change the names of all the things then anyone wanting to participate has to relearn everything you’ve made up (poorly in most cases.)

                                                                                                                                                                          It makes interacting with you like speaking in a second language you have little command of.

                                                                                                                                                                          EDIT: Just pause for a second and imagine reading a codebase where classes, functions and variables all have cute names…

                                                                                                                                                                          1. 7

                                                                                                                                                                            I think cutesy naming has its place, but I agree that sub-naming of cutesy things (e.g. cheese shop, wheels, eggs from Python packaging) is bad. Your cutesy name should just be a pun with a more or less deducible relationship to the thing it does (e.g. Celery feeds RabbitMQ). You can have jokes in the documentation, but no joke nomenclature.

                                                                                                                                                                            1. 7

                                                                                                                                                                              TIL! I worked at a company where we used Celery – but with Redis as the backing store – for years and I never made this Celery/RabbitMQ connection before.

                                                                                                                                                                            2. 4

                                                                                                                                                                              I don’t know that I disagree in general, either with you or with friendlysock’s comment. I was responding to a specific thing in it that I found significant. If you want to talk about naming more broadly, know that—at least from my perspective—people don’t all engage with names in the same way, and the purpose of names is situational, learned (think of mathematician vs programmer attitudes to naming variables), and at least in some cases a tradeoff between the interests of the various different people who will be using the name. So I don’t think it’s very useful to have a blanket opinion.

                                                                                                                                                                              1. 2

                                                                                                                                                                                Indeed I agree with you. I do seem to have grossly misread your comment and replied to it out of context, my apologies.

                                                                                                                                                                            3. 1

                                                                                                                                                                              Edgelord Simon Peyton Jones

                                                                                                                                                                            4. 7

                                                                                                                                                                              I find that I have more time for whimsy when I’m not fielding the umpteenth “what was the purpose of omega star again?” request. I’m not at work for cuteness–I’m there to get paid, support my family, and reduce the annoyance of the lives of my coworkers.

                                                                                                                                                                              So much this, and also:

                                                                                                                                                                              The joke is not going to hold up. It probably wasn’t the funny the first time except to you and maybe one other person, and it’s certainly not going to stand the test of time. I can count on one hand the number of “jokes” in comments and names I’ve come across that have actually made me laugh.

                                                                                                                                                                              You might think you are adding more “whimsy” into a drab world… in fact, you are probably inducing eye rolls for the decade of programmers who will have to maintain your work.

                                                                                                                                                                              1. 7

                                                                                                                                                                                Okay but I’m just going to say that 2consumers1queue is amazing.

                                                                                                                                                                                1. 1

                                                                                                                                                                                  I am more partial to 1cookie1jar but that’s also cool.

                                                                                                                                                                                2. 7

                                                                                                                                                                                  I’m put in mind of an old article by Rachel Kroll talking about some logging service or format that was named rather blatantly in reference to either a porno or a sexual act–while this might be a source of chuckles for the team at launch, later hires may object.

                                                                                                                                                                                  As an industry we haven’t gotten over the whimsy of blacklists and whitelists, master and slave, female and male connectors–or hell, even the designation of “user”. If we can’t handle those things, what chance do we think we have with names that seem entertaining in the spur of the moment?

                                                                                                                                                                                  Honestly, I think this is very easy to avoid if you have a diverse team and take a minimum amount of care in choosing a name. These examples are valid, but I think they are clearly influenced by the insularity and whiteness of software developers.

                                                                                                                                                                                  I’ve built a series of services over the past few years, and my preference has been animal names.

                                                                                                                                                                                  • Coyote is an ACME service
                                                                                                                                                                                  • Hedgehog is a routing layer for our Fastly ingress
                                                                                                                                                                                  • Mockingbird is an API polling service
                                                                                                                                                                                  • Cerberus is an IAM/OAuth/SAML service (I will grant you this one is the least creative)

                                                                                                                                                                                  They were not chosen at random, they were designed to be mnemonic.

                                                                                                                                                                                  While I take your point about AWS, Google does the opposite approach and names everything generically, which makes searching for them a pain in the ass. Also, I think there are distinctly different tradeoffs involved in choosing internal names vs external product names.

                                                                                                                                                                                  1. 2

                                                                                                                                                                                    I think this is very easy to avoid if you have a diverse team and take a minimum amount of care in choosing a name.

                                                                                                                                                                                    As a practical matter, early-stage startups and small companies do not tend to have diverse teams. Remember, naming is an issue that happens with a team size of 1 and which impacts a team size of…however many future selves or people work on a codebase.

                                                                                                                                                                                    You use Coyote as a harmless example (because ACME like in the coyote and roadrunner cartoons, right?) but similarly banal things pulled from the cartoons like gonzales for a SPDY library in this day and age cannot be guaranteed to be inoffensive. Even if you take care for today’s attitudes there is no guarantee of tomorrow.

                                                                                                                                                                                    On a long enough timeline, anything not strictly descriptive becomes problematic to somebody (and if you don’t like where the industry is heading in that regard, well, that ship has sailed).

                                                                                                                                                                                    1. 5

                                                                                                                                                                                      As a practical matter, early-stage startups and small companies do not tend to have diverse teams.

                                                                                                                                                                                      The less diverse your team is, the more care you should take.

                                                                                                                                                                                      You use Coyote as a harmless example (because ACME like in the coyote and roadrunner cartoons, right?) but similarly banal things pulled from the cartoons like gonzales for a SPDY library in this day and age cannot be guaranteed to be inoffensive.

                                                                                                                                                                                      I think this only buttresses my point: Gonzalez is clearly a racial/ethnic stereotype. I would never even think of choosing that. This is not rocket science!

                                                                                                                                                                                      On a long enough timeline, anything not strictly descriptive becomes problematic to somebody

                                                                                                                                                                                      Whereas using a purely descriptive name is much more likely to become problematic on a shorter timeline for the reasons stated in the article.

                                                                                                                                                                                      1. 2

                                                                                                                                                                                        According to Wikipedia, even though Speedy Gonzales is clearly a problematic ethnic stereotype, there has been a thing where the Mexican community has decided they like him, so he’s been uncanceled. Who can predict these things? https://en.wikipedia.org/wiki/Speedy_Gonzales#Concern_about_stereotypes

                                                                                                                                                                                      2. 1

                                                                                                                                                                                        You use Coyote as a harmless example (because ACME like in the coyote and roadrunner cartoons, right?) but similarly banal things pulled from the cartoons like gonzales for a SPDY library in this day and age cannot be guaranteed to be inoffensive.

                                                                                                                                                                                        Gonzales was once taken off the air out of racial concerns. Hispanic groups campaigned against this decision because Speedy was an a cultural icon and a hero. Eventually he went back on air

                                                                                                                                                                                        Assuming a person or demographics’s view point is it’s own danger. I am not innocent in this regard

                                                                                                                                                                                        1. 2

                                                                                                                                                                                          I’m well aware of the history there, never fear. That’s why I used him as an example: using that name may annoy well-meaning people, changing that name may annoy somebody with that Hispanic background.

                                                                                                                                                                                          If we’d gone with the boring utilitarian name of spdy-client, instead of being cutesy, we could’ve sidestepped the issue altogether.

                                                                                                                                                                                          Assuming a person or demographics’s view point is it’s own danger.

                                                                                                                                                                                          Sadly, that is not the direction well-meaning people influencing our industry have taken. So, in the meantime, I suggest boring anodyne utilitarian names until the dust settles.

                                                                                                                                                                                          1. 1

                                                                                                                                                                                            Sadly, that is not the direction well-meaning people influencing our industry have taken. So, in the meantime, I suggest boring anodyne utilitarian names until the dust settles. That’s a good point

                                                                                                                                                                                            Also sorry for my wording and tone. I’m not happy about how I wrote that

                                                                                                                                                                                    2. 1

                                                                                                                                                                                      As an industry we haven’t gotten over the whimsy of blacklists and whitelists, master and slave, female and male connectors–or hell, even the designation of “user”.

                                                                                                                                                                                      I’d argue that such metaphors have always been viewed as more on the descriptive side of the spectrum than whimsical or cute. In fact the idea that these terms are descriptive and in some sense “objective” is the most common defense I’ve seen of keeping such terms around, not that people enjoy them. I didn’t have to have anyone explain to me the meaning of master/slave replication when I first heard that term, the meaning is very intuitive. That’s an indictment of our culture and origins, not of metaphor.

                                                                                                                                                                                      My point is not that cute names are always great, or that it’s easy to avoid their pitfalls. It’s not. But I think holding space to be playful with language is often more generative than trying to be dry and descriptive. And it’s when we think we’re at our most objective that our subjectivity can lead us furthest astray.

                                                                                                                                                                                      1. 1

                                                                                                                                                                                        I think you’re completely missing that every product and open source project that you simply use will have such a name (maybe except OBS), so why is it different for local homegrown stuff?

                                                                                                                                                                                        1. 4

                                                                                                                                                                                          For the same reason that brand names can be “Amazon” or “Apple” but we don’t start renaming “computers” or “shopping websites” to something else. OSS projects exist in the same space as “brands” – typically a competitive space in which there are multiple competing solutions to the same problem. In that context, differentiating serves a purpose. However, it also has a cost: what your product does needs to be taught and remembered.

                                                                                                                                                                                          It’s possible that at a very large company some of those same forces take effect, but at small and medium companies they don’t. There, following the same principle would be like insisting everyone in the house call the kitchen sink “waterfall”. Why would I do that? “kitchen sink” works perfectly.

                                                                                                                                                                                          1. 4

                                                                                                                                                                                            I dunno, left-pad is pretty self-explanatory, as are sqlite and kernel-based virtual machine and logstash_json and open asset importer and lib_png.

                                                                                                                                                                                            There are people using clear, jargon-free naming conventions.

                                                                                                                                                                                            1. 2

                                                                                                                                                                                              So I guess we slightly differ on what cute and descriptive mean. sqlite has sql in it, descriptive, but -lite gives it a double meaning and makes it unique.

                                                                                                                                                                                              logstash_json is a horrible name, imho - because you could theoretically do the same project in many languages, it could be for logstash itself, or some intermediary product. (I don’t remember the specific one in question). Also libpng is very old and the assumption would be “this is the most popular PNG image library, written in C”, maybe because of the (weakly held) naming convention. These days we get many more new projects per year, but in theory a PNG lib in Erlang/Ruby/Brainfuck could also be called libpng, it’s just that the name was taken.

                                                                                                                                                                                              Maybe I am completely wrong here, but I understood the OP’s post more as “don’t use bland descriptive, pidgeonholed names” and you argue more over “don’t do cute names” - so maybe it’s a middle ground.

                                                                                                                                                                                              And yes, I still remember when a coworker wanted to call 2 projects “Red Baby” and “Blue Frog” or something and no one had any clue why, he couldn’t explain it, and we said: Why would one be red and one be blue?

                                                                                                                                                                                              1. 1

                                                                                                                                                                                                logstash_json has the project slug “Formats logs as JSON, forwards to Logstash via TCP, or to console.”. That’s roughly what I’d expect from the name, something to do with Logstash and something to do with JSON.

                                                                                                                                                                                                libpng is…“libpng is the official PNG reference library.” Sure, a slightly better name would’ve been “png_ref_implementation” or whatever, but again, the name tells me what to expect.

                                                                                                                                                                                                sqlite “implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine. “ So, you know, a SQL thingy but not large. Light, if you would. Again, maybe the name could mention the standalone nature, but that’s neither here nor there.

                                                                                                                                                                                                I think that bland, descriptive names are in fact exactly the right answer.

                                                                                                                                                                                                Again, examples from the other side:

                                                                                                                                                                                                nokogiri is a library for Japanese saws…no, wait, it’s for parsing XML and HTML.

                                                                                                                                                                                                Angular is a library for angles…no, wait, it’s an HTML templating and data binding library (among other things).

                                                                                                                                                                                                Beautiful soup is a library about soup…no, wait, another HTML/XML munging library.

                                                                                                                                                                                                Ristretto is a library for short shots of espresso…no, wait, it’s a caching library.

                                                                                                                                                                                                kubernetes is some tool for pilots…wait, no, it’s container orchestration and provisioning.

                                                                                                                                                                                                Prometheus is tool for giving fire to mortals…wait, crap, it’s a time series DB and monitoring setup.

                                                                                                                                                                                                These names do not enhance understanding.

                                                                                                                                                                                        1. 12

                                                                                                                                                                                          Minimize state! Use functional programming practices!

                                                                                                                                                                                          But seriously, my work with systems recently has been all about how to reduce the state that exists on a server. If you think this is solved with containers, I welcome you to the Jenkins container guidance of “put all that stuff in a volume mount”.

                                                                                                                                                                                          1. 8

                                                                                                                                                                                            There is a better way! A middle path, that captures the best of both worlds!

                                                                                                                                                                                            If a function is the sole owner of an object, and mutates it before returning it, that is indistinguishable from it never mutating anything at all, and instead returning a brand new object with the modifications.

                                                                                                                                                                                            If you pass a mutable reference to some data into a function, and only that function has the rights to modify that data, this is the same as never using mutation at all and instead having that function return the updated data, and using that updated data in place of the original data after the function call.

                                                                                                                                                                                                fn with_mutation(arg: &mut T);
                                                                                                                                                                                                with_mutation(&mut my_var);
                                                                                                                                                                                            
                                                                                                                                                                                            === fn without_mutation(arg: &T) -> T;
                                                                                                                                                                                                my_var = without_mutation(my_var);
                                                                                                                                                                                            

                                                                                                                                                                                            You can only do this safely and clearly with a type system that distinguishes sole ownership from shared references, and ensures there for every piece of data at every time, there is at most one function with permission to mutate that data. This is what Rust gives, and it’s what Val gives more clearly, though Val is still a prototype. And Haskell gives it too. Mutation without the spooky action at a distance.

                                                                                                                                                                                            1. 3

                                                                                                                                                                                              If you pass a mutable reference to some data into a function, and only that function has the rights to modify that data, this is the same as never using mutation at all and instead having that function return the updated data, and using that updated data in place of the original data after the function call.

                                                                                                                                                                                              One issue is that some operations may not be idempotent. If you had a function call that took a mutable reference, mutated the object, and then performed an operation that could fail you might not be able to retry the whole function safely, unless the mutation was idempotent itself.

                                                                                                                                                                                              For example, if you took a mutable reference to a dictionary, popped a value out of the dictionary, used that value to make an http request and that request failed you wouldn’t be able to rerun the whole function with the original reference.

                                                                                                                                                                                              You would be able to to that with immutable objects.

                                                                                                                                                                                              1. 2

                                                                                                                                                                                                Would linear typing also qualify as a means to reach this middle path? I learned about it recently, and some of the solutions you mentioned reminded me of the the whole “each value can only be used once” restriction.

                                                                                                                                                                                                1. 2

                                                                                                                                                                                                  Rust does use linear typing. It has four different rules for different kinds of values:

                                                                                                                                                                                                  • Small types like i32 and bool and friends are so cheap to copy it would be silly not to. These implement Copy, and are except from the rules of the next bullet point because the compiler will implicitly copy them when needed.

                                                                                                                                                                                                  • T is an owned value of type T (unless T is a small type like i32 and implements Copy). E.g. String is an owned heap-allocated string. This uses linear typing to enforce sole ownership. If you have a variable x: String, it’s a type error to say let y = x; let z = x;. (Pedants will point out that Rust uses affine types. All that that means is that you’re allowed to mention x zero times, while that’s technically disallowed by linear types.)

                                                                                                                                                                                                  • &T is a shared reference to T, there can be many simultaneous copies of it but it’s immutable.

                                                                                                                                                                                                  • &mut T is a mutable reference to T, there can be only one copy of it.

                                                                                                                                                                                                  The first (owned typed) use linear types. The second two use Rust’s borrow checker. It’s the combination of the two that makes the magic.

                                                                                                                                                                                                  Haskell gets to a similar endpoint (it allows mutation, but controls it well) by completely different means, using state monads.

                                                                                                                                                                                                  Most other languages pass around shared, mutable references, either explicitly, or under the hood. Which leads to confusion and bugs, and is the reason that people get up in arms about state. My point is that if you remove the sharing, then the state becomes harmless.

                                                                                                                                                                                                  1. 3

                                                                                                                                                                                                    Pedants will point out that Rust uses affine types.

                                                                                                                                                                                                    Yes, we shall. Rust’s affine types are useful, but they are not linear types, the lack of which prevents encoding in the type system that, e.g., some object given out by one’s module must be passed back to that module and not just dropped on the floor, and leads to kludges like types that prevent their values from being discarded unused by unconditionally panicking (throwing an exception or aborting the process) in their destructors.

                                                                                                                                                                                                2. 1

                                                                                                                                                                                                  Not familiar with Rust…. is there a fundamental conceptual difference between this and the OO pattern of private data that can only be mutated by a public method?

                                                                                                                                                                                                  1. 3

                                                                                                                                                                                                    The main difference with Rust is that in the typical OO language you can have two aliases to the same object, that can both call the public method, so there’s still room for spooky action at a distance.

                                                                                                                                                                                                  2. 1

                                                                                                                                                                                                    Clojure has a mechanism for this too. You can make a variable mutable, and it will error out if you pass it to a function that expects non-mutable data. This allows mutation for speed and going back to being immutable when passing data around.

                                                                                                                                                                                                    1. 3

                                                                                                                                                                                                      Not the same! The property I’m referring to is global, not local. It’s not the sort of thing you can bolt on to an existing type system.

                                                                                                                                                                                                      E.g. say that you have the object graph:

                                                                                                                                                                                                          A
                                                                                                                                                                                                        /   \
                                                                                                                                                                                                       B     C
                                                                                                                                                                                                        \   /
                                                                                                                                                                                                          D
                                                                                                                                                                                                      

                                                                                                                                                                                                      and A passes in two mutable references to a function: a mutable reference to B and one to C. Bam, invariant has been broken, spooky action at a distance may occur! If the function modifies B.D, then spookily it has also modified C.D.

                                                                                                                                                                                                    2. 1

                                                                                                                                                                                                      Good article and comment about that recently:

                                                                                                                                                                                                      https://verdagon.dev/blog/when-to-use-memory-safe-part-2

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

                                                                                                                                                                                                      i.e. borrow checking can be seamless for stateless apps, but is more complex for stateful apps

                                                                                                                                                                                                      Stateless programs like command line tools or low-abstraction domains like embedded programming will have less friction with the borrow checker than domains with a lot of interconnected state like apps, stateful programs, or complex turn-based games

                                                                                                                                                                                                      1. 1

                                                                                                                                                                                                        If you pass a mutable reference to some data into a function, and only that function has the rights to modify that data, […]

                                                                                                                                                                                                        You can only do this safely and clearly with a type system that […] ensures there for every piece of data at every time, there is at most one function with permission to mutate that data. This is what Rust gives, […]

                                                                                                                                                                                                        Rust’s &mut exclusive references mean that “only that function has the rights to modify” and read that data — letting one function mutate the data without barring other functions from reading the data at the time suggests a race condition.

                                                                                                                                                                                                        1. 1

                                                                                                                                                                                                          Another way to put this is that only the combination of shared mutable data is bad. If you remove / control sharing, mutation can be totally safe.

                                                                                                                                                                                                          I love this model, and am very interested in Val for that reason.

                                                                                                                                                                                                          1. 1

                                                                                                                                                                                                            (D calls this “weakly pure”)

                                                                                                                                                                                                          2. 2

                                                                                                                                                                                                            Completely agree! Minimizing state is paramount. I’ve found functional programming pushes the idea of state reduction, but it can apply to any philosophy and is the first step to solving a problem. I’ve found over time my feedback on design reviews has just been concerned with the design of state and how it’s being handled.

                                                                                                                                                                                                          1. 5

                                                                                                                                                                                                            I find this a bit silly. In which way is vim editing more keyboard centric than VSCode’s own shortcuts? To be honest I think current modern cua mode editors with their multi cursor, mark next occurrence, select inside, etc. Are kind of crossing keyboard usage effectiveness when compared to the two old editors. I am only missing a way to toggle between vertical and horizontal terminal split. Other than that, I don’t use the mouse at all.

                                                                                                                                                                                                            Why do people equate keyboard-centric to vim movement?

                                                                                                                                                                                                            1. 6

                                                                                                                                                                                                              A big component is arrow keys. Using literal arrow keys sucks, as they are far from home row, but account for a big chunk of keystrokes. This can be solved by:

                                                                                                                                                                                                              1. 2

                                                                                                                                                                                                                Is that really that big of a deal compared to long keybond sequences that need to be typed repeatedly? What about escape? It is also outside the home row.

                                                                                                                                                                                                                Feels like a meme without really ever asking these questions.

                                                                                                                                                                                                                1. 11

                                                                                                                                                                                                                  In my experience, yes it is. It is much faster and much lower mental effort to type something without moving hands. Reaching for arrow keys it not that much worse better than reaching for mouse. Again for me, even godawful Emacs keybindngs were a marked improvement over arrows.

                                                                                                                                                                                                                  Escape is on CapsLock of course!

                                                                                                                                                                                                                  1. 1

                                                                                                                                                                                                                    It is not worse than reaching the mouse, it is leaps and bounds less disruptive for typing than reaching the mouse. The arrow keys are always in the same relative position, and closer, to the letters than the mouse. And place your hand with the keys home, end,pgup, pgdn, insert, which are central to cursos movement.

                                                                                                                                                                                                                    Why is moving the right hand (most people most agile hand) to the arrows such a deal breaker to com users, but moving the left hand to escape is fine? What exactly is the difference?

                                                                                                                                                                                                                    1. 2

                                                                                                                                                                                                                      I don’t need to move my hand to reach escape key – just extend the hand. The wrist stays where it is. To move to the arrow keys, I need to rellocate the whole hand.

                                                                                                                                                                                                                      I totally can see how having to reach for arrow keys is not a big deal for some folks. However, the bit about “What exactly is the difference?” I don’t get. Obviously there’s a huge difference between just extending the finger versus moving the whole hand?

                                                                                                                                                                                                                      And, to clarify, on the layout I use, escape is capslock, arrows are ijkl, home end pgup/down are uo<>.

                                                                                                                                                                                                                  2. 2

                                                                                                                                                                                                                    What about escape? It is also outside the home row.

                                                                                                                                                                                                                    I, like many vim users, has a map for escape for this reason. I use jj from normal mode.

                                                                                                                                                                                                                    1. 1

                                                                                                                                                                                                                      How do you escape insert mode?

                                                                                                                                                                                                                      1. 1

                                                                                                                                                                                                                        I mistyped. Should have read “jj from insert mode”.

                                                                                                                                                                                                                  3. 1

                                                                                                                                                                                                                    Using literal arrow keys sucks

                                                                                                                                                                                                                    Yes, but only if you’re arrow keys are in a sucky location. There’s little reason to use hjkl if arrow keys are in an ideal location.

                                                                                                                                                                                                                    I realize alternative keyboards arent as affordable or accessible though.