HNHacker News
TopNewBestAskShowJobs

neild

1,247 karma · joined December 18, 2009

submissionscomments
neild··on When Jawaharlal Nehru Read ‘Lolita’
There are many answers to why Lolita was well received by many people. (It's worth noting that it was certainly not universally well received--many, many people share your opinion of it.)

One is that many of the people who like it seem not to have read it; or if they have read it, they did not understand it. Many men have described it as "a love story" or otherwise indicated that they feel the book approves of pedophilia. Two movies have been made based on the book, and both portray Dolores Haze (the girl the narrator calls "Lolita") as a seductress rather than as a victim. A substantial portion of the fan base of the book are, rather distressingly, men who appear to be quite enamored of the notion of having sex with children.

Another is that Nabokov was a clever writer who excelled at writing books which reward close reading. Lolita is the story of Dolores Haze, but the narrator is a man who has no interest in her other than as than the victim of his sexual attentions. He drones on at great length about trivialities, while completely skipping over vital information. He is deliberately constructing an exculpatory narrative, which opens fascinating questions about how we can find any truth when everything we read is lies. Sifting through his self-serving prose to find glimpses of the actual Dolores Haze is challenging, and--to me at least--interesting.

It's not an easy book, in many senses. The narrator is a monster. The bulk of the story is obscured behind lies and misdirection. There is no catharsis, no happy ending.

Contrary to the opinion of many people who have not read the book, and some who have, Nabokov was extremely well aware that "Humbert Humbert", the narrator, is a monster. Humbert is a pedophile who abducts a 12-year-old girl and rapes her repeatedly over the course of years. Dolores Haze is a victim, not a seductress, and is in no way responsible for or desirous of her abuse. Humbert is not a reliable narrator, and nothing he says can be trusted.

Nabokov himself was a victim of childhood sexual abuse. He knew what he was writing about. There's one scene that is almost certainly directly based on his own personal experience.

I'd have difficulty saying that I enjoyed Lolita, but it's a rewarding book, and I'm glad to have read it.

neild··on Chemistry of Cast Iron Seasoning: A Science-Based How-To (2010)
I have several cast iron pans of varying vintages and styles. They see a lot of use. And my experience is that the quality of the seasoning just doesn't matter that much. If the pan is hot and there's oil in it, almost nothing sticks even if the seasoning is indifferent. The stuff that does stick (tortillas are terrible for leaving carbonized residue on the pan) will do so no matter how good the seasoning is. It doesn't matter, though, because I just scrub it off and the pan still works fine.

Oh, and a bit of dish soap is fine, too. Doesn't seem to bother the pan any.

There's a whole vaguely macho culture around cast iron and the fiddly rituals for producing the perfect surface, but you can just ignore all that and cook on the things and they're fine.

neild··on Please don’t let anyone Americanise it (1992)
Bluey is the only show that made my kid want to turn the TV off so he could play whatever game Bluey and her sister were playing himself. We still play Silly Hotel from time to time.

It’s very different tonally (much more serene), but fans of Bluey should check out the BBC kids’ show Sarah & Duck, which is aimed at a similar age range and also contains much for parents to love as well as children. It’s gentle and surreal, and I’d have been happy to watch it on its own merits even if I didn’t have a kid who loved it as well.

neild··on Clone culture and its continuous impact on indie developers
World of Warcraft at launch had relatively low polygon count models and worked flawlessly on low-spec graphics hardware, but the animation was spectacular and miles beyond what any of its competition was doing. The feet of a moving model actually touched the ground as if it were a solid object; literally every other MMO I played from that era had models where the run or walk animation was completely decoupled from movement speed, with feet sliding around disconnected from the ground.

In addition, WoW had coherent and consistent art direction with characters, enemies, and environments all feeling like part of a thematic whole.

Blizzard had clearly spent ridiculous amounts of time and money on the visuals of the game, the animation in particular. They just did it while targeting low-spec hardware to avoid limiting their audience.

There’s a very big difference between cheap for the game developer to make, and supporting cheap hardware.

neild··on A “Sideways” supply response in California winegrapes
It’s complicated. A lot of the research is misreported. The supposed study demonstrating that experts can’t tell the difference between red and white wine says no such thing. But people do love a narrative that takes the wind out of a snob’s sails, so the legend persists.

True experts can distinguish an astonishing number of characteristics of wine in a blind taste. Most people are not experts. The price of wine is also largely decoupled from how much any given person will enjoy it. (However, psychologically, you will probably enjoy a bottle you paid $100 for more than one you paid $20 for.)

Basically: Wine is not all just indistinguishable fermented grape juice, but most stuff written about wine is a combination of bunk and rarified trivia no normal drinker should care about. Drink what makes you happy.

neild··on Three Minor Features in Go 1.18
It would, which is why the Go compiler and linker do not put the build time in binaries.
neild··on Three Minor Features in Go 1.18
Go builds are, in general, reproducible by default. Build stamps do not change this.
neild··on Jndi: An irresponsibly bad logging library
The version is specified in the go.mod file. The checksum of the module at that version is saved in the go.sum file. And on initial download the module checksum is validated against a auditable checksum database to verify that it matches the expected value for that module and version.

See: https://go.dev/ref/mod#authenticating

neild··on A new ProtoBuf generator for Go
Yes, to avoid an import cycle or polluting the protoreflect API documentation with a rather large non-user-facing API surface.
neild··on LG is getting out of the mobile phone business
I’ve never decided to take advantage of waterproofing, which made me all the more appreciative on the times I’ve unexpectedly done so.
neild··on Nil in Go is typed in theory and sort of untyped in practice
The predeclared identifier nil is a constant, like 0 or "".

Like 0 or "", nil is untyped. Go has both typed and untyped constants. 0 also is untyped, which is why you can write x==0 regardless of whether x is an int32 or an int64.

Unlike 0 or "", nil does not have a default type. The default type of a constant is the type that it is implicitly converted to when a type is required. For example, "x := 0" declares a new value x with the value 0, but 0 is untyped. Untyped integer constants have a default type of int, so x is given the type int.

Since nil does not have a default type, it's an error to write "x := nil".

You can declare a typed constant with the value 0 or nil. int32(0) is a constant with type int32 and the value 0. (* int32)(nil) is a constant with the type pointer-to-int32 and the value nil.

Variables of an interface type can hold any value that satisfies the interface. For example, a value of type io.Reader can hold any value that has a Read method with the appropriate signature.

The common confusion about nil occurs because you can compare an interface value to a non-interface value.

  var b *bytes.Buffer       // b is a variable with type *bytes.Buffer
  var r io.Reader           // r is a variable with type io.Reader
  r = b                     // r now holds a value with type *bytes.Buffer and value nil
  b == nil                  // true: b is nil
  r == b                    // true: r and b are equal
  r == (io.Reader)(nil)     // false: r is not a nil io.Reader
  r == (*bytes.Buffer)(nil) // true: r contains a nil *bytes.Buffer
  r == nil                  // false: r is not a nil io.Reader
 
The confusing part is that last line. How can r not be nil, when it contains a nil value? And the reason is hopefully apparent from the previous two lines: It depends on the type of "nil".

Whether you find this a wart in the language or not, this is not a case of nil being either typed in theory or untyped in practice. The predeclared identifier "nil" is an untyped constant.

neild··on Ordering burritos from my SPARC (1992)
I’d do much for one more burrito from the old school La Costeña. They were so good.

La Bamba had the best meat; just a plain pollo burrito was a thing of glory, and their carnitas was transcendent. But La Costeña was where it was at if you wanted a burrito with stuff in.

neild··on Gary Taubes: 'Obesity isn’t a calorie problem, it’s a hormone problem'
Calories are a unit of energy, not weight. Conflating the two is sloppy thinking.

Eat nothing but grass and you will die of starvation. Yet ruminants live on grass, and its energy content can be measured with a calorimeter. Thermodynamics are a poor mechanism for understanding biology.

neild··on Chemistry of Cast-Iron Seasoning (2010)
The main thing I’ve learned that most advice about seasoning pans doesn’t tell you is that how you use the pan to cook matters more than how well seasoned it is. Cast iron is really forgiving of seasoning, you don’t need the perfect job to cook with it.

However, cast iron will never be as non-stick as a good non-stick pan, and if you treat it as one, you’re going to have a bad time.

Put bacon in a dry, hot pan, and it’ll leave crispy fond stuck to the pan. (Nothing you do will ever create fond in a non-stick pan.) Cook bacon starting with a cold pan, and enough fat will render by the time it heats to keep it from sticking.

Eggs will stick to cold, dry cast iron. Fry eggs in a moderately hot pan with plenty of grease. I had the devil of a time with fried eggs until I realized I wasn’t letting the pan heat enough. Also, it’s very easy to burn butter in a cast iron pan; use a more forgiving fat like bacon grease or a neutral oil.

Cast iron behaves differently than non-stick or stainless steel. Different heat density, different emissivity. Just like any other cookware, you need to learn how to work with it; it’s not just a matter of getting the magical perfect seasoning and pretending it’s Teflon.

neild··on Go’s Major Versioning Sucks – From a Fanboy
I'm one of the people responsible for the choice of versioning for the Go protobuf module. (Sorry!)

The original Go protobuf implementation is in the module "github.com/golang/protobuf".

A couple years back, we decided that it was time to do a major overhaul of the protobuf implementation. Protobufs were one of the first major pieces of Go code outside the standard library (the second post ever on the Go blog is about it), and there were a number of design decisions that made sense at the time but which we wanted to go back and revisit. Doing all of this was not going to be possible while preserving API compatibility.

Given that, we needed a new module path. That's the core of Go modules and API changes: You change the module path when you make an incompatible change. You can do this by bumping the major version of the module (since the module path includes the version), or by changing the module path entirely. (There's another option, which I think doesn't get enough attention: You can just make the change, and force your users to deal with it. If you're okay with breaking your users when they upgrade, nothing stops you from doing this. We take backwards compatibility very seriously, so that wasn't an option for us.)

Given that we needed a new module path anyway, we took advantage of the opportunity to move to a path that isn't specific to a particular code hosting provider: "google.golang.org/protobuf". GitHub is great, we love GitHib, but we'd much rather have a provider-agnostic name for the module.

So we have a new module path. The question then was: What version do we tag the new module as when we release it? Remember that there has never been any version of "google.golang.org/protobuf" at this point; it's a completely new module.

One option was to tag it as v1.0.0. But that might be confusing, because this is "version 2" of the protobuf implementation, even if it's under a different module path. Also, if someone complains about a problem with "v1.2.0" and doesn't mention which module they're using, we won't have any way to tell which one they're talking about.

Another option was to tag it as v2.0.0. But that might be confusing, because there's never been a v1 of this package. Also, this would likely cause unnecessary confusion with "proto2" and "proto3" (versions of the protocol buffer language).

We waffled for quite a while, and eventually settled on v1.20.0, which avoids the missing v1 weirdness but also ensures that there is no overlap in versions between the two modules.

That confused people. Alas. Perhaps every option would have led to confusion.

In retrospect, perhaps we should have gone with v2.0.0 (and a module name of "google.golang.org/protobuf/v2"). Too late now; oh, well. If this was the worst decision we made in the new implementation (and so far, it looks like it may have been), I'll be quite happy.

neild··on Simdjson: Parsing gigabytes of JSON per second
Protobuf varints are particularly annoying because they require searching for a terminating byte. A naive implementation needs to make 20 comparisons to decode an 8-byte int (checking the value of each byte, and for overflow in the input data).

UTF-8-style varints, where the encoded length can be determined entirely from the first byte, are much nicer.

neild··on A new Go API for Protocol Buffers
We used up our breaking change budget for the next decade with this release, so we'll think about it in 2030.
neild··on A new Go API for Protocol Buffers
Indeed, tying the name of a package to a hosting provider is a bad idea! That's why we changed to an import path which isn't tied to one. google.golang.org/protobuf is not tied to any particular provider, and we can redirect it wherever we want.

See "go help importpath" for details on how this works.

neild··on A new Go API for Protocol Buffers
Reasoning went something like this:

We could tag the new API v2:

+ Makes the "v1" and "v2" distinction very clear in the import path.

- Confusing: google.golang.org/protobuf@v1 doesn't exist, but v2 does.

- In ten years, hopefully nobody cares about the old github.com/golang/protobuf and the confusion is gone.

We could tag the new API v1:

- Less visually distinct in the import path.

+ Seems to make sense for the first version of google.golang.org/protobuf to be a v1.

+ If we decide it was a terrible idea, it's easier to go from v1 to v2 than to roll back from v2 to v1.

We waffled back and forth for quite a while on this, and eventually decided that the first version of google.golang.org/protobuf would be a v1. Then as we got closer to release (but with a certain amount of usage of v0 in the wild), we decided not to second-guess that decision but to start with a version that wouldn't overlap with any version of github.com/golang/protobuf to avoid confusion when someone reports a bug in "v1.0.1".

Maybe it was the wrong choice. If it was the worst choice we've made in the new API, I'll be happy!

neild··on A new Go API for Protocol Buffers
Nah, we just really wanted to stop using an import path tied to a specific hosting provider. Once we decided to change to an entirely different path, we waffled a lot over whether to tag it v1 or v2. There were arguments for and against either, so we eventually picked one and went with it.
neild··on Apple in 2017: Report Card
Apple Watch series 3, no cellular: Usually ~75% charge remaining after wearing it for 16 hours. Maybe the cellular ones are a lot more power hungry, but I could charge this one only every other day with no problems.
neild··on What Needs to Happen Before Electric Cars Take Over the World
This is not true. (It is for some plans and some locations, but not all.)

I have a plan which charges significantly less during off peak hours.

neild··on Neugram – Scripting in Go
If the spec and an implementation disagree, there is a bug in one or the other. (There are multiple implementations of the language.) The Go spec is not entirely normative in that a disagreement between it and the implementation may be resolved in favor of the later. It is normative in that you should be able to implement the entire language from the spec alone.
neild··on Goroutines, Nonblocking I/O, and Memory Usage
It's a standard library limitation.

One could imagine a function that takes a set of net.Conns and returns the ones that are available for reading. You'd then pass those off to a goroutine for processing with blocking I/O as usual.

neild··on Employee sues Google for 'illegal' confidentiality policies
My understanding is that employers may not hinder employees in discussing salaries among themselves, but may impose restrictions on providing salary information to non-employees.

So I can tell another Googler my salary but I can't tell you (unless you're a Googler) because my NDA forbids it. I'm pretty certain that I'm allowed to tell you that I'm not allowed to tell you, though. :)

