HNHacker News
TopNewBestAskShowJobs

wgd

417 karma · joined October 23, 2011

Generalist Software Engineer and Electrical Engineer with experience ranging from circuit design/layout and microcontroller firmware, to backend servers and JavaScript frontends. Currently working as a Software Engineer at Estuary.
submissionscomments
wgd··on Passive Solar Water Desalination
This is some blog's restatement of an MIT press release, neither of which appear to name or link to the actual paper or other useful writeup.

But judging by the researcher names and the date I believe the actual paper is titled "Extreme salt-resisting multistage solar distillation with thermohaline convection" which appears to be available as a PDF at https://www.cell.com/joule/pdf/S2542-4351(23)00360-4.pdf

wgd··on Prophet: Automatic Forecasting Procedure
Disclaimer: I haven't looked at the linked library at all, but this is a theoretical discussion which applies to any task of signal prediction.

Out of all possible inputs, there are some that the model works well on and others that it doesn't work well on. The trick is devising an algorithm which works well on the inputs that it will actually encounter in practice.

At the obvious extremes: this library can probably do a great job at predicting linear growth, but there's no way it will ever be better than chance at predicting the output of /dev/random. And in fact, it probably does worse than a constant-zero predictor when applied to a random unbiased input signal.

Except that it's also usually possible to detect such trivially unpredictable signals (obvious way: run the prediction model on all but the last N samples and see how it does at predicting the final N), and fall back to a simpler predictor (like "the next value is always zero" or "the next value is always the same as the previous one") in such cases.

But that algorithm also fails on some class of inputs, like "the signal is perfectly predictable before time T and then becomes random noise". The core insight of the "No Free Lunch" theorem is that when summed across all possible input sequences, no algorithm works any better than another, but the crucial point is that you don't apply signal predictors to all possible inputs.

Another place this pops up is in data compression. Many (arguably all) compressors work by having a prediction or probability distribution over possible next values, plus a compact way of encoding which of those values was picked. Proving that it's impossible to predict all possible input signals correctly is equivalent to proving that it's impossible to compress all possible inputs.

Another way of thinking about this: Imagine that you're the prediction algorithm. You receive the previous N datapoints as input and are asked for a probability distribution over possible next values. In a theoretical sense every possible value is equally likely, so you should output a uniform distribution, but that provides no compression or useful prediction. Your probabilities have to sum to 1, so the only way you can increase the probability assigned to symbol A is to decrease the weight of symbol B by an equal amount. If the next symbol is A then congratulations, you've successfully done your job! But if the next symbol was actually B then you have now done worse (by any reasonable error metric) than the dumb uniform distribution. If your performance is evaluated over all possible inputs, the win and the loss balance out and you've done exactly as well as the uniform prediction would have.

wgd··on FTX’s balance sheet was bad
I remember getting those once a couple of months ago. It was so indescribably disappointing. I had never heard of FTX before that because I don't care about crypto-BS, but I feel like everything happening to FTX lately is a suitable punishment for inflicting those on the world and so I'm just sitting here with the metaphorical popcorn.
wgd··on The OK? Programming Language
It reminds me a little of https://vorpus.org/blog/notes-on-structured-concurrency-or-g... in how it forces concurrency to take place synchronously within a larger thread of execution and block until all sub-units are complete.
wgd··on The OK? Programming Language
> it's ultimately the class maintainer's responsibility

It's ultimately the responsibility of the programmer who's building a tool/product/etc, because everything is ultimately their responsibility.

As programmers we ~always have the nuclear option available to us of forking the code and implementing all the necessary accessors ourselves, but sometimes that's really just a bunch of pointless busywork and there's no reason we should have to put up with it in those cases.

This can be a contentious subject because there's a lot of nuance and the right answer is often context-dependent. But I personally think that the Java style of "we must absolutely protect the library user from themselves and childproof everything" is waaaay too far in the wrong direction.

I would much rather that a language have mechanisms to clearly communicate "don't touch this unless you have a good reason, but if you need to here's how" rather than saying in effect "you, the person using this library, are dumb and need to be prevented from messing with the library maintainer's perfect vision".

And so I think the "required acknowledgement" thing has the glimmer of a really neat innovation in it (although if I were to copy the idea for a language of my own I would probably make it obligatory, such that every struct allows breakglass access to private fields with a default acknowledgement, and all the library author can do is change the acknowledgement text).

