Molly Rocket is the studio of game developer Casey Muratori, with posts on The Witness, API design, hashing and immediate-mode GUIs.
HN links it for Meow Hash and Casey's criticism of object-oriented orthodoxy, which commenters tie to a growing pushback among game developers against standard best practices.
> This coding style is standard practice for Win32 API development.
Do you have a public style guide that indicates this?
I worked at Microsoft, and while there are teams that (very unfortunately) went with this "diamond" style of error handling, code written in the CNF (Cutler Normal Form) style, such as the kernel code, use gotos and a central cleanup point at the end of the function, which is also the same style used by the Linux kernel: https://github.com/torvalds/linux/blob/master/Documentation/process/coding-style.rst#7-centralized-exiting-of-functions
The "diamond" style hinders readability, especially when you have many levels of indentation). While it may be a practice adopted by many people, that is does not necessarily mean that it is good style. Even Steve McConnell's Code Complete, a book published by Microsoft Press, recommends early returns over deeply nested if statements for error handling: https://books.google.com/books?id=LpVCAwAAQBAJ&lpg=PA764&ots=GGPtgbClMI&dq=code%20complete%20indentation&pg=PA392#v=onepage&q&f=false
Unfortunately, the Win32 API is full of technical debt, many of which cannot be repaid due to backwards compatibility reasons. Given it is likely most application code written against Win32 is in C++, the ideal approach would be to follow an object-oriented style and use destructors and RAII rather than cleanup functions, but that is not the world we live in.
The design of the Win32 API should not be used as guidelines for good coding…
The original announcement post of Meow Hash from 2018 at https://mollyrocket.com/meowhash said:
> […] we wanted a fast, non-cryptographic hash for use in change detection and deduplication.
and
> To our surprise, we found a lack of published, well-optimized, large-data hash functions. Most hash work seems to focus on small input sizes (for things like dictionary lookup) or on cryptographic quality.
and also
> The Meow hash is not designed for cryptography and therefore we make no claims about its security. Assume it is completely insecure.
I found it confusing then that the cryptanalysis of Meow Hash posted here said:
> The creators make a few security claims; we will break them all. In particular, we present three main attacks […]
But then looking at the Meow Hash GitHub repo I see in the README:
> Due to recent discoveries by Peter Schmidt-Nielsen, we have decided to reclassify Meow hash 0.5/calico from level 3 to level 1. This means that we recommend not to use this hash for message authentication codes, or for hash tables in scenarios where collision induced denial-of-service attacks are a concern.
> We have seen no evidence that the hash is unfit for non-adversarial/non-cryptographic purposes, and continue to believe that it is amongst the best in this regard.
> For level 3/MAC capabilities consider migrating to SipHash. Do not migrate to any hash not advertising MAC capabilities as these are almost certainly much weaker than Meow 0.5. If the performance of…
Polynomial splines are pretty shitty compared to rational splines for animation and modeling, but they both have the problem of non-constant speed. It gets much worse with higher degree curves. You fix that by letting the animator separately specify a scalar speed curve so he can control where things speed up and down. To make this curve be natural to manipulate, it must be specified relative to an arc length parameterization. You can sometimes profitably combine the arc length reparameterization curve and the pre-integrated user-specified speed remapping into a single remapping curve that's baked out to disk, so the run-time curve evaluator only has to deal with a single level of parameter remapping on top of the raw spline.
This is just a fact of life with splines. They have non-uniform speed in their raw form and you have to deal with it. It's also why quaternion slerping being constant angular speed isn't a real advantage over lerp-and-normalize because they both trace out the same path and often you'll want to overlay a speed curve anyway (and lerp-and-normalize's speed is only barely non-uniform). Evaluate-and-normalize is the way to go for quaternions. It works great for multi-way skeletal animation blending and higher-order rotation interpolation (just do the spline evaluation in R^4 and project back onto the unit sphere). Casey has an old email that goes into some of this: http://mollyrocket.com/911.txt
No, it's the opposite - it doesn't have to drag around pointless layers of unused abstractions, and all the bugs that are there are bugs of subject matter, not of surrounding boilerplate. Such code minimizes the surface area and degrees of freedom, hence not leaving space for bugs.
The more I program, the more I'm convinced that - unless you've coded identical software many times before - code needs to grow organically and stay as focused and close to the problem as possible. Abstractions should follow naturally and be done "just in time". If they're needed, they have to be written either way, and you're not saving time by writing them up front (focused code is easy to refactor).
Of course with experience, you learn that some patterns of change are likely to occur, or that some touches of abstractions here and there are very beneficial. But beyond that, I feel the best way is to write simplest code possible, wait for it to be needed elsewhere, and then DRY up semantics.
I liked the posts of Casey Muratori, which explain roughly this mindset, calling it "semantic compression" and "compression-oriented programming": https://mollyrocket.com/casey/stream_0019.html.
Regarding the speed, meow_hash is certainly performant, but when hashing a single file, b3sum actually seems to be faster, perhaps due to using more threads. Could meow_hash be made even faster by running more operations in parallel?
time ~/.cargo/bin/b3sum ubuntu-19.10-beta-desktop-amd64.iso
0899b731b6b57d75a65273fe29d54802653b3bbe3bae6732140c487c4f0ece71 ubuntu-19.10-beta-desktop-amd64.iso
real 0m0,180s
user 0m1,735s
sys 0m0,092s
time meow_example ubuntu-19.10-beta-desktop-amd64.iso
meow_example 0.5/calico - basic usage example of the Meow hash
(C) Copyright 2018-2019 by Molly Rocket, Inc. (https://mollyrocket.com)
See https://mollyrocket.com/meowhash for details.
Hash of "ubuntu-19.10-beta-desktop-amd64.iso":
E5CC524A-522BDE7E-ED34A277-5C7D73AF
real 0m0,766s
user 0m0,119s
sys 0m0,645s
This benefit of test-driven design is not obvious (at least it wasn't for me) until you really experience it. Several years back I wasn't aware of the concept of dependency injection, but independently discovered it while trying to unit test some error logging functionality. Previously I'd always used a global/singleton logger object. That always felt wrong, but I always assumed it was necessary until writing unit tests forced me to avoid that design.
Also note that TDD is not the only way of getting this benefit. IMHO Paul Graham's essay Programming Bottom Up[1] and Casey Muratori's concept of 'compression-oriented programming'[2] both espouse this same idea of improving API design by "writing examples of their use."
[1] http://www.paulgraham.com/progbot.html
[2] https://mollyrocket.com/casey/stream_0019.html