There's an internal site where a number of Googlers share their compensation, anonymously or otherwise. I've never received any indication of disapproval or retaliation from management for being on it.

(I am not a lawyer, standard disclaimer applies.)

neild··on New research: cashiers who have their own lines move customers more quickly
This article fails to recognize the difference between throughput and latency. A single queue optimizes for latency, since slow customers don't stall the ones behind them. If cashiers work faster in a multiple queue setup, then this configuration will optimize for throughput while still losing at latency.

As a customer, all you care about is latency: How long you spend waiting in line. As a store owner, you also care about throughput: How many cashiers you need to process some number of customers per unit time. A store owner that cares about customer satisfaction will still care about latency, of course.

neild··on How Python 3 Should Have Worked (2012)
It's exceedingly rare that you need a sequence of codepoints. As evidence, consider that the native string types in many languages with pervasive Unicode support, such as Java and C#, do not provide a codepoint sequence.

Programs generally need to deal with textual data at one of three levels:

1. Manipulate strings and substrings. e.g., "does string x contain substring y"? Byte sequences of utf8 data are fine for this. You may need to normalize the data first, but that's true of codepoint sequences as well.

2. Deal with a small number of specific ASCII codepoints--e.g., the filename separator character. Again, utf8 byte strings are fine for this.

3. Deal with glyphs, including glyphs composed of multiple combining characters. You need to iterate to assemble the glyphs, so a codepoint sequence offers no advantages over a byte sequence of utf8 with a codepoint iterator.

