<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dw="https://www.dreamwidth.org">
  <id>tag:dreamwidth.org,2017-04-25:3165654</id>
  <title>Kevin Reid's blog</title>
  <subtitle>Kevin Reid</subtitle>
  <author>
    <name>Kevin Reid</name>
  </author>
  <link rel="alternate" type="text/html" href="https://kpreid.dreamwidth.org/"/>
  <link rel="self" type="text/xml" href="https://kpreid.dreamwidth.org/data/atom"/>
  <updated>2023-08-14T17:53:59Z</updated>
  <dw:journal username="kpreid" type="personal"/>
  <entry>
    <id>tag:dreamwidth.org,2017-04-25:3165654:55967</id>
    <link rel="alternate" type="text/html" href="https://kpreid.dreamwidth.org/55967.html"/>
    <link rel="self" type="text/xml" href="https://kpreid.dreamwidth.org/data/atom/?itemid=55967"/>
    <title>Link: “Role Of Algorithms”</title>
    <published>2023-08-14T17:53:59Z</published>
    <updated>2023-08-14T17:53:59Z</updated>
    <category term="programming"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">&lt;p&gt;Consider this part of my current series of programming advice posts. &lt;a href="https://matklad.github.io/2023/08/13/role-of-algorithms.html"&gt;Role Of Algorithms, by matklad:&lt;/a&gt;

&lt;blockquote&gt;
&lt;p&gt;“Algorithms” are a useful skill not because you use it at work every day, but because they train you to be better at particular aspects of software engineering.

&lt;p&gt;...

&lt;p&gt;&lt;em&gt;Second,&lt;/em&gt; algorithms teach about properties and invariants. Some lucky people get those skills from a hard math background, but algorithms are a much more accessible way to learn them, as everything is very visual, immediately testable, and has very short and clear feedback loop.&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;There's a lot here I agree with or at least consider worth thinking about. However, the article is focused on &lt;em&gt;the process of learning to program&lt;/em&gt;, and I'd like to suggest a different perspective too: rather than “you don't use algorithms at work every day”, every single function you write can be considered as an algorithm. Many of them are &lt;em&gt;trivial&lt;/em&gt; algorithms, but if you have the experience with looking through the algorithmic lens, you can &lt;em&gt;notice as you write&lt;/em&gt; (or read) useful facts like:

&lt;ul&gt;
&lt;li&gt;“Oops, this is going to be &lt;a href="https://en.wikipedia.org/wiki/Computational_complexity"&gt;O(&lt;var&gt;N&lt;/var&gt;²)&lt;/a&gt;; can I do it more efficiently?”
&lt;li&gt;“This &lt;em&gt;almost&lt;/em&gt; has an invariant or postcondition that …, but it could be violated if …, so let's think about where to check for that and what we want to do about it then, or what will happen if we don't check.”
&lt;/li&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=kpreid&amp;ditemid=55967" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2017-04-25:3165654:55795</id>
    <link rel="alternate" type="text/html" href="https://kpreid.dreamwidth.org/55795.html"/>
    <link rel="self" type="text/xml" href="https://kpreid.dreamwidth.org/data/atom/?itemid=55795"/>
    <title>Tests must document what they are testing for</title>
    <published>2023-07-19T23:40:09Z</published>
    <updated>2023-07-19T23:40:09Z</updated>
    <category term="programming"/>
    <category term="google"/>
    <category term="testing"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">&lt;p&gt;While I worked at Google I spent a lot of time doing testing and code review. One of the things I learned from this is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A test must document what it is testing.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This doesn’t have to be an explicit comment (it might be adequately explained by the name of the test, or the code in it), but either way, it should be obvious to maintainers what the goal of the test is — what property the code under test should have. “This test should continue to pass” is not a sufficient explanation of the goal. Why? Consider these scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A test failed. Does that mean…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;…the test successfully detected the loss of a desired behavior? 
