HN user

nayuki

6,541 karma

I am a software developer.

Home page: https://www.nayuki.io/

Posts102
Comments1,963
View on HN
vale.rocks 1y ago

JPEG XL and Google's War Against It (2024)

nayuki
26pts9
www.youtube.com 1y ago

Veritasium: I used to hate QR codes. But they're genius [video]

nayuki
3pts6
www.theglobeandmail.com 2y ago

The government dug a deep hole for itself with Bills C-11 and C-18

nayuki
30pts15
www.nayuki.io 3y ago

Show HN: SQLite Database File Visualizations

nayuki
1pts0
www.w3.org 3y ago

List of CSS properties, both proposed and standard

nayuki
1pts0
www.nayuki.io 3y ago

C/C++ arithmetic conversion rules simulator

nayuki
4pts1
thoughts.jatan.space 4y ago

Yes and No: A binary philosophy to being productive

nayuki
1pts0
www.wired.com 4y ago

NFTs Don’t Work the Way You Might Think They Do

nayuki
3pts1
www.sudokuwiki.org 4y ago

Sudoku Solver by Andrew Stuart

nayuki
2pts0
bford.info 4y ago

Cache Directory Tagging Specification (2004)

nayuki
1pts0
testtubegames.com 4y ago

Bond Breaker 2.0

nayuki
4pts1
www.biteinteractive.com 4y ago

Understanding Git Merge

nayuki
1pts1
www.nayuki.io 4y ago

PNG File Chunk Inspector

nayuki
48pts18
www.nayuki.io 5y ago

Practical Guide to Xhtml

nayuki
1pts0
www.hrw.org 5y ago

Dismantling a Free Society: Hong Kong One Year After the National Security Law

nayuki
6pts0
learn-the-web.algonquindesign.ca 5y ago

HTML Semantics Cheat Sheet

nayuki
6pts0
medium.com 5y ago

It’s the Settlement Assurances

nayuki
2pts0
www.cs.princeton.edu 5y ago

On the Instability of Bitcoin Without the Block Reward [pdf]

nayuki
154pts221
spectrum.ieee.org 5y ago

Protean Electric’s In-Wheel Motors Could Make EVs More Efficient [2018]

nayuki
1pts0
www.quora.com 5y ago

What are some things non-programmers say that frustrate programmers?

nayuki
1pts0
waitbutwhy.com 5y ago

The Thinking Ladder

nayuki
4pts0
orib.dev 5y ago

Low Barriers to Implementation

nayuki
2pts0
www.streamingmedia.com 6y ago

MPEG: What Happened?

nayuki
7pts0
www.youtube.com 6y ago

DVD+R and DVD-R; What was that about?

nayuki
2pts0
beza1e1.tuxen.de 6y ago

No Real Numbers (2019)

nayuki
1pts0
www.youtube.com 6y ago

The Metric System Is Bull Duggery [video]

nayuki
2pts0
philosophistry.com 6y ago

What is a “Black Triangle” moment? (2009)

nayuki
2pts0
electriccoin.co 6y ago

Lessons from the History of Attacks on Secure Hash Functions

nayuki
2pts0
fossil-scm.org 6y ago

Fossil: Hash Policy

nayuki
1pts0
netflixtechblog.com 6y ago

Protecting a Story’s Future with History and Science

nayuki
1pts0

This is an excellent visualization! I would love to see someone adapt this data into a first-person navigation game. The game should put you at some location in the station complex and ask you to navigate to some location. This would be excellent training for people visiting the real-life Shinjuku station for the first time.

I guess one could rack through many QR Code parameters while encoding the same payload text: Version (40 sizes with capacity constraints), 4 error correction levels (with capacity constraints), 8 mask patterns, splitting text into various blocks (with capacity constraints), using different character encoding modes (if applicable to the text), putting garbage data after the terminator (violates the spec, but can be a huge boost for generating some custom patterns).

Synthesis is harder than analysis

