Preferences

uzerfcwn
Joined 39 karma

  1. Thanks for sharing this! Went and changed some keybinds right away.
  2. My favourite feature is userChrome. The default chrome sucks in both Chrome and Firefox, but at least Firefox allows me to customize it to my liking without forking the entire browser.

    On the flip side, changing keybinds in Firefox requires forking, but the defaults aren't too bad.

  3. I feel that Windows Registry is similar legacy cruft as environment variables. Worse yet, most software doesn't document which registry keys it's using, so you have to find them on some ancient forum comment or do the detective work by yourself.
  4. > Is there anything C# _doesn’t_ have?

    Pi types, existential types and built-in macros to name a few.

  5. Last month, a Finnish court judged that using derogatory words in an email sent privately to the offended person counts as defamation.[1] When this was discussed in the Finnish Reddit [2], some found it unjust that it counts as defamation even though the message wasn't sent to third parties, but it is indeed how the law was written.

    [1] https://www.iltalehti.fi/kotimaa/a/6c9a65fe-f706-449e-b0d9-1...

    [2] https://old.reddit.com/r/Suomi/comments/1mv9usq

  6. The core difference between sums and unions is that sum types have cardinality |A+B| = |A| + |B|, whereas union types have cardinality |A∪B| = |A| + |B| - |A∩B|. As you noted, type systems with union types, such as Typescript, also support sum types because you can create disjoint wrapper types (like Ok and Err) and their union type will be semantically equivalent to a sum type, since the intersection is an empty set. In this sense, union types are strictly more powerful than sum types.

    The downside is that union types require some notion of subtyping, since otherwise A∩B is always empty for distinct A and B. Unfortunately, subtyping is apparently very difficult to implement in HM-like type systems (like Rust and ML) such that it plays well with type inference.[0] Hence, the downside of having union types in a language is that users have to write out types more often.

    Unlike kibwen, I don't think Rust's type system is particularly essential for new languages. It's a design choice where one side has more powerful types but the other side has more powerful type inference.

    [0] https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_sy...

  7. The problem with forking is that updating becomes a nightmare. Most ERPs provide a stable-ish API and heavily recommend customers to stick with it, because then automatic updates just work.
  8. > Most web apps today use APIs that return JSON and are called by JavaScript. Can you use REST for such services

    You kind of could, but it's a bad idea. A core tenet of the REST architecture is that it supports a network of independent servers that provide different services (i.e. webpages) and users can connect to any of them with a generic client (i.e. a web browser). If your mission is to build a specialized API for a specialized client app (a JS web app in your example), then using REST just adds complexity for no reason.

    For example, you could define a new content-type application/restaurantmenu+json and build a JS client that renders the content-type like a restaurant's homepage. Then you could use your restaurant browser JS client to view any restaurant's menu in a pretty UI... except your own restaurant's server is the only one that delivers application/restaurantmenu+json, so your client is only usable on your own page and you did a whole lot of additional work for no reason.

    > does REST require a switch to HTML representation ... How such HTML representation can even use PUT and DELETE verbs

    Fielding's REST is really just an abstract idea about how to build networks of services. It doesn't require using HTTP(S) or HTML, but it so happens that the most significant example of REST (the WWW) is built on HTTPS and HTML.

    As in the previous example, you could build a REST app that uses HTTP and application/restaurantmenu+json instead of HTML. This representation could direct the client to use PUT and DELETE verbs if you like, even though these aren't a thing in HTML.

  9. Feel free to write a bug report to Chrome developers or ManifestV3 authors. In the meantime, Firefox users can override any delivered content with the webRequest API.
  10. C++ also has generators[1], but the author is perhaps unaware of them.

    [1] https://en.cppreference.com/w/cpp/coroutine/generator

  11. To me, the cool (and uncommon in other languages' standard libraries) part about C++ ranges is that they reify pipelines so that you can cut and paste them into variables, like so:

        auto get_ids(std::span<const Widget> data)
        {
            auto pipeline = filter(&Widget::alive) | transform(&Widget::id);
            auto sink = to<std::vector>();
            return data | pipeline | sink;
        }
  12. That looks more like ad hoc union types than sum types. What happens if you do:

        data FooResult = Number | Number
    
    If you can't distinguish the two cases, then it means they're not an actual sum type, since e.g. the set size is |FooResult| = |Number| whereas a sum type should have 2*|Number|.

    The reason ad hoc union types are avoided in Hindley-Milner (HM) languages is that their usability depends on subtyping, which is incompatible with HM. You could get around this by saying that ad hoc sum types require the types to be distinct, but this would greatly impede usability. For example:

        ErrorA = FileNotFoundError | ParsingError
        ErrorB = FileNotFoundError | PermissionError
        ErrorC = ErrorA | ErrorB // Oops, trying to ad hoc sum FileNotFoundError twice
    
    The tried and true solution in HM is to use generic types like Result<A,B>, where you separate the cases with labels Ok and Err.

    On the other hand, languages with subtyping aren't that averse to ad hoc union types. TS and Python already have them and C# is adding them soonish [1].

    [1] https://github.com/dotnet/csharplang/blob/main/proposals/Typ...

  13. For me, that advanced reader is Thunderbird. It has amazing customizability with userchrome.css, web extensions, about:config and developer tools from Firefox.
  14. Once, I wanted to write a C# function roughly like this:

      (T1, ..., Tn) Apply<T1, ..., Tn>((Func<P, T1>, ..., Func<P, Tn>) args)
    
    This is not possible in C# because the language doesn't have variadic generics. Instead, I used runtime reflection and wrote something like this:

      object[] Apply(Func<P, object>[] args)
    
    Although it worked, the downside is that the types T1, ..., Tn are no longer statically known, which means that the function's contract has to be written in comments and the caller has to check them manually. In contrast, C++ has variadic templates, which would allow the compiler to check the types automatically.
  15. Exceptions are difficult to discuss because different languages implement exceptions differently, each with their own downsides. That said, I don't think anyone has an issue with bubbling. Even sum type proponents love Rust's ? shorthand, because it makes it easier to propagate Results up the stack.

    The big issue with exceptions in C#, Python and JS is that they're not included in function signatures, which means you have to look up the list of possible exceptions from documentation or source code. This could be amended with checked exceptions like Java, but it allegedly doesn't mesh well with the type system (I haven't personally written Java to confirm this). And then there's the C++ crowd that slaps noexcept on everything for possible performance gains.

    Personally, I like the way Koka does exceptions with algebraic effects and type inference. It makes exceptions explicit in function signatures but I don't have to rewrite all the return types (like in Rust) because type inference takes care of all that. It also meshes beautifully with the type system, and the same effect system also generalizes to async, generators, forking and other stuff. Alas, Koka is but a research language, so I still write C# for a living.

  16. You can add to the end of an array by using the path /.../myarray/-, i.e., the index is replaced by a dash.

    JSON patch is indeed not idempotent.

This user hasn’t submitted anything.