(This is the ideal case, that we hope to enable by writing and running tests.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;…the test incidentally depended on something that is changing but is not significant, such as ordering of something unordered-but-deterministic, or the exact sequence of some method calls?
(Ideally, test assertions will be written precisely so that they accept everything that meets requirements, but this is not always feasible or correctly anticipated.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;…the test incidentally depended on something that is being intentionally changed, but it wasn’t intending to test that part of the system, which has its own tests?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;A test no longer compiles because you deleted a function (or other declaration/item/symbol) it used. Does that mean…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;…the test demonstrates a reason why you should not delete that function?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;…the test needs to be rewritten to test the thing it is about, without incidentally using that function?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;…the function is necessary to perform this test, so it should continue to exist but be private?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;If tests specify the property they are looking for, then maintainers can quickly decide how to respond to a test failure — whether to count it a bug in the code under test, or to change or delete the test.&lt;/p&gt;

&lt;p&gt;If they do not, then maintainers will waste time keeping the code conformant to obsolete requirements, or digging through revision history to determine the original intent.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=kpreid&amp;ditemid=55795" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2017-04-25:3165654:55416</id>
    <link rel="alternate" type="text/html" href="https://kpreid.dreamwidth.org/55416.html"/>
    <link rel="self" type="text/xml" href="https://kpreid.dreamwidth.org/data/atom/?itemid=55416"/>
    <title>Writing some Rust libraries</title>
    <published>2023-05-06T22:18:47Z</published>
    <updated>2023-05-06T22:23:21Z</updated>
    <category term="all is cubes"/>
    <category term="programming"/>
    <category term="rust"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">&lt;p&gt;The piece of software I've mostly been working on recently is still &lt;a href="https://github.com/kpreid/all-is-cubes"&gt;All is Cubes&lt;/a&gt; (&lt;a href="https://kpreid.dreamwidth.org/tag/all+is+cubes"&gt;posts&lt;/a&gt;). However, this one project has sprawled out into a lot of things to do with Rust.

&lt;p&gt;For example, something about my coding style (or maybe my attention to error messages) seems to turn up compiler bugs — such as
&lt;a href="https://github.com/rust-lang/rust/issues/80772"&gt;#80772&lt;/a&gt;,
&lt;a href="https://github.com/rust-lang/rust/issues/88630"&gt;#88630&lt;/a&gt;,
&lt;a href="https://github.com/rust-lang/rust/issues/95324"&gt;#95324&lt;/a&gt;,
&lt;a href="https://github.com/rust-lang/rust/issues/95873"&gt;#95873&lt;/a&gt;,
&lt;a href="https://github.com/rust-lang/rust/issues/97205"&gt;#97205&lt;/a&gt;,
&lt;a href="https://github.com/rust-lang/rust/issues/104025"&gt;#104025&lt;/a&gt;,
&lt;a href="https://github.com/rust-lang/rust/issues/105645"&gt;#105645&lt;/a&gt;,
&lt;a href="https://github.com/rust-lang/rust/issues/108481"&gt;#108481&lt;/a&gt;, and
&lt;a href="https://github.com/rust-lang/rust/issues/109067"&gt;#109067&lt;/a&gt;. (Which is not to say that Rust is dreadfully buggy — on average, the experience is reliable and pleasant.) I'm also taking some steps into contributing to the compiler, so I can get some bugs (and pet peeves) fixed myself. (The first step, though, was simply running my own code against &lt;code&gt;rustc&lt;/code&gt; nightly builds, so I can help spot these kinds of bugs &lt;em&gt;before&lt;/em&gt; they get released.)

&lt;p&gt;I've also taken some code from All is Cubes and split it out into libraries that might be useful for others.

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The first one was &lt;a href="https://docs.rs/exhaust/latest/exhaust/"&gt;&lt;code&gt;exhaust&lt;/code&gt;&lt;/a&gt;, a trait-and-macro library that provides the ability to take a type (that implements the &lt;code&gt;Exhaust&lt;/code&gt; trait) and generate all possible values of that type. The original motivation was to improve on (for my purposes) &lt;a href="https://docs.rs/strum/latest/strum/trait.IntoEnumIterator.html"&gt;&lt;code&gt;strum::IntoEnumIterator&lt;/code&gt;&lt;/a&gt; (which does this for &lt;code&gt;enum&lt;/code&gt;s but always leaves the &lt;code&gt;enum&lt;/code&gt;’s fields with the &lt;code&gt;Default&lt;/code&gt; value) by generating &lt;code&gt;enum&lt;/code&gt;s and &lt;code&gt;struct&lt;/code&gt;s arbitrarily recursively.

&lt;p&gt;(Exhaustive iteration is perhaps surprisingly feasible even in bigger domains than a single &lt;code&gt;enum&lt;/code&gt;; if you have a simple piece of arithmetic, for example, it only takes a few seconds to run it on &lt;em&gt;every&lt;/em&gt; 32-bit integer or floating-point value, and look for specific outcomes or build a histogram of the results.)

&lt;li&gt;&lt;p&gt;The second one, published just yesterday, is &lt;a href="https://docs.rs/rendiff/latest/rendiff/"&gt;&lt;code&gt;rendiff&lt;/code&gt;&lt;/a&gt;, a (slightly) novel image diffing algorithm which I invented to compare the output of All is Cubes’ renderer test cases. Its value is that it is able to compensate for the results of rounding errors on the positions of the edges of objects in the scene — instead of such errors counting against a budget of allowable wrong pixels, they're just counted as correct, by observing that they exist at a neighboring position in the other image.

&lt;/p&gt;&lt;/li&gt;&lt;/p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=kpreid&amp;ditemid=55416" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2017-04-25:3165654:55189</id>
    <link rel="alternate" type="text/html" href="https://kpreid.dreamwidth.org/55189.html"/>
    <link rel="self" type="text/xml" href="https://kpreid.dreamwidth.org/data/atom/?itemid=55189"/>
    <title>end and beginning</title>
    <published>2023-05-06T21:47:54Z</published>
    <updated>2023-05-06T21:47:54Z</updated>
    <category term="life"/>
    <category term="google"/>
    <dw:security>public</dw:security>
    <dw:reply-count>2</dw:reply-count>
    <content type="html">&lt;p&gt;One month ago, April 7, 2023, I left my job at Google.

&lt;p&gt;At the time, I was working on &lt;a href="https://earthengine.google.com/"&gt;Earth Engine&lt;/a&gt; — “a planetary-scale platform for Earth science data &amp;amp; analysis”, or if you're looking at it through my lens, a cloud computing service which interprets parallel, pure-functional programs interleaved with image processing and database queries. (It’s a really interesting system, and if you'd like to check it out yourself, it's free for non-commercial use. Play with big data and make interesting pictures!)

&lt;p&gt;One of the elements of the plan I made for the future after this choice was that, this year, I would get to take some time to pursue my personal projects and interests unencumbered by “having a day job” or intellectual property contracts — and I have been doing that.

&lt;p&gt;Now, as you can see from the fact that my blog is as silent the last month as it has been for the last two years, that didn't instantly bring back all the energy for blogging I had in 2012. But, step one is to break the awkward silence. Step two is to post about stuff I've been doing. Maybe someday I'll get to step “update my website”.&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=kpreid&amp;ditemid=55189" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2017-04-25:3165654:54839</id>
    <link rel="alternate" type="text/html" href="https://kpreid.dreamwidth.org/54839.html"/>
    <link rel="self" type="text/xml" href="https://kpreid.dreamwidth.org/data/atom/?itemid=54839"/>
    <title>All is Cubes progress report</title>
    <published>2020-10-13T18:04:01Z</published>
    <updated>2020-10-13T18:04:27Z</updated>
    <category term="webgl"/>
    <category term="all is cubes"/>
    <category term="web"/>
    <category term="rust"/>
    <category term="programming"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">&lt;p&gt;I woke up last night with a great feature idea which on further examination was totally inapplicable to &lt;a href="https://github.com/kpreid/all-is-cubes"&gt;All is Cubes&lt;/a&gt; in its current state. (I was for some dream-ish reason imagining top-down tile- and turn-based movement, and had the idea to change the cursor depending on whether a click was a normal move or an only-allowed-because-we're-debugging teleport. This is totally unlike anything I've done yet and makes no sense for a first-person free movement game. But I might think about cursor/crosshair changes to signal what clicking on a block would do.)

&lt;p&gt;That seems like a good excuse to write a status update. Since &lt;a href="https://kpreid.dreamwidth.org/54200.html"&gt;my last post&lt;/a&gt; I've made significant progress, but there are still large missing pieces compared to the original JavaScript version.

&lt;p&gt;(The hazard in any rewrite, of course, is second-system effect — “we know what mistakes we made last time, so let's make zero of them this time”, with the result that you add both constraints and features, and overengineer the second version until you have a complex system that doesn't work. I'm trying to pay close attention to signs of overconstraint.)

&lt;p style="text-align: center;"&gt;
&lt;a href="https://switchb.org/kpreid/2020/all-is-cubes-10-13-progress.png"&gt;&lt;img src="https://switchb.org/kpreid/2020/all-is-cubes-10-13-progress.png" alt="[screenshot]" style="margin: 4px; max-height: 40em; max-width: 90%; border: none; padding: 1px; box-shadow: #22A 0px 1px 4px 0px; vertical-align: middle;"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Now done:

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;There's a web server you can run (&lt;code&gt;aic-server&lt;/code&gt;) that will serve the web app version; right now it's just static files with no client-server features.

&lt;li&gt;&lt;p&gt;Recursive blocks exist, and they can be rendered both in the WebGL and raytracing modes.

&lt;li&gt;&lt;p&gt;There's an actual camera/character component, so we can have perspective projection, WASD movement (but not yet mouselook), and collision.

  &lt;p&gt;For collision, right now the body is considered a point, but I'm in the middle of adding axis-aligned box collisions. I've improved on the original implementation in that I'm using the raycasting algorithm rather than making three separate axis-aligned moves, so we have true “continuous collision detection” and fast objects will never pass through walls or collide with things that aren't actually in their path.

&lt;li&gt;&lt;p&gt;You can click on blocks to remove them (but not place new ones).

&lt;li&gt;&lt;p&gt;Most of the lighting algorithm from the original, with the addition of RGB color.

  &lt;p&gt;Also new in this implementation, &lt;code&gt;Space&lt;/code&gt; has an explicit field for the “sky color” which is used &lt;em&gt;both&lt;/em&gt; for rendering and for illuminating blocks from outside the bounds. This actually reduces the number of constants used in the code, but also gets us closer to “physically based rendering”, and allows having “night” scenes without needing to put a roof over everything. (I expect to eventually generalize from a single color to a &lt;a href="https://en.wikipedia.org/wiki/Skybox_(video_games)"&gt;skybox&lt;/a&gt; of some sort, for outdoor directional lighting and having a visible horizon, sun, or other decorative elements.)

&lt;li&gt;&lt;p&gt;Rendering space in chunks instead of a single list of vertices that has to be recomputed for every change.

&lt;li&gt;&lt;p&gt;Added a data structure (&lt;code&gt;EvaluatedBlock&lt;/code&gt;) for caching computed details of blocks like whether their faces are opaque, and used it to correctly implement interior surface removal and lighting. This will also be critical for efficiently supporting things like rotated variants of blocks. (In the JS version, the &lt;code&gt;Block&lt;/code&gt; type was a JS object which memoized this information, but here, &lt;code&gt;Block&lt;/code&gt; is designed to be lightweight and copiable (because I've replaced having a &lt;code&gt;Blockset&lt;/code&gt; defining numeric IDs with passing around the actual &lt;code&gt;Block&lt;/code&gt; and letting the &lt;code&gt;Space&lt;/code&gt; handle allocating IDs), so it's less desirable to be storing computed values in &lt;code&gt;Block&lt;/code&gt;.)

&lt;li&gt;&lt;p&gt;Made nearly all of the GL/&lt;a href="https://github.com/phaazon/luminance-rs/"&gt;luminance&lt;/a&gt; rendering code not wasm-specific. That way, we can support "desktop application" as an option if we want to (I might do this solely for purposes of being able to graphically debug physics tests) and there is less code that can only be compiled with the wasm cross-compilation target.

&lt;li&gt;&lt;p&gt;Integrated &lt;a href="https://crates.io/crates/embedded-graphics"&gt;embedded_graphics&lt;/a&gt; to allow us to draw text (and other 2D graphics) into voxels. (That library was convenient because it came with fonts and because it allows implementing new drawing targets as the minimal interface "write this color (whatever you mean by color) to the pixel at these coordinates".) I plan to use this for building possibly the entire user interface out of voxels — but for now it's also an additional tool for test content generation.
&lt;/p&gt;&lt;/li&gt;&lt;/p&gt;&lt;/li&gt;&lt;/p&gt;&lt;/li&gt;&lt;/p&gt;&lt;/li&gt;&lt;/p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/p&gt;&lt;/li&gt;&lt;/p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/p&gt;&lt;/li&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Still to do that original Cubes had:

&lt;ul&gt;
&lt;li&gt;Mouselook/pointer lock.
&lt;li&gt;Block selection UI and placement.
&lt;li&gt;Any UI at all other than movement and targeting blocks. I've got ambitious plans to build the UI itself out of blocks, which both fits the "recursive self-defining blocks" theme and means I can do less platform-specific UI code (while running headlong down the path of problematically from-scratch inaccessible video game UI).
&lt;li&gt;Collision with recursive subcubes rather than whole cubes (so slopes/stairs and other smaller-than-an-entire-cube blocks work as expected).
&lt;li&gt;Persistence (saving to disk).
&lt;li&gt;Lots and lots of currently unhandled edge cases and "reallocate this buffer bigger" cases.
&lt;/li&gt;&lt;/li&gt;&lt;/li&gt;&lt;/li&gt;&lt;/li&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Stuff I want to do that's entirely new:

&lt;ul&gt;
&lt;li&gt;Networking; if not multiplayer, at least the web client saves its world data &lt;em&gt;to a server.&lt;/em&gt; I've probably already gone a bit too far down the path of writing a data model without consideration for networking.
&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=kpreid&amp;ditemid=54839" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2017-04-25:3165654:54586</id>
    <link rel="alternate" type="text/html" href="https://kpreid.dreamwidth.org/54586.html"/>
    <link rel="self" type="text/xml" href="https://kpreid.dreamwidth.org/data/atom/?itemid=54586"/>
    <title>Method chaining: why it's problematic and what happens in Rust</title>
    <published>2020-09-12T15:26:27Z</published>
    <updated>2020-09-12T15:27:51Z</updated>
    <category term="programming"/>
    <category term="rust"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">&lt;p&gt;In &lt;a href="https://kpreid.dreamwidth.org/54314.html"&gt;my previous post&lt;/a&gt;, I said “Rust solved the method chaining problem!” Let me explain.

&lt;p&gt;It's popular these days to have “builders” or “fluent interfaces”, where you write code like

&lt;blockquote&gt;&lt;pre&gt;let house = HouseBuilder()
    .bedrooms(2)
    .bathrooms(2)
    .garage(true)
    .build();&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;The catch here is that (in a “conventional” memory-safe object-oriented language, not Rust) each of the methods here has the option of:

&lt;ol&gt;
&lt;li&gt;Mutating &lt;code&gt;self&lt;/code&gt;/&lt;code&gt;this&lt;/code&gt;/recipient of the message (I'll say &lt;code&gt;self&lt;/code&gt; from here on), and then returning &lt;code&gt;self&lt;/code&gt;.
&lt;li&gt;Returning a different object with the new configuration.
&lt;li&gt;“Both”: returning a new object which wraps &lt;code&gt;self&lt;/code&gt;, and declaring it a contract violation for the caller to use &lt;code&gt;self&lt;/code&gt; further (with or without actually documenting that contract).
&lt;/li&gt;&lt;/li&gt;&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;The problem — in my opinion — with the fluent interface pattern by itself is that it’s underconstrained in this way: in a type (1) case, which is often the simplest to implement, the caller is free to completely ignore the return values,

&lt;blockquote&gt;&lt;pre&gt;let hb = HouseBuilder();
hb.bedrooms(2);
hb.bathrooms(2);
hb.garage(true);
let house = hb.build();&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;but this means that the fluent interface cannot change from a type 1 implementation to a type (2) or (3), even if this is a non-breaking change to the &lt;em&gt;intended&lt;/em&gt; usage pattern. Or to look at it from the “callee misbehaves” angle rather than “caller misbehaves”, the builder is free to return something &lt;em&gt;other than&lt;/em&gt; &lt;code&gt;self&lt;/code&gt;, thus causing the results to differ depending on whether the caller used chained calls or not.

&lt;p&gt;(Why is this a problem? From my perspective on software engineering, it is highly desirable to, whenever possible, &lt;em&gt;remove unused degrees of freedom&lt;/em&gt; so that the interaction between two modules contains no elements that were not &lt;em&gt;consciously designed in.&lt;/em&gt;)&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;Now here's the neat thing I noticed about Rust in this regard: Rust prevents this confusion from happening by default!&lt;/p&gt;

&lt;p&gt;In Rust, there is no garbage collector and no arbitrary object-reference graph: by default, everything is either &lt;em&gt;owned&lt;/em&gt; (stored in memory belonging to the caller, like a non-pointer variable or field in C) or &lt;em&gt;borrowed&lt;/em&gt; (referred to by a “reference” which is statically checked to last no longer than the object does via its ownership). The consequence of this is that &lt;em&gt;every method&lt;/em&gt; must explicitly take an owned or borrowed &lt;code&gt;self&lt;/code&gt;, and this means you can't equivocate between writing a setter and writing a chaining method:

&lt;blockquote&gt;&lt;pre&gt;impl HouseBuilder {
    /// This is a setter. It mutates the builder passed by reference.
    fn set_bedrooms(&amp;mut self, bedrooms: usize) {
        self.bedrooms = bedrooms;
    }

    /// This is a method that consumes self and returns a new object of
    /// the same type; “is it the same object” is not a meaningful question.
    /// Notice the lack of “&amp;”, meaning by-reference, on “self”.
    fn bedrooms(mut self, bedrooms: usize) -&amp;gt; HouseBuilder {
        // This assignment mutates the *local variable* “self”, which the
        // caller cannot observe because the value was *moved* out of the
        // caller's ownership.
        self.bedrooms = bedrooms;
        self                       // return value
    }
}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Now, it's &lt;em&gt;possible&lt;/em&gt; to write a setter that can be used in chaining
fashion:

&lt;blockquote&gt;&lt;pre&gt;    fn set_bedrooms(&amp;mut self, bedrooms: usize) -&amp;gt; &amp;mut HouseBuilder {
        self.bedrooms = bedrooms;
        self
    }&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;But because references have to refer to objects owned by &lt;em&gt;something&lt;/em&gt;, a method with this signature cannot just decide to return a different object instead. Well, unless it decides to return some object that's global, allocated-and-leaked, or present in some larger but non-global context. (And, having such a method will contaminate the entire rest of the builder interface with the obligation to either take &lt;code&gt;&amp;mut self&lt;/code&gt; everywhere or make the builder an implicitly copyable type, both of which would look funny.)

&lt;p&gt;So this isn't a perfect guarantee that everything that looks like a method chain/fluent interface is nonsurprising. But it's pretty neat, I think.

&lt;hr&gt;

Here's the rest of the code you'd need to &lt;a href="https://play.rust-lang.org/?version=stable&amp;amp;mode=debug&amp;amp;edition=2018&amp;amp;gist=6e660138a9c1f347a329799ccb3b5ca4"&gt;compile and play with&lt;/a&gt; the snippets above:

&lt;blockquote&gt;&lt;pre&gt;struct HouseBuilder {
    bedrooms: usize,
}

impl HouseBuilder {
    fn new() -&amp;gt; Self {
        HouseBuilder {
            bedrooms: 0
        }
    }

    fn build(self) -&amp;gt; String {
        format!("Home sweet {}br home!", self.bedrooms)
    }
}

fn main() {
    let h = HouseBuilder::new()
        .bedrooms(3)
        .build();
    println!("{:?}", h);
}&lt;/pre&gt;&lt;/blockquote&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=kpreid&amp;ditemid=54586" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2017-04-25:3165654:54314</id>
    <link rel="alternate" type="text/html" href="https://kpreid.dreamwidth.org/54314.html"/>
    <link rel="self" type="text/xml" href="https://kpreid.dreamwidth.org/data/atom/?itemid=54314"/>
    <title>Early thoughts on Rust</title>
    <published>2020-09-12T14:22:07Z</published>
    <updated>2020-09-12T15:27:02Z</updated>
    <category term="rust"/>
    <category term="programming"/>
    <category term="all is cubes"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">&lt;p&gt;I've now been programming in Rust for over a month (since the end of July). Some thoughts:

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;It feels a &lt;em&gt;lot&lt;/em&gt; like Haskell. Of course, Rust has no mechanism for enforcing/preferring lack of side effects, but the memory management, which avoids using a garbage collection algorithm in favor of statically analyzable object lifetimes, gives a very similar feeling of being a force which shapes every aspect of your program. Instead of having to figure out how to, at any given code location, fit all the information you want to preserve for the future into a return value, you instead get to store it somewhere with a plain old side effect, but you have to prove that that side effect won't conflict with anything else.

&lt;p&gt;And, of course, there are algebraic data types and type classes, er, traits.

&lt;li&gt;&lt;p&gt;It's nice to be, for once, living in a world where there's a library for everything and you can just use them by declaring a dependency on them and recompiling. Of course, there's risks here (unvetted code, library might be doing unsound &lt;code&gt;unsafe&lt;/code&gt;, unmaintained libraries you get entangled with), but I haven't had a chance to have this experience at all before.

&lt;li&gt;&lt;p&gt;The standard library design sure is a fan of short names like we're back in the age of “linker only recognizes 8 characters of symbol name”. I don't mind too much, and if it helps win over C programmers, I'm all in favor.

&lt;li&gt;&lt;p&gt;&lt;a href="https://kpreid.dreamwidth.org/54586.html"&gt;They (mostly) solved the method chaining problem!&lt;/a&gt; (This got long, so it's another post.)

&lt;/p&gt;&lt;/li&gt;&lt;/p&gt;&lt;/li&gt;&lt;/p&gt;&lt;/li&gt;&lt;/p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=kpreid&amp;ditemid=54314" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2017-04-25:3165654:54200</id>
    <link rel="alternate" type="text/html" href="https://kpreid.dreamwidth.org/54200.html"/>
    <link rel="self" type="text/xml" href="https://kpreid.dreamwidth.org/data/atom/?itemid=54200"/>
    <title>Cubes reboot: All is Cubes</title>
    <published>2020-08-09T15:06:50Z</published>
    <updated>2020-08-09T15:06:50Z</updated>
    <category term="all is cubes"/>
    <category term="webgl"/>
    <category term="cubes"/>
    <category term="programming"/>
    <category term="web"/>
    <category term="rust"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">&lt;p&gt;I've been getting back into playing Minecraft recently, and getting back into that frame of mind caused me to take another look at my &lt;a href="https://github.com/kpreid/cubes/"&gt;block-game-engine project titled "Cubes"&lt;/a&gt; (&lt;a href="https://kpreid.dreamwidth.org/tag/cubes"&gt;previous posts&lt;/a&gt;).

&lt;p&gt;I've fixed some API-change bitrot in Cubes so that it's runnable on current browsers; unfortunately the GitHub Pages build is broken so the running version that I'd otherwise link to isn't updated. (I intend to fix that.)

&lt;p&gt;The bigger news is that I've decided to rewrite it. Why?

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;There's some &lt;a href="https://github.com/kpreid/cubes/issues/71"&gt;inconsistency in the design&lt;/a&gt; of how block rotation works, and the way I've thought of to fix it is to start with a completely different strategy: instead of rotation being a feature of a block's behavior, there will be the general notion of blocks derived from other block definitions, so “this block but rotated” is such a derivation.
&lt;li&gt;&lt;p&gt;I'd like to start with a client-server architecture from the beginning, to support the options of both multiplayer and ✨ saving to the cloud!✨ — I mean, having a server which stores the world data instead of fitting it all into browser local storage.
&lt;li&gt;&lt;p&gt;&lt;strong&gt;I've been looking for an excuse to learn &lt;a href="https://www.rust-lang.org/"&gt;Rust&lt;/a&gt;.&lt;/strong&gt; And, if it works as I hope, I'll be able to program with a much better tradeoff between performance and high-level code.
&lt;/p&gt;&lt;/li&gt;&lt;/p&gt;&lt;/li&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;The new version is &lt;a href="https://github.com/kpreid/all-is-cubes"&gt;already on GitHub&lt;/a&gt;. I've given it the name “All is Cubes”, because “Cubes” really was a placeholder from the beginning and it's too generic.

&lt;p&gt;I'm currently working on porting (with improvements) various core data structures and algorithms from the original version — the first one being the voxel raycasting algorithm, which I then used to implement a raytracer that outputs to the terminal. (Conveniently, "ASCII art" is low-resolution and thus doesn't require too many rays.) And after getting that solid, I set up compiling the Rust code into WebAssembly to run in web browsers and render with WebGL.

&lt;p style="text-align: center;"&gt;
&lt;img src="https://switchb.org/kpreid/2020/all-is-cubes-first-console.png" alt="[console screenshot]" style="margin: 4px; max-height: 30em; max-width: 50%; border: none; padding: 1px; box-shadow: #22A 0px 1px 4px 0px; vertical-align: middle;"&gt;
&lt;img src="https://switchb.org/kpreid/2020/all-is-cubes-first-webgl.png" alt="[WebGL screenshot]" style="margin: 4px; max-height: 30em; max-width: 50%; border: none; padding: 1px; box-shadow: #22A 0px 1px 4px 0px; vertical-align:middle;"&gt;
&lt;/p&gt;

&lt;p&gt;(In the unlikely event that anyone cares, I haven't quite decided what to do with the post tags; I think that I will switch to tagging them all with &lt;a href="https://kpreid.dreamwidth.org/tag/all+is+cubes"&gt;all is cubes&lt;/a&gt;, but I might or might not go back and apply that to the old posts on the grounds that having a tag that gets everything is good and I'm not really giving the rewrite a &lt;em&gt;different&lt;/em&gt; name so much as taking the opportunity to replace the placeholder at a convenient time.)&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=kpreid&amp;ditemid=54200" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2017-04-25:3165654:53855</id>
    <link rel="alternate" type="text/html" href="https://kpreid.dreamwidth.org/53855.html"/>
    <link rel="self" type="text/xml" href="https://kpreid.dreamwidth.org/data/atom/?itemid=53855"/>
    <title>New hobby: 3D printing</title>
    <published>2019-04-14T19:03:40Z</published>
    <updated>2019-04-14T19:03:40Z</updated>
    <category term="electronics"/>
    <category term="life"/>
    <category term="3d-printing"/>
    <category term="3d"/>
    <category term="radio"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">&lt;p&gt;Just about a year ago, I acquired a 3D printer.

&lt;p&gt;I've been casually reading about the progress of hobbyist 3D printing since the RepRap days, but sometime in late 2017 I decided to seriously consider whether I should get one for myself. I'd already purchased items from printing services (i.materialise and Shapeways), both &lt;a href="https://www.thingiverse.com/thing:1156995" title="Servo Switch Plate Mount"&gt;existing&lt;/a&gt; and &lt;a href="https://www.thingiverse.com/thing:2983124" title="Case for Hyve Touch Synth with battery holder"&gt;of my own design&lt;/a&gt;, and that experience taught me that I wanted to do more and to iterate cheaper and faster. As a sanity check, I made a list of further things I thought I could make with one — not general themes but specific items to solve problems I had. That list was immediately filled with ten or so items, so I bought one.



&lt;p&gt;I purchased a Prusa i3 MK3 kit printer (despite, at the time, uncertainty about whether the MK3 design was flawed as a lot of people were reporting quality and reliability issues), set it up in April 2018, and have been printing things ever ever since (with very little trouble).

&lt;p&gt;I've been posting &lt;a href="https://www.thingiverse.com/switchborg/designs"&gt;my designs on Thingiverse&lt;/a&gt; (pictures there) and &lt;a href="https://github.com/kpreid?tab=repositories&amp;amp;q=3dp"&gt;on Github&lt;/a&gt; — rather, those that I have declared finished and documented. There's another 30 or so that aren't published, yet.

&lt;p&gt;(You can also see hints of some other ‘new hobbies’ in what I've been posting, but I'm overly fond of putting things in chronological or at least dependency order.)&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=kpreid&amp;ditemid=53855" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2017-04-25:3165654:53695</id>
    <link rel="alternate" type="text/html" href="https://kpreid.dreamwidth.org/53695.html"/>
    <link rel="self" type="text/xml" href="https://kpreid.dreamwidth.org/data/atom/?itemid=53695"/>
    <title>Update to A Visual Introduction to DSP for SDR</title>
    <published>2018-09-09T15:04:57Z</published>
    <updated>2018-09-09T15:04:57Z</updated>
    <category term="sdr"/>
    <category term="radio"/>
    <category term="amateur radio"/>
    <category term="web site"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">&lt;p&gt;&lt;a href="https://visual-dsp.switchb.org/"&gt;A Visual Introduction to DSP for SDR&lt;/a&gt; now includes some slides on digital modulation.

&lt;p&gt;I wrote these a long time ago but the wording was targeted at an amateur radio audience. I finally got around to tweaking it to be slightly more general and publishing the result.&lt;/p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=kpreid&amp;ditemid=53695" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2017-04-25:3165654:53317</id>
    <link rel="alternate" type="text/html" href="https://kpreid.dreamwidth.org/53317.html"/>
    <link rel="self" type="text/xml" href="https://kpreid.dreamwidth.org/data/atom/?itemid=53317"/>
    <title>Playing with analog feedback</title>
    <published>2018-08-10T02:50:59Z</published>
    <updated>2018-08-10T02:50:59Z</updated>
    <category term="music"/>
    <category term="video"/>
    <category term="audio"/>
    <category term="electronics"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">&lt;iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/WpHMC0LnaGI?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen="allowfullscreen"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=kpreid&amp;ditemid=53317" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2017-04-25:3165654:53011</id>
    <link rel="alternate" type="text/html" href="https://kpreid.dreamwidth.org/53011.html"/>
    <link rel="self" type="text/xml" href="https://kpreid.dreamwidth.org/data/atom/?itemid=53011"/>
    <title>HTTPS, finally</title>
    <published>2018-06-28T17:43:13Z</published>
    <updated>2018-06-28T18:06:12Z</updated>
    <category term="security"/>
    <category term="web site"/>
    <category term="web"/>
    <category term="apache"/>
    <category term="meta"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">&lt;p&gt;In further news of updating my personal web presence, I have finally set up HTTPS for &lt;a href="https://switchb.org/kpreid/"&gt;switchb.org&lt;/a&gt;. As I write this I'm working on updating all the links to it that I control.

&lt;p&gt;The thing I found underdocumented in Let's Encrypt/Certbot is: if you want to (or must) manually edit the HTTP configuration, what should the edits be? What I concluded was:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;VirtualHost *:443&amp;gt;
  ServerName &lt;var&gt;YOUR DOMAIN NAME&lt;/var&gt;
  Include /etc/letsencrypt/options-ssl-apache.conf
  SSLCertificateFile /etc/letsencrypt/live/&lt;var&gt;YOUR DOMAIN OR CERT NAME&lt;/var&gt;/cert.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/&lt;var&gt;YOUR DOMAIN OR CERT NAME&lt;/var&gt;/privkey.pem
  SSLCertificateChainFile /etc/letsencrypt/live/&lt;var&gt;YOUR DOMAIN OR CERT NAME&lt;/var&gt;/chain.pem

  &lt;var&gt;...rest of configuration for this virtual host...&lt;/var&gt;
&amp;lt;/VirtualHost&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notes:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/etc/letsencrypt/options-ssl-apache.conf&lt;/code&gt; (which of course may be in a different location depending on your OS and package manager) contains the basic configuration to enable SSL (&lt;code&gt;SSLEngine on&lt;/code&gt;) and certbot-recommended cipher options.
&lt;li&gt;You have to have a separate VirtualHost entry for *:443 and *:80; there's no way to copy the common configuration as far as I heard.
&lt;li&gt;By "&lt;var&gt;CERT NAME&lt;/var&gt;" I mean the name assigned to a multi-domain-name certificate if you have requested one. You can find out the certificate names with the command &lt;kbd&gt;certbot certificates&lt;/kbd&gt;. For a single domain it will be identical to the domain name.
&lt;/li&gt;&lt;/li&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=kpreid&amp;ditemid=53011" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2017-04-25:3165654:52842</id>
    <link rel="alternate" type="text/html" href="https://kpreid.dreamwidth.org/52842.html"/>
    <link rel="self" type="text/xml" href="https://kpreid.dreamwidth.org/data/atom/?itemid=52842"/>
    <title>Shiny new old blog</title>
    <published>2018-02-18T19:51:51Z</published>
    <updated>2018-02-18T19:51:51Z</updated>
    <category term="meta"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">&lt;strong&gt;As of right now, I've imported my blog contents from LiveJournal to Dreamwidth. Everything older than this entry was originally posted on LJ.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;I've been procrastinating doing anything for a long time, because of the feeling that I really should move to a self-hosted blog that I can guarantee is forever unchanged. However, I haven't found satisfactory software or put much effort into it at all, and I think it's well past the point that it's more important to me to have a place to write than that it be the perfect customized URL-never-changes-again solution.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=kpreid&amp;ditemid=52842" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
</feed>