Taking this statement at face value, it means something in computer science: computing an answer (synthesis) is currently believed to be harder than checking an answer (analysis).

The simplest example to illustrate the claim is that factoring a number is harder than multiplying the two factors to check that it equals the original number, or even to decide whether the original is prime or composite (but without yielding the factors).

This also cuts to the heart of what NP means - it means that the answer to a yes/no problem about binary strings can be checked in polynomial time. It doesn't give a recipe for how to generate the answer, but it is implied that finding an answer can take up to exponential time and no more.

Reminding Us Nothing Digital Is Ever Truly Ours

Wrong, Kotaku. Lots of digital things are ours. Digital files on our personally owned HDDs and SSDs. Digital movies on DVD and Blu-Ray discs on our shelves. Digital ISO files on hard drives that are ripped from the aforementioned digital physical DVDs.

What you meant to say is, streaming content is not ours - and that is true by definition, because the data is streamed from somewhere else. Someone else can always delete files, take down servers, or go out of business entirely.

The word digital contrasts with analog. Digital and physical are two independent axes - there are digital physical things, digital virtual things, analog physical things, and analog virtual things.

The game got too tedious to play by hand, so I wrote a script to play it automatically. It handles CPU, I/O, and processes quite well - but doesn't recognize a crown on a process and doesn't handle memory management at all.

I found that even on the easy level, the number of processes keeps growing slowly, and there isn't enough CPU time to keep all processes satisfied. I feel like the game is inherently setting you up for failure. Here is the script if anyone wants to play with it:

  // ==UserScript==
  // @name     Auto-play "You're the OS!" game
  // @include  https://plbrault.github.io/youre-the-os/
  // ==/UserScript==

  (async function() {
      const IO_EVENTS = {x: 160, y: 25};
      const CPUS = 4;
      const CPU1 = {x: 50+46, y: 50+42};
      const SQUARE = {w: 64+5, h: 64+5};
      const PROCESS = {x: 50+46, y: 155+42};
      const PROCESS_ROWS = 6;
      const PROCESS_COLS = 7;
      
      let cnv = document.querySelector("body > canvas");
      while (cnv.width != 1280 || cnv.height != 720)
          await new Promise(res => setTimeout(res, 100));
      
      while (true) {
          const pixels = new Uint32Array(cnv.getContext("2d").getImageData(0, 0, cnv.width, cnv.height).data.buffer);
          function getPixel(x, y) { return pixels[y * cnv.width + x]; }
          
          if (getPixel(IO_EVENTS.x, IO_EVENTS.y) == 0xFF808000);
              await pressKey("Space");
          let cpuStatuses = [];
          for (let i = 0; i < CPUS; i++) {
              const p = getPixel(CPU1.x + SQUARE.w * i, CPU1.y);
              cpuStatuses.push(
                  p == 0xFF000000 ? 1 :
                  p == 0xFF9A9B9B ? 2 :
                  p == 0xFF00FF00 ? 3 :
                  p == 0xFFE6D8B0 ? 4 :
                  0);
          }
          let processStatuses = [];
          for (let r = 0; r < PROCESS_ROWS; r++) {
              for (let c = 0; c < PROCESS_COLS; c++) {
                  const p = getPixel(PROCESS.x + SQUARE.w * c, PROCESS.y + SQUARE.h * r);
                  let s =
                      p == 0xFF000000 ? 1 :
                      p == 0xFF9A9B9B ? 2 :
                      p == 0xFF00FF00 ? 3 :
                      p == 0xFF00FFFF ? 4 :
                      p == 0xFF00A5FF ? 5 :
                      p == 0xFF0000FF ? 6 :
                      p == 0xFF00008B ? 7 :
                      p == 0xFF000050 ? 8 :
                      0;
                  if (s >= 3)
                      processStatuses.push({r, c, status: s});
              }
          }
          
          processStatuses.sort((a, b) => a.status - b.status);
          for (let i = 0; i < cpuStatuses.length; i++) {
              if (cpuStatuses[i] < 1)
                  continue;
              if (cpuStatuses[i] >= 2)
                  await pressKey("Digit" + "1234567890".charAt(i));
              const p = processStatuses.pop();
              if (p !== undefined)
                  await clickMouse(PROCESS.x + SQUARE.w * p.c, PROCESS.y + SQUARE.h * p.r);
          }
          
          await new Promise(res => setTimeout(res, 300));
      }
      
      async function clickMouse(x, y) {
          const rect = cnv.getBoundingClientRect();
          const opts = {
              bubbles: true,
              clientX: rect.left + x * rect.width / 1280,
              clientY: rect.top + y * rect.height / 720,
          };
          cnv.dispatchEvent(new MouseEvent("mousemove", {...opts, buttons: 0}));
          cnv.dispatchEvent(new MouseEvent("mousedown", {...opts, buttons: 1}));
          cnv.dispatchEvent(new MouseEvent("mouseup", {...opts, buttons: 0}));
          await new Promise(res => requestAnimationFrame(res));
      }
      
      async function pressKey(code) {
          cnv.dispatchEvent(new KeyboardEvent("keydown", {code, bubbles: true}));
          cnv.dispatchEvent(new KeyboardEvent("keyup", {code, bubbles: true}));
          await new Promise(res => requestAnimationFrame(res));
      }
  })();

