1. 1

    Must be a different notion of what a fixture is than I’m accustomed to.

    Most of my tests are unit tests, property tests, or integration/functional tests. A lot of my tests will run DAL code or poke at the API and see what state the database is in. As a result, when I talk about fixtures I mean the data installed into the database post-table-truncation. Usually in Haskell I’ll also have a datatype storing all the data from the database in memory as a big Fixtures record, a pattern I picked up from a past employer.

    1. 5

      I damaged the recoil spring guide rod in my competition pistol by installing it upside down. Rookie mistake! It now has a crack on one side but still works. Will have to see if I can machine one: only have a lathe and this isn’t quite a rotational only shape. Otherwise could try and silver braze the crack.

      We’re also eyeing a 2nd vehicle, BMW i3, so a test drive maybe.

      1. 2

        I’m guessing (and hoping) that a failure of the recoil spring guide isn’t going to be dangerous to the shooter?

        1. 1

          Nope, and the crack is not on the side that’s subjected to mechanical stress: wouldn’t ever crack there if it was inserted properly.

        2. 1

          What’s your comp pistol?

          1. 1

            Browning Hi-Power GP Competition, the one with long barrel and muzzle weight.

            1. 2

              Browning Hi-Power GP Competition

              Nice! Any opinions on the CZ comp models?

              1. 6

                Most 75/85 pattern matchguns are made with IPSC type shooting in mind: quick draw, high speed, large targets at close range. I do Nordic field shooting which is more precision oriented. It’s 6 shots per hold, typically at 25m but can vary from 15 to 180m. For IPSC you want one that can be quickly reloaded, has high mag capacity, accepts red dot sights, and is not unwieldy to draw. For Nordic it’s iron sights only so priority is on the largest sightline and the longest barrel (restricted to 6”).

                I never shot CZ but used a Tanfoglio loaner for a while, which is an Italian 75 copy. It’s entirely fine but is a handicap in Nordic events. Right tool for the job etc.

                1. 1

                  This was very informative, thank you!

          2. 1

            I assume that the upside down here refers to forward to backward? Or did you literally rotate the thing about its axis?

            1. 1

              No, literally upside down: the part has asymmetric lug engaging with the barrel and slide stop, and can be inserted both ways. Somehow I messed up after doing it right a few times already.

          1. 23

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

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

            1. 3

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

              1. 2

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

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

                1. 2

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

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

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

                  1. 1

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

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

                1. 4

                  I rather like this idea. The single lines published on the front right now are a little basic for me to find interesting, but I do like the idea of studying an interesting line of code each day. I saw a line recently written by a colleague that while simple, I found quite elegant. I’m not sure I would have thought to apply a constructor to the result of a database action like this.

                  risk <- Entity rid <$> runDB (get404 rid)
                  

                  I guess the hard part here would be curating a gallery of interesting single lines of code, or otherwise incubating a community to crowdsource that effort.

                  1. 3

                    I end up joining a traversal sometimes.

                    Here’s one I was able to ripgrep from my archives: second join $ traverse (first return)

                  1. 2
                    • Answering the editor of my book’s questions, pushing toward a final version.

                    • Finished moving my wife to Texas, settling in now.

                    • Teaching a friend the basics of desktop publishing and LaTeX.

                    • Going over the Baltimore Catechism and how it compares pedagogically with the universal Catechism.

                    • Seeing a German Shepherd Dog tomorrow that needs a new home.

                    1. 6

                      Ports. The t480s has 2 USB-A ports and 2 USB-C ports. It also has a full size HDMI, SD card slot, and full-size Ethernet. Is 0.14” difference in thinness worth access to the ports, user upgrade-ability, and the longevity of the keyboard?

                      Given that there are quite a few usb-c hubs[1], or single-use-case (eg. hdmi for presentations) dongles, out there that offer the ports in a breakout/hub/dongle format, I don’t desire a return of all the ports that I use so occasionally/seldom. Paying the size/thickness/weight tax all the time for something I use rarely isn’t a great tradeoff for me.

                      Then again, I use a laptop to be mobile, not as a desktop replacement. I realize that not everyone does this, so ymmv.

                      [1]: Kingston’s Nucleum has two USB 3.0 ports, an HDMI port, a SD and microSD card slot, one USB-C charging port and one regular USB-C port

                      1. 13

                        USB-C devices and hubs are pretty bad if you want to run more than one 4k60 display. Some can’t even do one. You can’t just plug in one hub and be done. I had to plug in three different USB-C dongles to get two 4k60 monitors, ethernet, keyboard, mouse, audio going on my 15” rMBP. Worse, USB-C slips and loses connectivity very easily.

                        The whole situation is asinine. Yes they’re meant to be mobile but I’m not paying $3k for something functionally equivalent to a netbook on steroids.

                        1. 6

                          USB-C slips and loses connectivity very easily

                          I missed this part earlier (or maybe you edited it in later). I very much agree with this one. I find usb-c a bit fiddlier than I would like, especially for power in comparison to the old apple magnetic (magsafe) power connectors. RIP magsafe.

                          1. 2

                            Multiple 4k60 displays seems a bit like a job for a desktop to me. That said, I agree that sucks. I wonder if it is a limitation of usb-c or just so few people with that use-case that nobody makes one that can do that yet.

                            EDIT: hmm. looks like a displayport 1.2 limitation, based on some searching. DP 1.2 supports a single 4K 60 Hz monitor, two 1440p 60 monitors, and so on. DP 1.3 supports more (gfx card willing), but I think usb-c/thunderbolt3 is still DP1.2. bummer.

                            1. 5

                              It’s a MacBook Pro. I was running 2 displays off a 12” Thinkpad with the dock years and years ago.

                              1. 4

                                And you can still do so if those displays aren’t 4k. The terrible industry-wide state of getting pixels from ram to screen is not Apple’s doing and any attempt they make to fix it themselves will be met with endless pearl-clutching about “proprietary connections”

                                1. 2

                                  I don’t mind how they fix it, I would prefer more port types than just USB-C. I think the decision to only have USB-C is aesthetic not functionality.

                                  1. 3

                                    There are functional reasons to want only one port on your device. However, their decision to go about it in classic Apple fashion, making the change out of nowhere, was certainly a head-scratcher.

                                2. 4

                                  A MBP will absolutely run multiple 4K displays on a single port.

                                  Fuck, a Mac mini with just Intel graphics will run 2 4K displays, also from a single port.

                                  1. 2

                                    I get that it has Pro in the name. Did you use docking at every location where you worked with multiple monitors? Monitors these days also just seem huge to me. I can’t imagine someone having two 30+ inch 4k monitors on their desk ( that’s a /lot/ of terminals! ;) ) and yet choosing to drive it with a laptop. The workflow comparison between that and running undocked seems significant.

                                    I do wonder if some portion of people get laptops just because, or on the off chance that they might do something on the go, but then they end up using them docked 100% of the time anyway. Definitely not saying this was you though, as I have no clue how you worked or used your machines.

                                    1. 5

                                      Some people don’t buy laptops but their company only provides laptops. You have to be able to use the laptop as a desktop replacement if you need/want to. Heck, desktops are a vanishing breed, I imagine 90% of them are sold as gaming machines, these days.

                                      1. 2

                                        Chiming in with an anecdote, but I will emphasize this is my singular experience and preference.

                                        I have a 2015-era Thinkpad X1 Carbon whose built-in display is 1440p. Most of my programming uses, I use it docked to an additional 1440p display, sometimes two and turn off the built-in screen in favor of two full-sized monitors. In both cases they are only 25” displays, but the additional pixels are very appreciated. I don’t really see myself upgrading those to 4K screens, but I can imagine others who might.

                                        Some non-programming tasks also benefit greatly from the extra screen real-estate. I do will sometimes design in Figma (full screen on one monitor) with the second monitor hosting two windows: an editor window for referencing existing CSS in our projects, and a browser open to the Spec for the project whose design I am working on

                                        I am very much in the “laptop for the off chance they might do something on the go” crowd, but those times are far from insignificant. A lot of it is on-the-go comms with my team, doing project management and product management tasks. I definitely would not be effective with only a desktop, i.e. only a phone for on-the-go productivity.

                                  2. 0

                                    Limiting yourself to a USB-C (protocol) dock/device when you have TB3 ports but clearly want a not-average-joe functionality makes no sense to me.

                                  3. 3

                                    For me, this (multiple do-almost-anything ports, vs several each do-1-specific-thing ports) is the killer thing, but it works specifically for Macs because those ports are all TB3 not “just” USB-C.

                                    For basic things (i.e. the common complaint about the pre-TB3 MBP having “USB-A, HDMI and SD card” you can get a single USB-C ‘hub’ to provide all those ports, but whenever possible (and particularly for stuff relating to displays) I actually tend to get/suggest TB3 devices.

                                    1. 2

                                      My question — and the question of most people I know who have a newer MacBook Pro — why not both? Why not have USB-C ports and a HDMI? TB3 is awesome but it doesn’t have to be exclusive.

                                      1. 4

                                        It’s entirely possible Apples reasoning is aesthetic, but to me, a HDMI port is useless, and usually adding a HDMI port means you lose something else (see: the 2018 Mac mini that only supports 2x4k displays over TB3 because the third ‘supported’ display must be over HDMI).

                                        HDMI is also one of the least-hard “problems” to solve: you already need a HDMI cable, so use a different HDMI cable, with USB-C on one end.

                                        1. 2

                                          You’re right. The Mac mini is a really good example of a combination of ports that folks really enjoy having access too.

                                          This is all a tangent though, the reality is Apple is bent on making their laptops like their tablets and I wish they wouldn’t. In the end though it’s all preference.

                                          1. 3

                                            reality is Apple is bent on making their laptops like their tablets

                                            Maybe the reality as you see it, but until they add touch screens to their laptops, I’m going to remain pretty dubious about that viewpoint.

                                            1. 2

                                              You missed my point. Not sure if that was deliberate or not.

                                              The Mac mini has HDMI.. for some reason, but because it does, you can’t run 3 DisplayPort 4K displays from it. You can run two DP, and one has to be HDMI.

                                              I would be happier if the mini had forgone HDMI for more TB3 ports (or even dedicated (mini) DisplayPort would be better than HDMI). I’d even give up the USB-A ports for more TB3 ports.

                                              reality is Apple is bent on making their laptops like their tablets

                                              I really cannot agree with that at all and I wonder if you somehow don’t understand that TB3 and USB-C are not the same thing.

                                              1. 2

                                                you can’t run 3 DisplayPort 4K displays […] I really cannot agree with that at all and I wonder if you somehow don’t understand that TB3 and USB-C are not the same thing.

                                                Well, if we are going to be pedantic ;). If you use DisplayPort 4K displays, you are not using Thunderbolt 3, you are using the USB-C DisplayPort alternate mode. They are separate things, since there are also machines that have USB-C ports that support DisplayPort alt mode, but not Thunderbolt 3, such as the MacBook 12” [1].

                                                So, why do you care about USB-C Thunderbolt 3 ports if you are going to hook up a DisplayPort display?

                                                (BTW. it seems that Apple’s wording is intentionally muddy here for marketing purposes.)

                                                [1] https://support.apple.com/en-us/HT206587

                                                1. 1

                                                  I use a TB3 to dual DisplayPort adapter, so it only takes one port. I can guarantee you it is not using USB-C alt-mode.

                                                  1. 1

                                                    Now you are adding new data points. The default (and much cheaper) thing to do is to hook up a DisplayPort display directly to a Mac Mini or MacBook. Which is done using a regular passive DisplayPort <-> USB-C cable.

                                                    1. 1

                                                      No, I’m not.

                                                      You asked what’s wrong with a HDMI port. I told you: takes away video streams that would otherwise be available over DisplayPort.

                                                      Whether they’re routed over 3 USB-C to DP cables using Alt Mode, or via a TB3 adapter is irrelevant.

                                                      Go look at any tech forum with people having issues with displays: a decent chunk of them it’s because they’re using HDMI, because it was literally designed for TVs and receivers, being used for computer displays is an after thought, and it’s very apparent.

                                                      1. 1

                                                        HDMI doesn’t “take away” video streams, Apple does. If Apple really wanted, they could’ve added ability to use 3rd video stream using USB-C, but they didn’t. There is really nothing stopping them, except maybe the Intel chip that may not have a 3rd DP output.

                                                        1. 1

                                                          The UHD 630 supports 3 displays over dp hdmi or edp.

                                                          Apple chose to include hdmi which means one of those outputs from the igpu is used or “taken away” from potential as a DP output over USB-c/TB3.

                                            2. 1

                                              It’s entirely possible Apples reasoning is aesthetic, but to me, a HDMI port is useless, and usually adding a HDMI port means you lose something else (see: the 2018 Mac mini that only supports 2x4k displays over TB3 because the third ‘supported’ display must be over HDMI).

                                              HDMI 2.0 supports 4k displays. The Mac Mini specs explicitly state that you can drive three 4k screens:

                                              Up to three displays: Two displays with 4096-by-2304 resolution at 60Hz connected via Thunderbolt 3 plus one display with 4096-by-2160 resolution at 60Hz connected via HDMI 2.0

                                              https://www.apple.com/mac-mini/specs/

                                              1. 1

                                                That’s what I said. It forces one display of the three to be hdmi, which IMO is garbage compared to DP. I’d rather have no HDMI and be able to drive 3 displays over TB3/DP

                                                1. 1

                                                  Your comment was vague, it seemed to suggest that you cannot drive three 4k displays, but the point is that one of them has to be driven through HDMI. Fair enough.

                                                  Apple’s rationale is very logical. Quite some people use Mac Mini’s as media centers. They’ll have a TV with HDMI connectors and HDMI cables. So, it lowers the friction for a significant chunk of the audience for a tiny subset that insists on driving three 4k displays through DP. I am not saying that it is not a legitimate use case, but a niche. Apple will probably tell you to buy a Mac Pro or something.

                                                  1. 1

                                                    What is vague about this:

                                                    the 2018 Mac mini that only supports 2x4k displays over TB3 because the third ‘supported’ display must be over HDMI

                                                    I would bet money Apple do not include HDMI on a Mac mini for those few people who still try to run a media centre on one. Apple’s “solution” (in terms of what they support feature wise and expect people would use) is AppleTV.

                                                    They provide HDMI because it’s designed as a “bring your own display” device and a bunch of cheap shit displays have HDMI input rather than DP.

                                            3. 2

                                              Another reason is that the HDMI connector is bigger than the side of the MacBook Pro. Mini and micro HDMI connectors could fit but hey, even if it’s HDMI you need not-so-common adapters or special cables so USB-C/TB3 is not a bad alternative.

                                          2. 2

                                            The t480s does have 2 USB-C ports for breaking out to more exotic ports but having a nice selection of ports is great.

                                          1. 9

                                            Additionally, the technology landscape had shifted away from the tools we chose in late 2012 (jQuery, Signals, and direct DOM manipulation) and toward a paradigm of composable interfaces and clean application abstractions.

                                            I always find statements like this amusing. Composable interfaces and clean application abstractions are what I always heard was what programs were supposed to be. Did people in 2012 not care about writing good programs?

                                            Are they going to look back in another seven years and say “we shifted away from react, redux, and virtual DOM manipulation toward a paradigm of composable interfaces and clean application abstractions” as the winds shift again? Or will it shift to “we shifted away from X toward performant interfaces and clean application implementations?”

                                            Just silly.

                                            1. 5

                                              Judging by [other] tech companies’ blog posts, there always seems to be enough time to move to $CURRENT_JS_ZEITGEIST_FRAMEWORK versus actually writing clean code to make your choice of libraries/frameworks irrelevant in the long run.

                                              To their credit, it looks like Slack did the less sexy thing here while also upgrading to the current hotness.

                                              1. 7

                                                FWIW, React is 5 years old now. Where I work, we’ve been using it for all of that time and don’t have any plans to switch. Sure, maybe we’d use Preact to save some bytes on the wire sometimes, but it’s still fundamentally the same.

                                                I’m not saying there will never be a thing that replaces React or that there aren’t people out there using some new hotness. My point is more that React is fundamentally easier to reason about that jQuery DOM manipulation, and until someone offers a real step change, I’d expect a lot of folks to stick with it.

                                                1. 3

                                                  Related to this, I’m always surprised when a game company is able to switch rendering libraries (OpenGL -> Vulkan) in a few man-weeks but then I remember they usually abstract over it in their framework/engine.

                                                2. 7

                                                  Did people in 2012 not care about writing good programs?

                                                  No they did not and they don’t now.

                                                  1. 3

                                                    A more accurate way of phrasing it would be “Additionally, as the original team got expanded and replaced, the Slack team had shifted away from the rapid prototyping tools we used in late 2012 and toward a paradigm of composable interfaces and clean application abstractions.” Apparently, they think their company is the whole universe.

                                                    1. 1

                                                      It was a lot more work and discipline to develop and maintain a nicely organized codebase with their old toolsthan with their new tools, partly because composability and clean abstractions weren’t explicit design goals for those tools. React/redux really was a major improvement over previous front-end arrangements.

                                                    1. 28

                                                      The folks working with Python and Ruby and Perl (and PHP) are jealous of the way a Java programmer can create an uberjar, and they are jealous of the way a Golang programmer can create a binary that has no outside dependencies — and so the Python programmer, and the Ruby and Perl and PHP programmer, they turn to Docker, which allows them to create the equivalent of an uberjar. But if that is what they want, maybe they should simply use a language that supports that natively, without the need for an additional technology?

                                                      Because “Use another language” is a thought terminating cliche that does not make use of the expertise on hand, the libraries/ecosystem at play and the business constraints? Because work into single binary Python blobs like PyOxidizer are relatively new, so solutions like Docker (arbitrary userland in a box) are the next best thing?

                                                      Programming languages have their strengths and weaknesses. In that sense, they are not equal. It would be foolish to change out the tech stack, switch to Java, just because someone thinks he understands version pinning better in Maven than Docker image hashes and tags (and therefore it must be the fault of the technology that he learned one stack before the other). It’s easier to update your understanding than making extra work for yourself.

                                                      As to the MySQLdb import, I often tell people to use “-m pip” invocation because it allows you to specify which interpreter, and therefore install location, to use. Relying on fragile, potentially name-stomping scripts like “pip3” isn’t a good idea - it can result in unpredictable and broken install paths.

                                                      Docker is a flawed technology in that it conflates build artifacts and distribution together in the same context (Dockerfile, multi-stage builds et al). Despite its flaws it has been quite successful. I believe that better tooling in optimizing/slimming down Docker images will materialize as opposed to businesses switching languages just because their devops guys want to optimize their side of the business. Still, I have heard of (usually) Golang using businesses quickly trying to evolve a missing ecosystem as they go. That’s an insane amount of work (and best of luck to those in such situations!). So it’s not unheard of, I guess.

                                                      1. 5

                                                        Because work into single binary Python blobs like PyOxidizer are relatively new,

                                                        I was using Python app -> exe packing tools a decade and a half ago. They’ve never worked well.

                                                        1. 6

                                                          I use them pretty often these days and they work just fine.

                                                          1. 6

                                                            Google uses a packing tool for python binaries, they come out as self-contained .par files. I think this is the open source version. It works fabulously within Google at least.

                                                          2. 6

                                                            Because “Use another language” is a thought terminating cliche

                                                            Perhaps… but

                                                            Despite its flaws it has been quite successful.

                                                            So is this, and I think a more harmful one, because it stalls progress.

                                                          1. 1

                                                            Very nice. Is the (b ~ Double) trick needed because () gets picked by defaulting rules; and if so, is this only a problem in GHCi (which does more defaulting) or would it also affect .hs files given to GHC?

                                                            Nitpick: I would define KB as 1000, MB as 1000000, KiB as 1024 and MiB as 1024*1024. I would definitely avoid the names KBi and MBi, which look like typos for the latter ;)

                                                            1. 2

                                                              Very nice. Is the (b ~ Double) trick needed because () gets picked by defaulting rules

                                                              No. I described in the blog post the transition steps:

                                                              • Bytes -> Double
                                                              • Bytes -> b
                                                              • (b ~ Double) => Bytes -> b

                                                              It’s needed because otherwise type inference doesn’t work. The defaulting is a different error/issue that is an artifact of GHCi trying to help the inferencer, but it doesn’t work if you use it outside of that context.

                                                              You need this trick to make the syntactic pattern work with type inference at all, it’s not particular to my demonstration using GHCi. I wouldn’t go to the effort of writing a blog post about it otherwise. This demonstration/trick links up with a related issue in other languages where you can’t really have return type polymorphism. You’re absolutely permitted this in Haskell but it’s easy to break inference if you don’t use type families, functional dependencies, associated types, or this trick. What all of these techniques have in common is that they let you create a relationship or equality between types that helps type inference. Haskell has no reason to assume that just because you used a numeric literal as a function that you mean the particular instance Bytes -> Double. The argument type of a function does not imply the return type, it could be anything.

                                                              This article about functional dependencies describes the problem and motivates a particular solution: https://wiki.haskell.org/Functional_dependencies

                                                              Nitpick: I would define KB as 1000, MB as 1000000, KiB as 1024 and MiB as 1024*1024. I would definitely avoid the names KBi and MBi, which look like typos for the latter ;)

                                                              Seems reasonable. I’m not trying to publish a library here so I’m not going to change it, but anybody that feels inspired to do so should probably follow your suggestion here.

                                                            1. 9

                                                              In Haskell:

                                                              data Bytes =
                                                                  B
                                                                | KB
                                                                | MB
                                                              
                                                              instance (b ~ Double) => Num (Bytes -> b) where
                                                                fromInteger i B =
                                                                  fromInteger i
                                                                fromInteger i KB =
                                                                  fromInteger $ i * 1024
                                                                fromInteger i MB =
                                                                  fromInteger $ i * 1024 * 1024
                                                              
                                                              instance (b ~ Double) => Fractional (Bytes -> b) where
                                                                fromRational r B =
                                                                  fromRational r
                                                                fromRational r KB =
                                                                  fromRational $ r * 1024
                                                                fromRational r MB =
                                                                  fromRational $ r * 1024 * 1024
                                                              
                                                              Prelude> 100 B
                                                              100.0
                                                              Prelude> 100 KB
                                                              102400.0
                                                              Prelude> 100 MB
                                                              1.048576e8
                                                              
                                                              1. 3

                                                                I had no idea that was possible. Would you mind explaining a bit more in detail how it works? Do you need any language extensions?

                                                                1. 2

                                                                  Do you need any language extensions?

                                                                  You need flexible instances and ~, usually from TypeFamilies. These are things I have turned on by default in all of my application projects.

                                                                  Would you mind explaining a bit more in detail how it works?

                                                                  Warning: This explanation won’t work great if you (generic you, I know contivero knows Haskell) know literally zero Haskell. If that’s the case, uhhhh, buy my book? http://haskellbook.com

                                                                  The Num and Fractional type classes are the basis for integral and fractional literals in Haskell. Every numeric literal in Haskell is polymorphic until the instance is resolved to a concrete type. 1 :: Num a => a and 1.0 :: Fractional a => a, where :: is type ascription and can be read as “has type.”

                                                                  The (b ~ Double) isn’t strictly necessary if you don’t care about type inference. You could elide it and then the examples would look like:

                                                                  Prelude> 100 B :: Double
                                                                  

                                                                  The essence of it is in the weird shape of the instance type: Num (Bytes -> b). We’re making an instance for numerical literals that is function-typed. We’ve said the inputs must be values from our Bytes type. This makes it so that in the expression: 100 B, the 100 gets resolved to a function which multiples the underlying number by the magnitude expressed in the data constructor passed to it as an argument, be it B, KB, or whatever else.

                                                                  Now, hypothetically, we might know that we always want Bytes -> Double. If we don’t care about type inference, then our instance can be pretty simple:

                                                                  instance Num (Bytes -> Double) where
                                                                  

                                                                  And we’re done, but that didn’t satisfy me. I wanted to see if I could get fancy syntax. If you try it unqualified, you get:

                                                                  Prelude> 100 KB
                                                                  
                                                                  <interactive>:7:1: error:
                                                                      • No instance for (Num (Bytes -> ())) arising from a use of ‘it’
                                                                          (maybe you haven't applied a function to enough arguments?)
                                                                      • In the first argument of ‘print’, namely ‘it’
                                                                        In a stmt of an interactive GHCi command: print it
                                                                  

                                                                  GHCi will default the return type to () when the instance head is Bytes -> Double. So the stages of evolution are:

                                                                  Bytes -> Double
                                                                  Bytes -> b
                                                                  (b ~ Double) => Bytes -> b
                                                                  

                                                                  The weird part is, (b ~ Double) => Bytes -> b and Bytes -> Double are the same type. b ~ Double just means, “b is Double”. However, that part of the type-checker runs at a different time than instance resolution.

                                                                  What we really want is “instance local functional dependencies” and that’s exactly what this trick accomplishes. See more about functional dependencies here: https://wiki.haskell.org/Functional_dependencies

                                                                  What the type (b ~ Double) => Bytes -> b lets us do is “capture” uses of function-typed numerical literals whose inputs are Bytes and that have a return type whose type is unknown, then we supply a concrete type for the return type with the type equality b ~ Double after the instance is already resolved.

                                                                  You can’t overlap them:

                                                                  Duplicate instance declarations:
                                                                        instance (b ~ Double) => Num (Bytes -> b)
                                                                          -- Defined at /home/callen/work/units/src/Lib.hs:40:10
                                                                        instance (b ~ Integer) => Num (Bytes -> b)
                                                                          -- Defined at /home/callen/work/units/src/Lib.hs:49:10
                                                                  

                                                                  But if the input types are different, totally kosher:

                                                                  data Bytes =
                                                                      B
                                                                    | KB
                                                                    | MB
                                                                  
                                                                  instance (b ~ Double) => Num (Bytes -> b) where
                                                                    fromInteger i B =
                                                                      fromInteger i
                                                                    fromInteger i KB =
                                                                      fromInteger $ i * 1024
                                                                    fromInteger i MB =
                                                                      fromInteger $ i * 1024 * 1024
                                                                  
                                                                  data BytesI =
                                                                      Bi
                                                                    | KBi
                                                                    | MBi
                                                                  
                                                                  instance (b ~ Integer) => Num (BytesI -> b) where
                                                                    fromInteger i Bi =
                                                                      i
                                                                    fromInteger i KBi =
                                                                      i * 1024
                                                                    fromInteger i MBi =
                                                                      i * 1024 * 1024
                                                                  
                                                                  Prelude> 100 B
                                                                  100.0
                                                                  Prelude> 100 Bi
                                                                  100
                                                                  

                                                                  An older application of this trick where I originally explored it: https://github.com/bitemyapp/buttress/blob/master/src/Buttress/Time.hs#L58

                                                                  1. 2

                                                                    Thanks! That’s a neat trick. The number acting as a function was one of the main things confusing me.

                                                              1. 32

                                                                This guy is a far better hype man than he is anything else.

                                                                edit:

                                                                Try to use it yourself if you think it is good. Send me a message later if I was right or wrong.

                                                                I didn’t say he was bad, actually I think he is a great hype man, one of the best in this space. The way he appeals to surface level curiosity while keeping facts just obscure enough to solicit donations[1] is a work of art. It is a valuable lesson to know how to manipulate people at a large scale. If he starts a marketing consultancy, I think he might do very well.

                                                                To the author of V: I really want you to succeed, if everything promised worked as advertised It would be a great thing for everyone.

                                                                [1] https://www.patreon.com/vlang

                                                                1. 3

                                                                  In fairness I assumed this was work done in spare time and not something being paid for with $800 monthly donations, maybe I should have done more research.

                                                                  1. 3

                                                                    I am a bit jealous, I don’t know how to start an OSS project with so many donations. Being liberal with what you promise seems to help.

                                                                    I hope it is a “fake it till you make it” more than a “cut and run”. Obviously if everything promised worked as advertised It would be a great thing for everyone.

                                                                    1. 3

                                                                      Rates vary and my city tends to be expensive, but 800/mo seems unlikely to fund more than a little hobby work a week. I suppose if you were already setup (no debts to service) you could make it work in a cheap area…

                                                                      1. 7

                                                                        I think lots of stuff like this is done for ego and personal satisfaction rather than the money. The money is icing on the cake. There’s another benefit that hyping projects might bring. So, the job interview goes like this:

                                                                        Interviewer: “Do you have any prior projects with the impact that justifies the high-paying position you’re applying for?”

                                                                        V developer: “I made a language that (big claims here). Easier than Rust. I open-sourced it on Github. As you see, it had four, thousand stars in no time.”

                                                                        Interviewer: “Wow, that’s pretty impressive to pull that off and get so many users.”

                                                                        Yet, hardly anything was delivered. Add this project as another data point on why Github stars are meaningless to me. If anything, they make me more skeptical of a project.

                                                                        1. 3

                                                                          I never said it is livable, I just just think that is enough incentive to exaggerate the truth.

                                                                    2. 3

                                                                      Are you aware your comment above, as it appears at the time of me writing this reply, is a raw and pure ad hominem, with absolutely no merit-based argument at all? Could you please try to provide some verifiable technical criticism instead?

                                                                      1. 27

                                                                        Ok, the language itself has more than 3800 stars on github, but most of the libraries in this repository are empty stubs:

                                                                        Let’s compare to zig, an equivalent project made by a serious person with many contributors and 3000 stars on github:

                                                                        The difference? The V guy is a better hype man. The Zig guy spent far more time working on things. I didn’t say he was bad, actually I think he is a great hype man.

                                                                        1. 25

                                                                          musl-libc is another example of a project that has very little hype, but represents a significant contribution to the open source community at large, with incredibly high quality standards. It’s been around for years, yet making less than V on Patreon.

                                                                          I honestly feel a little guilty about this. I’ve done some marketing to hype up Zig and so I’m making more than Rich does with musl, even though it has been around longer than Zig as well. Furthermore Zig ships with musl and a lot of the standard library is ported from musl, so the Zig project benefits in a huge way from musl. I’m donating $5/mo on Patreon to musl, but I dunno, it doesn’t seem fair to give that low amount. But I’m also not making a living wage yet, so… it also doesn’t feel right to just give a large portion of my income away.

                                                                          1. 6

                                                                            For now everyone should look after themselves and not feel guilty, but I do think collectively we need to do something to fix the broken nature of open source funding.

                                                                            1. 6

                                                                              And create a funding model that isn’t contingent on HN hype/Github stars.

                                                                              1. 2

                                                                                This is tantamount to, “nullify the power social influence has over allocation of resources.” Not saying some progress can’t be made, but realize what you’re up against here.

                                                                                There are some political ideologies inadvertently end up trying to shift society towards social power being even more influential rather than less. Given how easy it is to monopolize celebrity, this is bad for solidarity & equality.

                                                                            2. 1

                                                                              Thank you so much! That is exactly the kind of a comment I was hoping for, backed with some concrete references. This gives so much more substance and weight/value to me as a reader than the original one, significantly boosting the speed with which I can evaluate the subject. Thanks again!

                                                                              1. -1

                                                                                Language version 0.0.12 that’s been just released has not very mature libraries. Developed by 1 person. Sorry about that.

                                                                                1. 5

                                                                                  For all the hype you’ve been generating, I think people expected some kind of 1.0 release, or at least all the promised features to actually be implemented.

                                                                              2. 9

                                                                                From the patreon page:

                                                                                C/C++ translation
                                                                                V can translate your entire C/C++ project and offer you the safety, simplicity, and up to 200x compilation speed up.
                                                                                
                                                                                Hot code reloading
                                                                                Get your changes instantly without recompiling!
                                                                                Since you also don't have to waste time to get to the state you are working on after every compilation, this can save a lot of precious minutes of your development time.
                                                                                

                                                                                Maybe it will reach these goals one day, but it doesn’t do them now.

                                                                                I will give you some time to find that in the repository and verify it.

                                                                                1. 0

                                                                                  https://github.com/vlang/doom

                                                                                  Full code next week, but you can already build a major file transpiled from C to V and replace the object file in the project.

                                                                                  1. 5

                                                                                    is that C++ too? How about the hot code reloading? It isn’t a full project either like you say.

                                                                                    1. 5

                                                                                      That’s one file though, not the entire game like you seem to be implying.

                                                                                2. 1

                                                                                  I don’t know man, just from a few moments glance through this it looks like a serious effort that probably took him a significant amount of time. I can’t imagine it would be so great to have invested so much time and then see people being so critical, especially in an unfounded way.

                                                                                  1. 22

                                                                                    There’s some context here: for the past few months he’s been making pretty extreme claims about V’s features, and attacking anyone who expressed any skepticism. He also refused to explain how any of it works, just saying we should wait until the open release. Well… it’s the open source release and it turns out the skeptics were right.

                                                                                    1. -1

                                                                                      I never attacked anyone. Do you have examples of my attacks or extreme claims?

                                                                                      1. 42

                                                                                        My examples will be released in 2 weeks.

                                                                                    2. 7

                                                                                      It isn’t unfounded, see comment above - and any time anyone posts anything, you can expect criticism. It happens all the time.

                                                                                      I didn’t say he was bad, actually I think he is a great hype man.

                                                                                      1. -1

                                                                                        I only receive constant criticism like from you in this thread :) I don’t bother to post criticism. Any examples?

                                                                                        1. 5

                                                                                          I’d like to note that, to me, most of your replies here just look like damage control. This kind of comment is usually not well-received in technical forums such as Lobste.rs. Don’t respond to every comment you don’t like - let your work speak for itself!

                                                                                    3. 1

                                                                                      Hi

                                                                                      Can you please point out specific things that don’t work as expected or things that I “hype” on the website?

                                                                                      Thanks

                                                                                      1. 22
                                                                                        • hot code reloading
                                                                                        • C++ translation
                                                                                        • “a strong modularity” (this isn’t grammatically correct)
                                                                                        • compiles to native binaries without dependencies…except libcurl or other libraries you obviously depend on, not to mention a C compiler. That is a dependency whether you like it or not.
                                                                                        • you mention doom being translated to V, your repo only shows what looks like a single file being translated
                                                                                        • you give an example of a “powerful web framework” yet show no code to back up that claim
                                                                                        • you do concurrency in the most lazy and inefficient way possible and promise to have something that big companies struggle with by the end of this year
                                                                                        • you claim being able to cross compiling…except from non-macOS to macOS
                                                                                        • it only looks like you support amd64 processors from the code I read
                                                                                        • you claim no null yet have both perfect c interoperability and optionals. What happens when the c libraries the user wants to use require the use of null? What happens when the optional is not filled with the target data?

                                                                                        Need I go on?

                                                                                        1. 4

                                                                                          Can you substantiate your claim that

                                                                                          V compiles ≈1.2 million lines of code per second per CPU core

                                                                                          from the website?

                                                                                          1. 4

                                                                                            Generating 1.2 million lines of code with:

                                                                                            print "fn main() {"
                                                                                            
                                                                                            for i = 0, 1200000, 1
                                                                                            do
                                                                                              print "println('hello, world ')"
                                                                                            end
                                                                                            
                                                                                            print "}"
                                                                                            

                                                                                            I got the following error:

                                                                                            $ time v 1point2mil.v
                                                                                            pass=2 fn=`main`
                                                                                            panic: 1point2mil.v:50003
                                                                                            more than 50 000 statements in function `main`
                                                                                                    2.43 real         2.13 user         0.15 sys
                                                                                            

                                                                                            Note that this is 50,000 ish lines of code in TWO SECONDS.

                                                                                            1. 3

                                                                                              Generating 1.2 million lines of code with: I patched the compiler to remove the arbitrary 50’000 statement restriction (and also disabled calling out to the C compiler, so that it doesn’t artificially inflate compilation times), and I got these times:

                                                                                              % time compiler/v test.v
                                                                                              
                                                                                              Edit: remembered another fun one: The generated C has a baseline of 69 warnings (I did not make that up) then one for every string literal, since the type of `tos` uses `unsigned char *` instead of `char *`.
                                                                                              /home/matheus//.vlang//test.c
                                                                                              14.58user 0.60system 0:15.61elapsed 97%CPU (0avgtext+0avgdata 1311836maxresident)k
                                                                                              0inputs+91504outputs (0major+316215minor)pagefaults 0swaps
                                                                                              

                                                                                              Some other things I also noticed:

                                                                                              • The 1000 byte global allocation at the start is used for format string literals suffixed with a !. If you generate a string that exceeds this length, the generated code aborts with an assertion failure from malloc().
                                                                                              % cat test.v
                                                                                              fn main() {
                                                                                              x := 1
                                                                                              println('$x [redacted repetitions]'!)}
                                                                                              % v test.v; clang ~/.vlang/test.c -w; ./a.out
                                                                                              /home/matheus//.vlang//test.c
                                                                                              malloc(): corrupted top size
                                                                                              fish: “./a.out” terminated by signal SIGABRT (Abort)
                                                                                              
                                                                                              • V supports goto but doesn’t check whether labels are defined, so they crash in the C compiler;
                                                                                              • V doesn’t ever convert their integer literals to integers internally; There’s a check for division by zero, but it’s comparing the literal to '0' - the string. So this won’t compile:
                                                                                              fn main() {
                                                                                                x := 1 / 0
                                                                                                println('$x')
                                                                                              }
                                                                                              

                                                                                              But this does:

                                                                                              fn main() {
                                                                                                x := 1 / 00
                                                                                                println('$x')
                                                                                              }
                                                                                              
                                                                                      1. 3
                                                                                        1. Usenet but P2P and sneakernet / airgapped-wifi compatible.

                                                                                        2. Airdrop (but Win/Mac/Lin compatible)

                                                                                        3. Podcast app for iOS. I use Apple’s right now but it’s just not good enough if you listen to 500 ep+ history podcasts that are best listened to linearly from the start of the show.

                                                                                        My SSG needs have been satisfied by Zola. I use it for bitemyapp.com. I use Wunderlist for to-do.

                                                                                        1. 4
                                                                                          1. Usenet but P2P and sneakernet / airgapped-wifi compatible.

                                                                                          You should checkout https://www.scuttlebutt.nz/, it’s pretty interesting.

                                                                                          1. 1

                                                                                            I’m aware of it, I don’t have a detailed explanation of why prepared, but it didn’t fit what I was looking for.

                                                                                            I really want something more like a Usenet that can’t easily be killed off, E2E encrypted, and that is convenient for normal folks to use.

                                                                                            Scuttlebutt/Patchwork are about as close as it gets but it’s not really there.

                                                                                            This is plainly absurd for something that’s meant to be pick up and go for 99.99% of the population. This excludes even most programmers who aren’t highly motivated to use a novel mode of communication.

                                                                                            If Usenet and mailing lists were still used for actual conversations and E2E had happened in a user friendly way for email (no webmail I guess?), then I wouldn’t care even a fraction as much.

                                                                                            1. 1

                                                                                              I mean, imho a pub isn’t that crazy, considering people are ok with Mastodon home servers, etc. Even usenet requires somebody to have setup an nntp server. Are you assuming that everyone has to be running a pub?

                                                                                              1. 2

                                                                                                I don’t think we’re reading what I linked the same way at all, perhaps even in the opposite direction.

                                                                                                I have serious qualms with Mastodon too, particularly with how disinterested Eugen is in the care and feeding of the fediverse and in cooperating with others or letting his users make their own decisions about who they want to speak with. I’m happy for Eugen that he’s getting what he wants but it doesn’t scratch the itch I have.

                                                                                                Further, in the GNU Social / fediverse, that server owns your identity. That’s not what I want and I don’t think it’s an improvement over email. Email is less obnoxious in this particular respect. With email, at least if you own a domain you can move your account around.

                                                                                          2. 2

                                                                                            Podcast app for iOS.

                                                                                            Have you tried Overcast? Not sure how it works with a 500 ep+ history, but just thought I’d recommend this since it’s a LOT better than the Apple default.

                                                                                            1. 1

                                                                                              Another vote for Overcast from me. I find it decent for long unplayed lists and I do know there’s a web interface that might help too.

                                                                                              1. 1

                                                                                                I’m not paying $10 a year for an app that hasn’t improved much in the last few years just to not hear ads.

                                                                                                I’ve used Overcast and paid for Overcast Premium in the past. It’s not much of an improvement over Apple Podcasts and it doesn’t handle the “prolific history podcast” use-case more than marginally better.

                                                                                            2. 1

                                                                                              Usenet but P2P and sneakernet / airgapped-wifi compatible.

                                                                                              Sounds a bit like uucp.

                                                                                              1. 1

                                                                                                Well when there’s a Bonjour/mDNS-aware uucp out there let me know.

                                                                                            1. 1

                                                                                              Markdown in a git repository mostly. Sometimes we use YAML for metadata.

                                                                                              1. 4

                                                                                                Rust + Actix backend and ReasonML + ReasonReact frontend for a record expungement app.

                                                                                                1. 0

                                                                                                  That’s not comprehension syntax.

                                                                                                  1. 2

                                                                                                    Approaching Rust from a Haskell-y angle, traits look superficially similar to Haskell typeclasses. However, if I remember/understand correctly, the lack of Higher Kinded Types in Rust prevents you from implementing a hierarchy of typeclasses like Functor, Applicative & Monad. Is this correct? I’d be interested in reading a more detailed explanation of the issue.

                                                                                                    1. 2

                                                                                                      It’s more complicated than that. Rust doesn’t have higher kinded types, but that isn’t exactly why something like Monad isn’t useful in Rust.

                                                                                                      Rust Traits can derive on top of other traits just like the hierarchy of type classes w/ Functor -> Applicative -> Monad.

                                                                                                      This thread goes into the details: https://twitter.com/withoutboats/status/1027702531361857536?lang=en

                                                                                                      This pertains to a particular application of Monad and monadic syntax, but it gets across why the problems are more particular than not having HKTs.

                                                                                                    1. 3

                                                                                                      @bitemyapp I think you made a mistake with the Associated Type:

                                                                                                      class Hello a where
                                                                                                        type Return
                                                                                                        helloWorld :: a -> Return
                                                                                                      

                                                                                                      Associated Types must mention their type parameter right? So it’d have to look more like:

                                                                                                      class Hello a where
                                                                                                        type Return a
                                                                                                        helloWorld :: a -> Return a
                                                                                                      
                                                                                                      1. 1

                                                                                                        Yeah, fixed. Thanks!

                                                                                                      1. 4

                                                                                                        Learning to leverage types, a REPL, getting fluent with one editor (I don’t care which), learning how to quickly and efficiently share my screen for pairing with others on problems.

                                                                                                        http://bitemyapp.com/posts/2018-03-14-how-i-stream-coding.html touches on some of what I use for pairing.

                                                                                                        Writing logs as I debug problems is another one. I basically journal my thoughts, what hypotheses I have, what I’m observing, and why I may have changed my mind in the process. When I’ve exhausted the data I can pull/observe and the experiments I can run, I review my log. There’s several reasons this is important:

                                                                                                        • I’ve discovered the causes of problems in the past solely because I could scan up and down my log.

                                                                                                        • I can MUCH more efficiently and effectively bring a coworker or outside expert up to speed on a problem.

                                                                                                        • Issues that have required debugging can now be checked into version control and searched in case a future problem arises to see if it’s a regression/repeat or if there are commonalities in the occurrences of the problems.

                                                                                                        Related but different: I’ve also shifted away since about 2012 or 2013 from “debugging” as an act that requires an actual injected or interactive debugger like GDB toward observability. Especially WRT making extensive use of structured, queryable logs. My Road to Damascus moment on this one was realizing I fixed a problem with a Python parser after many hours of ipdb debugging in 5 minutes once I switched to using logs and scanned them with my eyes linearly.

                                                                                                        1. 20

                                                                                                          On the one hand, the article has moments that make it seem dubiously sourced.

                                                                                                          On the other hand, I’m reminded of a conference I went to years ago where some genius from NSA was harranguing me about the security dangers of non-US born programmers working in US firms or on open source projects. I asked him why he was not more worried about Chinese built motherboards and he refused to believe me that the USA depended on imports of Chinese motherboards.

                                                                                                          1. 21

                                                                                                            “The dangers of non-US born programmers working on open source projects”?

                                                                                                            The spook mentality is something to behold.

                                                                                                            1. 3

                                                                                                              It is well known that Linus is a Russian spy and goes by the name Linyos Torovoltos. :)

                                                                                                              The link above was submitted recently here.

                                                                                                              1. 2

                                                                                                                I recall, from Linus’s autobiography, that he claimed that his parents were fans of the soviet union & until their divorce he was raised as a red-diaper baby. Obviously, that hasn’t made him into a stalinist as an adult, but if somebody wanted to spin it that way more seriously I’m sure they could. (I recall back in the naughts some microsoft fanboys trying to make those claims & paint the whole open source movement with that brush, but I don’t think they were very successful.)

                                                                                                              2. 1

                                                                                                                It was kind of jarring - I am not born in USA either!

                                                                                                                1. 1

                                                                                                                  And you come over here with that foreign thinking devising things like RTLinux that jeopardize the profits of domestic, closed-source, RTOS vendors. That’s exactly the kind of thing our non-corrupt, capitalist government was worried about! ;)

                                                                                                              3. 3

                                                                                                                I think I don’t trust this article on its face value at all. Bloomberg could be telling a fake story on the demand of someone who wants to further his agenda against Chinese hardware. Also they might partake in a stock manipulation scheme, it was very effective if that’s the case.

                                                                                                                Going to wait and see what’s happening before I conclude anything from here.

                                                                                                                1. 6

                                                                                                                  I really really really doubt it. Bloomberg in particular is financial news, its reporters are constantly seeing how (to quote Matt Levine) Everything Is Shareholder Fraud. Publishing something like this with willful negligance would open them up to soooooo many lawsuits.

                                                                                                                  Not to mention that Bloomberg is beholden to basically no one, as an organization. They make huge amounts of money selling their stuff. While Businessweek is being pushed to be more self-sufficient, there’s still a lot of value in them being trustworthy.

                                                                                                                  Also making up a story, publishing it in a major outlet, and profiting off of a stock trade afterwards. Oh my god that is a “go directly to jail do not pass go do not collect $200” move, especially if you’re just a journalist and not a multi-billionaire. And these people know it, because they’re the ones reporting on other people doing this kind of thing!

                                                                                                                  I’m not saying the story is most definitely right, but it’s a serious outfit.

                                                                                                                  1. 4

                                                                                                                    Yeah, the idea that either Businessweek itself or the author is fabricating this story is hard to swallow – if they did, then somebody’s making incredibly poor decisions.

                                                                                                                    On the other hand, I could absolutely buy the idea that they’ve been fed fabricated evidence. This story exists at the intersection of international relations, espionage, and big business. I can imagine some Angelton-esque character whose paranoia only became pathological after they got in a position of power who suddenly decided that supply chain meddling by chinese intelligence is inevitable & decided to try to trigger an outright ban by orchestrating a high-profile story. (After all, once upon a time our president campaigned on heavily limiting chinese imports, so it’s possible that somebody in intelligence capable of faking convincing-looking Apple & Amazon documentation thought it’d be an easy sell.)

                                                                                                                      1. 1

                                                                                                                        Author doesn’t seem to mention particular Bloomberg stories that those authors wrote that turned out to be false.

                                                                                                                        It’s not outside the realm of possibility but I find it hard to believe that there’s a pattern of a couple authors making stuff up in multiple stories for that outfit – or even reporting stories that end up being wrong due to misleading sources, unless they’ve got damned good excuses. I’ll believe it when I see the stories he’s talking about.

                                                                                                                        (BadBIOS is getting mentioned in that thread, but BadBIOS was broken by Ars Technica, right? Anyhow, the whole BadBIOS story was – accurately – reported as “this one researcher thinks this is happening, and other researchers think it’s possible but probably bullshit” in all the coverage I saw. While it was questionably newsworthy, that coverage wasn’t wrong or misleading, unless you only read the headlines – which are almost always wrong & misleading, even in good articles.)

                                                                                                                1. 1

                                                                                                                  OK, this sounds very intriguing, if only for being so disconnected to how I/we usually work; and I want to dig into it when I’m fresher, but if someone could ELI5 to after-hours-me, that’d be splendid.

                                                                                                                  As for PRs, I did find myself longing for better tools to tackle larger Pull Requests than what the GitHub UI has to offer. Mainly “saving progress” somehow, or marking individual files as “read”.

                                                                                                                  1. 3

                                                                                                                    As for PRs, I did find myself longing for better tools to tackle larger Pull Requests than what the GitHub UI has to offer. Mainly “saving progress” somehow, or marking individual files as “read”.

                                                                                                                    There’s a bunch of commercial services that do this, I think https://reviewable.io/ is one. A past client of mine uses Reviewable.