wgd··on The OK? Programming Language
Jokes aside the compiler-checked acknowledgements are kind of clever. The example in the docs is deliberately confrontational, but there's a kernel of a neat idea there. Imagine needing to write:

  // I acknowledge that the internal structure of this data is subject to change without notice
  x = foo.state
Or perhaps:

  // I acknowledge that this data is a complicated graph of pointers and is easy to break in subtle ways
  foo.xyz[0].bar[1] = &foo.asdf[3]
Or perhaps:

  // I acknowledge that this data is heavily cached and I need to call rebuild() before changes take effect
  x.something = "Hello"
  x.rebuild()
wgd··on C99 doesn't need function bodies, or 'VLAs are Turing complete'
The issue of memory bounds is commonly handwaved away. Note that your desktop computer is technically not Turing complete either, since it only has access to a finite amount of memory+disk storage, and is thus a (very large) finite state machine since there are only a finite number of states it can be in.
wgd··on Berlin prepares 'huge thermos' to help heat homes in winter
I was wondering how exactly this hot water would be used, since in the US most hot water heating is done within a single building, but it turns out that Berlin has a large network of hot-water pipes for what is known as "district heating" [1], which as of last year served three quarters [2] of all households.

[1] http://www.seon.info/2013/09/andrew-deys-berlin-blog-distric... [2] https://www.cleanenergywire.org/news/city-berlin-aims-decarb...

wgd··on Contra Wirecutter on the IKEA air purifier
Regarding "reviews written by people who have actually touched the thing they're reviewing", I'm not sure Consumer Reports deserves to be listed these days either.

I bought a subscription a few months ago because I needed to buy several large appliances for my home, but all I found behind that paywall curtain was computer-generated tables of star ratings and statistics about mechanical reliability. Which is probably useful to somebody, but isn't something I found valuable.

I ended up ignoring CR's data tables, cancelling my subscription, and buying the same models of appliances my parents have because at least I could try those out in person and verify that they worked decently well without any glaring flaws.

wgd··on Photonic Chip Performs Image Recognition at the Speed of Light
The article implies that the weights are programmable, but the overall shape is fixed.
wgd··on Photonic Chip Performs Image Recognition at the Speed of Light
Equally important: "nine neurons". This is not a deep circuit.

When we say that a CPU is running at some frequency that's essentially the speed at which a signal propagates through all the gates of its slowest pipeline stage, and the individual gates have a transition frequency an order of magnitude higher.

So if a CPU is running at 4GHz, it completes a clock cycle in 0.25ns (250ps), but that means that individual transistors must have latencies <=0.025ns (25ps). If you built a tiny little 9-neuron single-layer network out of those transistors then the network's latency would be around the single-gate latency and it would appear to be 20x better than this photonic setup, and even if those 9 neurons were laid out sequentially it would outperform this photonic chip by 2x.

Now granted, that's comparing the performance of a mature IC process using equipment that cost billions of dollars to set up, to something that was built in a university lab on a substantially smaller budget, so direct performance comparisons aren't exactly fair in that sense. But it's also misleading to take a direct hardware implementation of an itty bitty neural network and handwave away the very real issues with scaling such an approach.

wgd··on No Dislikes has officially ruined YouTube for me
All models are wrong, but some are useful. The value of a theory is how accurately it allows you to predict future observations.

If AI-driven recommendation systems and a trend towards centralizing all discourse on giant social media platforms produces a result indistinguishable from the Dead Internet Theory, then the theory is a useful way of thinking about and engaging with the internet.

wgd··on Learning to think critically about machine learning
I mentored an FTC team that was using the vision system this year, and my overall impression was that the TensorFlow model was absolute garbage and probably performed worse than a simple "identify blobs by color" algorithm would have.

The vision model was tolerably decent at tracking incremental updates to object positioning, but for some reason would take 2+ seconds to notice that a valid object was now in view (which is quite a lot, in the context of a 30s autonomous period), and frequently identified the back walls of the game field as giant cubes.

wgd··on Distilling the Real Cost of Production Garbage Collectors [pdf]
> With reference counting there are no pauses, and memory is reclaimed immediately