Not only that, but Python had the benefit of doing a very painful break in version 3 (2008), when they had the option to cleaned up almost anything they wanted.

(Some changes in Python 3 I can recall: bytes/str/unicode being the biggest one; fixing mutable variables in nested functions; changing some obscure behavior in class hierarchies and overload resolution; changing things like range() and map() to lazy evaluation.)

For better or for worse, Java has maintained very good (not perfect) compatibility throughout, even with painful changes like generics in 1.5, lambdas in 8, modules in 9, eventual removal of applets and SecurityManager, etc. This also contrasts with C#/.NET, which I think had some breaking changes over the decades.

A condo is a type of home, so it's like you're saying "Do you drive a car or a vehicle?".

Also, condominium does not automatically imply apartment, because there are condo townhouses and condo detached houses.

A condominium is a legal structure that prescribes which parts are owned jointly and which parts are owned individually. https://en.wikipedia.org/wiki/Condominium

You somehow missed the second part of that sentence: "No, the statement is completely true: 100% of your rent money goes to someone else, and you also don't get any asset to sell later on."

The oft-repeated statement that "renting is throwing your money" is an implicit contrast to owning a home, where the mortgage payment "builds equity" in your asset that can be sold later.

"Throwing money away" means you don't get to own something that can be sold for money later on. That's why we "throw money away" on gasoline, but not "throw money away" in a savings account.

The second part of my argument is that throwing money away isn't necessarily a bad thing, because the alternative (such as paying to own something) can end up being more expensive and being a worse deal financially.

Great article, love that you enumerated all the costs in buying a home. I don't like how renters romanticize home ownership and fail to understand how many costs are involved.

You've probably heard someone say something to the effect of "renting is just throwing your money away". Don't believe it. It's a glib statement that simply isn't true.

No, the statement is completely true: 100% of your rent money goes to someone else, and you also don't get any asset to sell later on.

However, this statement doesn't exist in a vacuum. You need some place to live, and you have to compare the cost of renting to the cost of owning.

To give an example, the typical rent in Toronto is $1000~2000/month, and the typical home ownership cost (including principal, interest, taxes, and maintenance) is $2000~3000/mo. We can just pretend that both are around $2000/mo.

If owning is still $2000/mo but suddenly rent is $500/mo, then renting suddenly becomes a great deal - even though you are still literally "throwing money away". You can use that differential $1500/mo to invest in a savings account, stocks, etc.

And speaking of that, I realized that the biggest cost in owning a home isn't the mortgage (and you correctly pointed out that paying down the principal doesn't change your net worth). The biggest cost is the opportunity cost of the down payment, when you could have instead invested in the stock market at 7~10%/year.