A sequence of bytes is just fine as a native string type. Store Unicode data as utf8-encoded byte strings. Provide easy iteration over codepoints in utf8 strings, transcoding for I/O, normalization functions, etc. Call it a day.

neild··on Strings, bytes, runes and characters in Go
Indexing on runes is expensive, since either you need to store strings as arrays of runes or iterate on each index operation. Indexing on runes is also less useful than it may first seem. Consider that a rune is distinct from a glyph--a single "character" on the screen may be composed of several runes. The occasions when you care about specific runes as opposed to substrings are uncommon. When dealing with substrings, there is no advantage to substring-of-runes as opposed to substring-of-bytes.

Note that many languages that appear to offer indexing by rune (e.g., Java) do not in fact do so, since their 16-bit "character" type is incapable of representing all runes. The fact that this is only rarely an issue points at the fundamental rarity with with code needs to deal with runes-qua-runes.

neild··on Why Python uses 0-based indexing. It's because of slices
This is not correct. Perl has arrays and, as the person you are replying to said, allows the index of the first array element to be changed globally by setting a special variable. $[, if I recall correctly.
neild··on What Python developers need to know before migrating to Go
It is very seldom that you really want to deal with a string as an array of runes. (If actually you do want to, Go makes it fairly easy: Just use []rune rather than string.)

Consider a simple string: "école". How many runes does it contain? Possibly five:

    LATIN SMALL LETTER E WITH ACUTE
    LATIN SMALL LETTER C
    LATIN SMALL LETTER O
    LATIN SMALL LETTER L
    LATIN SMALL LEtTER E
Possibly six:

    LATIN SMALL LETTER E
    COMBINING ACUTE ACCENT
    LATIN SMALL LETTER C
    LATIN SMALL LETTER O
    LATIN SMALL LETTER L
    LATIN SMALL LEtTER E
If you normalize the string you can guarantee you have the first form, but not every glyph can be represented as a single rune.

Fortunately, you generally don't need to deal with any of this. If you're working with filenames, for example, you really only care about the path separator ('/' or '\' or whatever); everything else is just a bunch of opaque data. You can write a perfectly valid function to split a filename into components without understanding anything about combining characters. When you're dealing with data in this fashion, you rarely if ever care about the number of runes in a string; instead you care about the position of specific runes.

← PreviousPage 2 of 6Next →