You can't guarantee both of these properties at once, in the general case. Consider a very large tree of objects which are referenced through a single root node, and then that root node becomes eligible for reclamation. For a sufficiently large object graph, either reclamation will require a noticeable pause or some portion of the work will have to be deferred until later.

wgd··on 3M Cuts Output of PFAS Used in Chip Production
> Do not use soap

Using modern dish soap on cast iron is entirely fine, the detergents used are much softer than the sorts of lye-based soap that this advice stems from, and will not remove the baked-on (polymerized) seasoning. (It will slightly slow down the rate of seasoning accumulation by removing the thin layer of unpolymerized oil, but this can be fixed by just wiping on a thin coat of oil after washing and drying the pan. I usually don't even bother doing that much though.)

In general I think that most guidance for using cast iron is overly cautious and makes it sound like more of a hassle than it needs to be. At the end of the day it's a large hunk of metal, and there's very little you can do in the kitchen that will permanently mess it up.

edit: One piece of advice I do have: don't use a plastic spatula, they're a suboptimal choice people are forced into by easily-damaged cookware. Since that's not a concern with cast iron, you should get a thin metal spatula (example: https://www.amazon.com/dp/B0015R7P6O). The tip will always be exceedingly thin and never deform/melt/get torn up like a plastic spatula, and as a bonus it doubles as a very effective scraper for easy cleanup.

wgd··on Artificial sweeteners are associated with increased cancer risk
The obvious objection to almost every study of this sort is that associated with doesn't imply causality, and it could be that some third factor like "propensity to consume highly-processed food products" is responsible for the observed correlation. But from the abstract:

> Associations between sweeteners and cancer incidence were assessed by Cox proportional hazards models, adjusted for age, sex, education, physical activity, smoking, body mass index, height, weight gain during follow-up, diabetes, family history of cancer, number of 24-hour dietary records, and baseline intakes of energy, alcohol, sodium, saturated fatty acids, fibre, sugar, fruit and vegetables, whole-grain foods, and dairy products

So I have a more interesting question here: how effective are these sorts of statistical methods? Is it plausible to start out with a highly-biased population [1], adjust for twenty or so distinct factors, and get results that are actually meaningful?

[1] As I understand it, the study population consists of 102k French adults, self-selected via finding the relevant website and their willingness to go fill out a bunch of surveys. As TFA notes "[...] 78.5% of the participants included in the analysis were women, which could be considered a selection bias. Additional biases noted by the researchers were that participants were more likely to have higher educational levels, and to demonstrate health-conscious behaviors."

wgd··on Tail recursion, but modulo cons
There's a fascinating relationship between tail recursion and continuations, because any non-tail-recursive function call can in principle be made tail-recursive through conversion to explicit continuation-passing style.

For added fun, that continuation can then be defunctionalized [1] back into a data structure. It can be argued that TRMC as implemented in the linked post is simply a special case of this more general transformation.

[1] https://www.pathsensitive.com/2019/07/the-best-refactoring-y...

wgd··on Ask HN: Who wants to be hired? (June 2021)

  Location: San Jose, CA (current) / St. Louis, MO (desired)
  Remote: Yes
  Willing to relocate: No
  Technologies: Python, Go, Embedded C/C++, Linux, Bluetooth, WiFi, Vanilla JavaScript / ES6, OpenGL, TensorFlow, Clojure, Haskell, Lisp
  Résumé/CV: http://www.willdonnelly.net/Resume-May2021.pdf
  Email: wgd@willdonnelly.net
Hi, I'm Will, a generalist SWE with a degree in Electrical Engineering, 5+ years of professional experience with embedded systems and wireless connectivity, and a wide range of other skills. I'm willing to tackle just about anything: hardware development, backend servers and web frontends, functional programming, machine learning, and computer graphics are all fields that I enjoy working with so long as the problem is interesting.

I've been happy at Google for the past 7 years, but after the year that was 2020 I've realized that I want to move back home (St. Louis, MO) to live near family, so my primary motivation for changing jobs is to make that a possibility. Most likely this will be via remote work, although a company with offices in the STL area would also be great.

wgd··on A top audio engineer explains NPR’s signature sound (2015)
Similarly, his performances on The Masked Singer were outstanding: https://www.youtube.com/watch?v=iIZ23g9lsBk&t=359s
wgd··on MediaCrush – A website for serving media super fast
At 1/3 of a second to compute a single hash, brute forcing the entire space of possible addresses takes around 45 CPU-years. But computing the hash of every single IP address is ridiculously parallel, so it's trivial to spin up 2k machines on EC2 and brute force the entire thing in a week. Total cost, somewhere under $8k if you don't want to bother owning real machines, less for any organization that happens to need to do similar things on a regular or semi-regular basis.

It's not a trivial investment since that effort only gets you a single IP address, but it's easily within the reach of a vast number of organizations if they have real motivation (read: not a fishing expedition) to reverse it.

wgd··on UTF-8 – "The most elegant hack"
While you may be correct, it's interesting to note the existence of Consistent Overhead Byte Stuffing (http://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffi...) which sort of kind of if you squint manages to add a 257th symbol to the data stream at a constant (worst-case) overhead per byte.

The original paper also discusses how to use the "Eliminate all zero bytes" behavior in order to set up an unambiguous sync pattern to indicate the beginning of transmissions in a bit-level wire protocol.

wgd··on Urbit: A clean-slate functional OS
The difference is one of universality.

Let's say that my VM of choice has a tracing JIT, and it will attempt to optimize traces up to 1,000 instructions long. Let's further say that in the current version of my code, the body of my hot loop is 980 instructions long. Then in a new version I add another few operations which push it up to 1,010 instructions. Suddenly the JIT stops trying to optimize that portion of my code and performance tanks.

Meanwhile some other guy wrote his code using a VM which used this sort of "Jets" approach. It's probably not as fast or as versatile overall, but when he adds another few dozen instructions to a hot loop he can do so secure in the knowledge that all the preexisting code will continue to execute just like it did before.

wgd··on Urbit: A clean-slate functional OS
The more I think about it the more I really like the whole "Jets" concept (although I'm not sold on the name, I'd love to learn that it's a known concept in the PL field with a nicer name). I'd like to see how such an approach would work out for optimizing something more "fundamental" like the Binary Lambda Calculus.
wgd··on Urbit: A clean-slate functional OS
I think it's a fascinating tradeoff. A typical approach with JIT-compilation is to write relatively inefficient code and hope that the JIT compiler picks up on it and optimizes it for you. Their approach seems to instead be to say "if you generate particular sequences of instructions, we'll detect those and instead execute a more efficient version, every time".

IMO this is a really cool idea because the performance optimizations are quite a bit less brittle than the ones you get with a JIT-compiled virtual machine.

wgd··on Dissent: accountable anonymous group communication
I've been thinking more about the whole "better multiplexing" issue for a bit now, and I suspect that some sort of http://en.wikipedia.org/wiki/Carrier_sense_multiple_access_w... type of solution is ideal for this use case. Because if you think about it, two transmitters at once is not an unrecoverable failure mode, in fact it's easier to handle here than in, say, the original ethernet standard, because with packet-based internet stuff we can do things like changing the data rate on the fly in response to collisions.

Currently the system I'm imagining works as follows: Every T seconds a new packet is initiated, and fancy spanning tree relaying or whatever is used, and eventually everyone has the XOR of all server and client versions of the packet, which happens to be the XOR of whatever various clients happened to include into their packet. Now the additional information for a client who chooses to add that will be the payload plus a checksum value (which must not be homomorphic under the XOR operation). If one client transmits, the checksum passes, and everyone is happy. If multiple clients transmit, they collide, and the checksum does not pass, and each transmitter knows this and waits a random backoff time (number of packets) before trying again. But in addition, a collision is often a signal that the packet rate is too low, so collisions also cause the packet period T to decrease (and lack of messages will cause it to increase, naturally).

So I think the basic "matrix of shared secrets" construct can be extended to allow low-overhead (for values where "low" means "on the order of 3x") communications, because dynamically varying the period between packets and allowing anyone to try transmitting during any packet time will tend to mean that when no one is transmitting bandwidth drops to a very low level (I could easily believe 16-byte idle packets every 5 seconds for something where absolutely low latency isn't a requirement).

wgd··on Dissent: accountable anonymous group communication
Apologies in advance for the wall of text, but the first half is basically just a summary of their protocol for people who don't want to try to identify where the actual information resides (it appears to be http://dedis.cs.yale.edu/2010/anon/pres/120104-dissent.pdf).

As I understand it, the basic idea is that there is a network made up of N clients and M servers, with the clients (and potentially servers) identifiable in some external fashion (IP addresses or GPG keys or whatever, it's unimportant to the protocol) and we want to make it possible for any of the clients to broadcast a message without anyone being able to tell which client it came from.

So what happens is each client and each server generate a Diffie-Hellman key which is associated with their actual external identity. Then each client establishes a unique secret with each server (and vice versa, naturally). These unique secrets are used to produce N times M unique bitstreams using PRNGs (so each client has a bitstream corresponding to every server that exists, and each server has a bitstream corresponding to each client that exists).

Then each client XORs together the bitstreams from the unique secret it shares with each server, and each server does the same thing for each client's shared secret. Now there are N + M bitstreams, with the nice property that if you XOR together all of them they all cancel out (because every client-server pairing occurs in the bitstream from that client and the bitstream from that server).

Furthermore, if one client also XORs some data into the bitstream that they publish, no one else can tell, it still contains a bunch of indistinguishable-from-noise data to everyone else who might look. But then when we XOR together all N + M bitstreams, we end up with everything cancelling out except for that extra data that one client added.

So then the Dissent protocol pulls in another construct, and uses something called MIX to shuffle a set of public keys generated by the peers, and uses these public keys to establish a transmission order, essentially reimplementing TDMA (Time-Domain Multiple Access) in a digital domain with signatures.

In my opinion as a hobbyist interested in this stuff, the whole "everyone produces a bitstream and they magically evaporate leaving behind only the data everyone transmitted" thing is almost magically cool. The time-domain multiplexing is less cool, and my EE background compels me to wonder if a meaningful analogue to CDMA or OFDM could be developed. Well, obviously they could be developed the real question is "could they be useful?".

It's also sort of interesting how the fact that we can't ever be allowed to know when a given peer is transmitting means that the design becomes more "continuous", with data being transmitted by everyone at all times so that the real transmissions can be disguised. I wonder if the theoretical perfectness could be loosened somewhat to allow only, say, 10% of peers to have to be transmitting at any given time (in the long run this could make it possible to identify a transmitter uniquely, but not so quickly that it wouldn't be useful still).

Unfortunately, the second bullet-point (accountability) goes close to unfulfilled. And I feel like it sort of has to, since any method which could determine where malicious data comes from can also be used to undermine the anonymity of the system for everyone else. There's a kind of accountability, which is that the peers themselves can be associated with a public identity without anyone being able to tell which peer produced a given message, even in theory, but it doesn't extend to any system with open registration, because it doesn't handle the "sock puppet" problem at all.

But personally I think the sock puppet problem is pretty much un-silver-bullet-able. The best we can probably ever hope to do for "general purpose" uses is probably a combination of a cryptographic proof-of-work algorithm, public-key signatures to allow (though not force) persistent identity, and some sort of reputation system.

wgd··on Persona - Mozilla's decentralized and secure authentication system
I really like the overall result of Persona when used for logging into a web site, but has anyone come up with a good way of integrating Persona login with mobile apps or APIs?

I suppose mobile apps would ideally use some sort of Persona login service provided by the underlying OS, and until such a thing exists I guess an app could reimplement all the user-agent logic and load the user's login page in a webview. But I have no idea how at all I would go about designing an API for a website which uses Persona for logins.

wgd··on Atomic bond types discernible in images
They say the pictures were taken with a variant of Atomic Force Microscopy, so what you're seeing is most likely a false-colored representation (that is, they just chose some gradient of colors to use instead of grayscale) of the strength of the electrostatic forces acting on the probe tip at each location. So the whole thing is essentially just an image of the electron clouds.
wgd··on Redesigning the hotel icon
> having an airline seat represent a plane would be quite confusing, and having a bed represent a hotel is no clearer

The distinction here is that you don't get in an airplane to sit in the seats, you get in an airplane so it can fly somewhere with you in it, and the shape of an airplane is very good at conveying that. With a hotel, I don't go there so I can admire the building, I go there so I have somewhere to sleep.

wgd··on SpaceX Falcon 9/Dragon Launch Webcast (starts at 12:00am PDT)
Is the music they're playing during the countdown something identifiable? It's the kind of thing that's perfect for playing over and over for hours without getting repetitive.
← PreviousPage 3 of 4Next →