Continuing with the Toronto example, if you bought a home for $500k with 20% down, then the counterfactual if you had continued renting is that the $100k chunk of money could've generated $7000~10000/year = $580~$830/mo, which is a substantial fraction of the $2000/mo rent.

Shoutout to this article again: "You Are Naturally Short Housing" https://thezikomoletter.wordpress.com/2012/12/10/you-are-nat...

(I'd like to note that I wrote a lot of code in Java and Python, and continue to use each language in its respective strong areas. This isn't meant as a drive-by attack of "Java r00lz, Python sux"; this is an experienced take.)

My real problem with the evolution of Python is that initially, the language and the community was positioned as anti-Java, anti-big-OOP-like-C++, and then it changed into the thing that it was against, but in a roundabout and suboptimal way. To me, the initial vibe of Python was, "write a 100-line script, don't worry about explicitly documenting types, don't worry about grand architecture, don't worry about creating custom classes, don't worry about encapsulation and public/private". I've been with Python since year 2007 in the 2.x days, and Java since 2002.

Initial examples: Why go through the ceremony of `public static void main(String[] args)` when Python just executes the script line by line at the top level? Oh wait, now you have things like `import` actually executing code instead of simply being a compile-time namespace convenience, and you need weird techniques like `if __name__ == "__main__"`. Why `System.out.println()` when `print()` is so much more concise? But now you're polluting the global namespace, and `print(file=sys.stderr)` isn't that elegant either.

Static typing in Python is the biggest hypocrisy ever. As I understood it, Python scripts were meant to be lightweight and free of the tyranny of enterprise OOP which was epitomized by Java. But people found out that keeping track of types in your head is laborious and error-prone, and getting a compiler to check {that the shape of your objects and function calls match} is a huge productivity boost. And so Python 3 enabled static type hints... which, like I said before, Java had from day zero. To make matters worse, static type hint features were introduced progressively over the years, leading to things getting deprecated from the `typing` module and moved to things like `T|None` and `list[T]` and `collections.abc`.

IIRC the old practice in Python was that you specified some kind of interface in prose or in code (e.g. `class IoStream: def read(); def close()`), but you didn't need to explicitly use that interface as a superclass; you can just duck-type your way around things. But this completely goes against static typing, so I'm pretty sure the new preferred way is to explicitly use abstract superclasses... just like Java did all along (and is mandatory).

I really don't think having top-level (module) variables and functions in Python is a good thing, especially because then they are duplicated as fields and methods in classes. In Java, fields and methods (whether static or instance) can only be placed in classes, and I think this particular straitjacket is a good thing.

because Python wants these things to be optional

We can both agree that Python gives multiple ways to do things (e.g. no static type hints vs. static type hints). This flies in the face of:

Readability counts.

The Zen of Python / There should be one-- and preferably only one --obvious way to do it. -- https://peps.python.org/pep-0020/

Probably the most tragic example is the ways to build up strings in Python: `+` and str(), `%` operator, `str.format()`, f-string.

(To be fair, I have a laundry list of complaints about Java too, such as: .class files and the JVM being an intermediate layer that needs to be understood which is actually different from the Java source language, lack of in-place structs so `new Point[]` is very painful on the memory system, awkward string interpolation/formatting compared to Python's f-strings, very awkward JDBC compared to for example Python sqlite3 API, kinda clunky for web server programming, very awkward JSON handling, enterprisey libraries and APIs that are perfectly documented but are impossible to actually understand.)

lead to Dredd-like Mega Cities just taking over the entire continent

This is impossible. Look at even the densest cities today such as Hong Kong, with many 50-storey buildings packed closely. HK as a whole has maybe 25% land area allocated for buildings and the rest is forest and green space.

Or consider Tokyo - sure, it is a big sprawling metropolis and pretty much an uninterrupted patch of concrete. But the urban area does eventually end, and much of the land area of Japan is mountains, forests, farms, etc.

Java made opaque types possible from the very start by private and package-private constructors.

It's sad to see that many features regarding object-oriented programming and static typing are implemented worse in Python than Java. Various examples: __str__() vs. toString(); underscore vs. private; @staticmethod/@classmethod vs. static; generic types are so clunky in Python; types are not shown in the official Python standand library documentation; __init__() doesn't force you to call super() whereas it's mandatory in Java; @override (Python 3.12; year 2023) copying Java @Override (JDK 1.5; year 2004) very late; convention changing from duck typing (always available in Python) to structural typing (optional in Python, mandatory in Java).

I agree with your comment a lot. My ideal for road pricing is something like a https://en.wikipedia.org/wiki/Vehicle_miles_traveled_tax multiplied by weight (maybe squared, due to the https://en.wikipedia.org/wiki/Fourth_power_law of road damage).

I do think that a lot of people think that public roads are "free" and cost nothing to build and maintain. It is really hard to make people think about where the labor, materials, and funding come from.

It's not flawed logic though. If, say, a mile of highway costs $1 million and it needs some expensive repaving/reconstruction every 20 years, who should bear the cost?

The current model is roughly that all of society shoulders the cost roughly equally per person, regardless of how much they use that road or how much they drive in general. But clearly, some people derive more benefit from the road than others. The guy who doesn't drive derives 0 units of benefit. The gal who drives on it once a year derives 1 unit of benefit. The daily commuter gets 100 units of benefit. For the trucker moving $10M of goods a year on that road, their company gets 3000 units of benefit. So in a sense, the people who drive less are subsidizing the people who drive more - kind of like going to a fixed-price buffet dinner (people who eat more are subsidized by people who eat less).

Targeting more of the cost burden on heavy goods vehicles isn't an issue in my opinion. The thing is, that highway costs $1M no matter what. The only thing we can decide as a society is how to split that cost among the people. In the current way, I think the truck is underpriced and is doing more than its fair share of damage. If we change the prices so that car drivers pay less (not zero) and the truck driver pays more, that's okay. The truck's costs get passed onto consumer, such that people who buy more goods pay more road tax - exactly as intended.

Taking a step back, I think a lot of (not all) problems in society are a result of mispricing - often for political, special-interest, and/or "feel-good" reasons. When people pay less than the true cost, they over-consume. When people pay more than the true cost, they under-consume.

When it comes to any good or service, there are only two choices: the user pays, or other people pay. The status quo is that drivers pay a lot for roads through gasoline taxes and vehicle registration fees, but the rest of society (including non-drivers) pay through income taxes, sales taxes, and property taxes. Moreover, a lot of taxes paid for road construction/maintenance are not proportional to how much you drive; a driver doing double the miles in a year is paying less than twice of another driver.

Please explain your ideal scenario of who pays for roads. And if your answer is "someone else" (e.g. "taxes", "government", "corporations", "billionaires"), further explain why "someone else" can't use the same argument to make you pay.

While bored in high school math class around the year 2005, I forced myself to learn the Greek alphabet. That very much came in handy in university, as Greek letters are frequently used for variables in computer science, mathematics, and physics.

Applying the increment or decrement operators over the same variable more than once on the same line should be a compile-time error

That would be nice, but don't forget the more general case of pointers and aliasing:

    int a = 5;
    int *pa = &a;
    printf("%d", (a++ + ++*pa));
The compiler cannot statically catch every possible instance of a statement where a variable is updated more than once.

You wrote ethanol (C₂H₆O), but do you mean ethylene/ethene (C₂H₄)? Polyethylene (PE) is a very common plastic, such as HDPE, LDPE, PET.

A neat dashboard. The usage of metric units can be improved:

Corona ~1.2M K / Active Regions ~2M K / Hot Flares ~6.3M K / Flare Plasma ~10M K / Active Corona ~2.5M K / 10M K Hottest flare plasma

If "M" means "million", then it's correct but not the best way to express things. If "M" means "mega", then there must be a space after the number and no space before the unit of kelvin - it needs to be written as "1.2 MK" (megakelvins), "2 MK", etc.

The Cosmos at a Glance / 1.4M km Solar diameter

If "M" means "million", then it's correct but really not the best way to express things. If "M" means "mega", then stacking prefixes is not allowed in metric - it needs to be written as "1.4 million km" (full number word), "1 400 000 km", or "1.4 Gm (gigametres)".

In general publications, any length unit bigger than the kilometre is extremely uncommon. But this aversion to large prefixes is weird because we are (forced to be?) routinely comfortable with megahertz, gigahertz, megabytes, gigabytes, terabytes, megapascals (material strength), megaohms (insulators), megavolts (the highest voltage transmission lines). I see no good reason to avoid megametres, gigametres, etc. But the unspoken convention is to write "thousand kilometres", "billion kilometres", etc.

The Cosmos at a Glance / 3,000 km/s Fastest CME speed

This fact is given in kilometres-per-second, but a bunch of other facts are given in kilometres-per-hour. This makes it much harder to compare their relative magnitudes. It's similar to the problem of comparing airplane speeds in knots versus bullet speeds in feet per second. These units aren't wrong individually, but think carefully about when to switch units and when not to.

The Sun facts / A dynamic sphere of plasma photographed by NASA’s SDO every 12 seconds in 12 wavelengths — from the 5,000 K surface to 10-million-degree flare plasma.

Don't switch units mid-sentence from kelvins to degrees (and which type of degree?). Compare "5 000 K" with "10 000 000 K". It's correct but less common to say "5 kK vs. 10 000 kK" (kilokelvins).

The Sun facts / The Sun’s core burns at 15 million °C — hot enough to fuse 600 million tons of hydrogen into helium every second.

I would like to note that 600 million tons (megagrams) is 600 Tg (teragrams). But it's also an unspoken convention to avoid units of mass larger than kilogram, so it's rare to see megagrams, gigagrams, etc. in writing.

The Sun facts / The Sun’s surface gravity is 28 times stronger than Earth’s. A 150-pound person would weigh 4,200 pounds there.

I would prefer not to see the unit of pounds in the discussion, and also the sentence conflates mass with weight. Reworded with extra notes: A 70-kilogram person (anywhere in the universe) would feel like they weigh 1900 kg on Earth (18.7 kilonewtons).

The Sun facts / Sunspots are cooler regions — about 3,500°C compared to the 5,500°C surface — but are still incredibly hot.

You mostly used kelvins to talk about the Sun, but now you're using degrees Celsius for a few facts?

Before anyone accuses me of pedantry, please remember: Clarity matters in communication. We have spelling and grammar rules in English, and there are also rules in technical syntax such as expressing quantities using the metric system.

Also, people copy each other, so setting a good example is not just about the current reader, but also future writers and readers. To give an example, almost no one uses the unit "kelvin" correctly, and the bad usages keep getting propagated. Incorrect - "4000-Kelvin light bulb" (adjective form, uppercase), "temperature of 273 degrees kelvin". Correct - "4000-kelvin light bulb" (adjective form, lowercase), "temperature of 273 kelvins" (non-adjective form requires plural). The unit of kelvin must be treated no differently than joules, watts, newtons, etc.

The purpose of standards is to reduce the space of possibilities, which makes it easier for writers to choose what to write and easier for readers to understand the correct intended meaning. As an example, the symbol for metre is just "m", no others. Some ad hoc sloppy abbreviations for metre include: "M" (conflicts with mega), "mtr", "mtrs", "ms" (conflicts with millisecond). For writers and readers alike, it's much easier to learn the single symbol rather than four or more ways of expressing the same unit. Similarly, gram is "g", but I've seen supermarkets with labels like "gm"; kilometre is "km", but I've seen "kms" as an ad hoc plural.