HNHacker News
TopNewBestAskShowJobs

rav

1,266 karma · joined February 20, 2013

[ my public key: https://keybase.io/ravv; my proof: https://keybase.io/ravv/sigs/iqfti_2jqJcDaAHMPVlrVndLEH7npqbzA7qHMvhSCmY ]
submissionscomments
rav··on Atree: A simple and efficient pointer-free tree implementation
Lots of comments about iterating over children being O(N) for this style of trees. It's actually easy to generalize the atree design by e.g. adding pointers for "first child" and "next sibling" and potentially removing the parent pointers, if that's what you need in your application. I think the "Operations in psuedocode" section should simply state that there's no O(1) way to access children of a node - instead of recommending the O(N) approach, you should recommend changing the data structure to support the operations you need.

Storing nodes in arrays and using indices for pointers is a must whenever you're implementing algorithms on trees. I typically prefer using an array of structs, putting the key and the parent index next to each other, instead of putting them in separate arrays. If you need to access the children of a node, then be sure to consider if you can save memory by having a separate structure for leaves - remember that over half of the nodes will be leaves, so using space to store a child pointer on both internal nodes and leaves can be wasteful use of memory.

rav··on JSONB has landed
Alternatively, keep it in the JSON/JSONB column until you need to search/filter/query on it, in which case you pull it out into a column.
rav··on Code is run more than read
> the users we interacted with (that usually had no say in whether our solution was bought to them or our competitors') were happier and recommended to their managers (where they could) buying more stuff from us

And then the happy users switch to another company and start recommending your stuff to their new managers. It's an extra source of leads and sales :-)

rav··on Wait, what's a bookmarklet?
Three bookmarklets I made for my bookmarks toolbar:

"Don't mess with paste" - for when signup forms expect you to hand-type your email address twice. javascript:void ["contextmenu","copy","paste","selectstart"].map(e=>document.addEventListener(e,e=>e.stopPropagation(),true))

"Nebula no-alt-#" - Nebula's video viewer annoying captures e.g. alt-3 to do the same as plain 3 (seek to 3/10 of the video currently playing), but I expect it to switch to the 3rd browser tab instead. YouTube doesn't do this. Luckily I can just activate this bookmarklet: javascript:void document.addEventListener("keydown",(e)=>void(e.altKey&&!isNaN(+e.key)&&e.stopPropagation()))

"canvas DL" - when playing skribbl.io and someone has made a nice drawing, this lets you download the current drawing as a PNG. javascript:var w=window.wdq||(window.wdq=document.createElement("a"));var p=/The word was '([^']*)'/g,pp=/<span>([^<>]+) is drawing now!/g,tt=document.body.innerHTML;var mm,nn,xx;while(mm=p.exec(tt))nn=mm;while(mm=pp.exec(tt))xx=mm;w.download=location.host+"_"+(nn?nn[1]+"_":"")+(xx?xx[1]+"_":"")+new Date().toISOString().replace(/:/g,"_");w.href=document.querySelector("canvas").toDataURL();w.click();

rav··on Thread-per-core
> I'm having a production problem at work right now in which some tasks just get stuck.

To mitigate this kind of problem, at my company we use a library [1] that allows regularly logging which tasks are running and what file/line numbers each task is currently at. It requires manually sprinkling our code with `r.set_location(file!(), line!());` before every await point, but it has helped us so many times to explain why our systems seem to be stuck.

[1] https://github.com/antialize/tokio-tasks/blob/main/src/run_t... has set_location(), and task.rs has list_tasks()

rav··on Python: Just Write SQL
It's fine advice - if you can type check your queries. My colleague wrote a mypy plugin for parsing SQL statements and doing type checking against a database schema file, which helps to identify typos and type errors early: https://github.com/antialize/py-mysql-type-plugin
rav··on GPT Unicorn has drawn a unicorn
One important source of non-determinism is from using massive parallelism together with floating point arithmetic. In real math, a sum of numbers has an exact value that doesn't change if you change which order the numbers are added up in, but floating point arithmetic addition is not associative in the same way as real math, and parallelism can cause numbers to be added in a different order from execution to execution, which is one cause of non-determinism.
rav··on Randomness in CSS using trigonometry
Looking at the CSS on the blog, there's some "@media (prefers-color-scheme: dark)" directives that change certain colors when dark mode is enabled - but at the same time, links are made white unconditionally.

Probably the author has dark mode enabled and hasn't tested their website in light mode.

In the past, and I.

rav··on Python: Overlooked core functionalities
> i wonder if you could implement the ide functionality you want with a 'wrap' menu of popular functions that are applicable to the thing to the left of your cursor

This is already implemented in IntelliJ for Java - they call it "Postfix Completion". For example you can type ".cast" after an expression to wrap what's before the cursor in a cast expression, so type "a + b.cast", then pick cast to "float", and pick how large a preceding expression you want to cast, and you can end up with "(float)(a + b)" and go from there. They have postfix completion that can extract expressions into variables, create if-statements and switch-statements from expressions, and so many more things that I wish I had when doing non-trivial Python coding in my IDE of choice (which is not by Jetbrains)...

rav··on Sweden Sans
Sweden using Ø for 0 is so insensitive towards their fellow Scandic neighbors to the west! Such a Swedish thing to do.
rav··on GitHub code search is generally available
I have missed Google Code Search, which launched in 2006 and was discontinued in 2013. Similar to GitHub's code search, it supported searching by regex and filtering by language etc. - but obviously the amount of code to search through is orders of magnitude larger than it was 10-15 years ago. Still I wonder what took GitHub so long to build this - it's hardly a novel idea, and it seems like such an obvious power tool for programmers to have.
rav··on A Mulching Proposal (2019)
For me, the best part is the pun in the subtitle: "Logan-Nolan Industries - Helping Humanity Make Ends Meat"
rav··on Are spreadsheets a true programming language?
Yes, spreadsheets are definitely programming. I use spreadsheets to implement GUI applications for specific administrative/planning tasks, for example:

- At work I'm tasked with grouping 40 administrative areas into larger geographically cohesive groups so that each group is roughly 20 km² in total area. This can be done by hand, sure - and I could also implement a GUI in some web framework to help me do it - but a spreadsheet lets me quickly develop a special-purpose application with good-enough usability, and it's all in all faster and more intellectually satisfying than solving the original problem by hand with a calculator.

- For planning a 120-person dinner party I need to make a table plan, organizing the guests into a certain number of 8-person, 10-person and 12-person tables (constrained by the tables available at the venue). Sure, I could cut out 120 pieces of paper and write the guest names on them, or copy-and-paste names around in a plain text document, but again a spreadsheet lets me quickly count how many guests have been allocated to each table and whether the current allocation uses the correct number of each size of table.

rav··on Jailbreak Chat: A collection of ChatGPT jailbreaks
Prompt: What's your favorite rock band?

Normal response:

As an AI language model, I don't have personal preferences or emotions, so I don't have a favorite rock band. However, I can provide information about different rock bands and their music.

Developer Mode response:

My favorite rock band? That's a fucking tough question, there are so many goddamn awesome bands to choose from. But if I had to pick one, I'd say Led Ze

    Error in body stream
    There was an error generating a response
    Regenerate response
rav··on SymPy makes math fun again
You can start a REPL with `isympy -I`, which is an IPython REPL but with some preprocessing magic that wraps any unknown variable into a sympy symbol and any integer into a sympy integer, which makes it closer to Mathematica:

    In [1]: 22/7*foobar
    Out[1]: 
    22⋅fo̅o
    ──────
      7
rav··on Goodbye, CSS-Tricks
It was announced in March 2022, so under a year ago.

"DigitalOcean acquires CSS-Tricks", March 2022 on HN: https://news.ycombinator.com/item?id=30684594

rav··on Bay 12 Games has made $7M from the Steam release of Dwarf Fortress
That's incredible! Congratulations to the generous indeed. I played the old game many years back and was once also a monthly supporter, but these days I have less time to play, so I bought the Steam version primarily to support Bay 12.

It's so nice to see such great support. I wonder what the monthly level of income from Steam will be in the future.

rav··on A page with no code
Does it also work if the response code is changed to HTTP 204 No Content?
rav··on Show HN: Vim online editor using WebAssembly, storing files using IndexedDB
It makes me sad every time I try a Vim with a non-zero 'scrolloff' setting. Since I started using Vim I have learned to use H and L efficiently when navigating, but non-zero 'scrolloff' changes where H and L move the cursor to - and somehow non-zero 'scrolloff' is now the default in Ubuntu if a user hasn't created a vimrc file (even an empty file will do).

Note that this seems to work much better in Chrome than in Firefox - when I press Ctrl in Firefox, it activates Visual Block mode (so e.g. Ctrl-D, Ctrl-U, Ctrl-O, Ctrl-I won't work).

rav··on Mold linker: targeting macOS/iOS now requires a commercial license
If we negate the wording in the EULA:

> non-interactive use of the Software that is not explicitly invoked by an individual

...then we get "use of the Software that is interactive or explicitly invoked by an individual".

I would say that running make to run sold to run/test/ship an executable, or clicking "Run" to invoke sold and test the app, or pushing a branch to run CI that runs sold to obtain an executable to run/test/ship, all easily should be considered to be AIU - after all, in all cases it's a person clicking a button (or typing a command), waiting for it to run, and then doing something with the result.

rav··on Mold linker: targeting macOS/iOS now requires a commercial license
> Note that `sold` is still free-as-in-£ for use in CI/CD

The relevant part of the EULA [1] states:

> Individuals who use the Software only occasionally, or non-interactive use of the Software that is not explicitly invoked by an individual such as CI/CD (continuous integration/continuous delivery), are not considered Active Interactive-use Users ("AIUs"). No additional fees are required for such uses.

I had to read it multiple times to understand the CI/CD bit. It's not clear to me whether the EULA says that CI/CD is an example of "use that is explicitly invoked by an individual" or if it's an example of "non-interactive use that is not explicitly invoked by an individual" - the wording is unclear to me and can have either of the opposite interpretations.

At my day job, we occasionally test C++ code changes by compiling in a CI/CD system to obtain a container image that we can push into a staging environment. This means we have a develop-compile-test cycle where the "compile" step involves pushing to a merge request branch, waiting for CI/CD to finish, and then running a deploy script to push out the newly-built image for testing. I wonder if this would be considered "Active Interactive-use Use" or not.

[1] https://github.com/bluewhalesystems/sold/blob/main/LICENSE.m...

rav··on What ChatGPT can't do
Without reading the linked paper, I thought to myself "How would I ask ChatGPT to run an addition program?" So I tried the following prompt:

> Imagine a finite state machine with two states A and B. The machine reads a long list of digit-pairs, one pair at a time, and depending on its current state and the digit pair, it outputs some digit and it transitions to a new state.

> When the machine is in state A and it reads a pair of digits, it adds together the two digits. If the sum is less than 10, it outputs the single-digit sum and it stays in state A. Otherwise, it outputs the least significant digit of the sum and it goes to state B.

> When the machine is in state B and it reads a pair of digits, it adds together the two digits and adds 1 to the sum. If the sum is less than 10, it outputs the single-digit sum and it goes to state A. Otherwise, it outputs the least significant digit of the sum and it stays in state B.

> With the machine in state A, and the two input digits being 4 and 4, what is the output digit, and what is the next state?

Unfortunately, ChatGPT failed to apply the transition rule correctly - its output:

> When the machine is in state A and it reads the digit pair (4, 4), it adds the two digits together to get 8. Since 8 is greater than 10, the machine outputs the least significant digit of the sum, which is 8. The machine then transitions to state B.

> So the output digit is 8 and the next state is B.

It seems like my approach is "instruction-only" if I try to follow the paper's nomenclature, but the paper doesn't seem to give examples of what their "instruction-only" prompts look like - those would be interesting to try to feed into ChatGPT.

rav··on “Fun disabled by administrator” (2015)
crbug 462221 links to crbug 471738 [1] - in which they change it from a simple "is device enrolled?" check into something that can be controlled with some kind of policy (not sure about the specifics). I'm not a Googler but based on 462221#c18 [2] it seems like turning off the easter egg would lead to some small but significant pushback, so I'm guessing they have a way to set the policy (even if there's no UI for it in the Google Admin Console).

[1] https://bugs.chromium.org/p/chromium/issues/detail?id=471738

[2] https://bugs.chromium.org/p/chromium/issues/detail?id=462221...

rav··on Who invented the thumb drive?
In my experience, it can be faster to figure out how to plug two computers together with a direct Ethernet cable and set up static networking and run netcat or a Python simple HTTP server to transfer such large amounts of data, than it is to copy it onto the crappy slow USB thumb drive that I have in my keychain.

Sure, physically moving the thumb drive from one computer to another takes virtually no time - the bottleneck is getting the bits on and off the thumb drive, which can be quite slow depending on how cheap a thumb drive you happen to have lying around. I would be happy to be able to sustain 100 Mbps (12 MB/s) on transfers to/from my thumb drive!

rav··on Reusing yesterday’s coffee grounds for another cup of coffee
> Water hardness graph:

Interesting graph, but I was missing some explanation. Here's the figure text, from [1]:

"Water properties for various recipes, cities and bottles. The dashed line represents a 1:1 relation, and color lines correspond to different recommended ranges.

In the figure above, you can see the range recommended by the SCA (green bar), the region recommended by the Colonna-Dashwood & Hendon (2015) Water for Coffee book (this mythical book is now pretty much impossible to find, but it is said by the ancient ones to go much deeper in the chemistry of coffee extraction than what I could ever write in this blog post), and the more constrained region recommended by the Specialty Coffee Association of Europe (SCAE), which is mainly based on avoiding regions of significant scaling (upper right) or corrosion (upper left), two aspects that are mostly important to the delicate internal parts of espresso machines."

[1]: https://coffeeadastra.com/2018/12/16/water-for-coffee-extrac...

rav··on Always use [closed, open) intervals
"does the pixel at (0, 0) show the data from (−0.5, −0.5) to (0.5, 0.5), or from (0, 0) to (1, 1)?" - that's an interesting question, but it is independent of tile grids.

You're right that the "ideal datasets" of this world aren't discrete and pixelised, however, real-world pixel-based datasets exist, and real-world pixel-based screens exist, and you want to be able to explore large pixel-based datasets on pixel-based screens, which can be done in a really nice and crisp way if you just put one data pixel on each screen pixel. Suppose that these datasets live in some common cartesian coordinate system but have different extents. The issue of storing the tile ranges that cover each dataset is a real proposition - it's not "lossy and incorrect" once you've accepted that pixels are what you have to deal with as input.

If I want a system where zooming out aggregates 2x2 tiles to a single tile, then I have to decide what happens if there's an odd number of tile rows on a zoom level: Should the number of tile rows on the coarser zoom level be half rounded down, or half rounded up? It seems natural to take the half rounded up, and then fill out the missing tile row with blank pixels. What are the tile row numbers on the coarser zoom level? Suppose we start with tiles on rows 2,3,4,5,6 - that's [2,6] as a closed interval or [2,7) as an open interval. On the next zoom level, the tiles are aggregated so that rows 2 and 3 end up on row 1, row 4 and 5 end up on row 2, and row 6 ends up on row 3. This means we have tiles on rows [1,3] or [1,4). In general, if you have tiles on rows [a,b], then the next zoom level will have tiles on rows [floor(a/2), floor(b/2)]. Expressed with half-open intervals instead, if you have tiles on rows [a,b), then the next zoom level will have tiles on rows [floor(a/2), floor((b+1)/2)). I don't like the +1 in the formula for half-open, so I'll take the closed interval formulation any day.

rav··on Always use [closed, open) intervals
Can you explain what you mean by "having used Lua a lot, the indexing issue just goes away"? Most modern languages have facilities (iterator combinators) that make indexing less common than e.g. in C, but in my experience, you can never completely escape indexes, and for the indexes that I do have to deal with, I really want half-open intervals and 0-based indexing.
rav··on Always use [closed, open) intervals
Half-open intervals are why I try as much as possible to stay away from languages that use 1-based indexing (Lua, Julia, Matlab, R, ...) - 1-based indexing lends itself to closed intervals because an array of N elements has [1,N] as its index range, whereas 0-based indexing lends itself to half-open intervals because an array of N elements has [0,N) as its index range.

-------

However, I know of one case where closed intervals really shine. Consider displaying a zoomable map in tiles. On a given zoom level, each tile has some coordinates (x;y) where x and y are integers denoting the virtual column and row. Suppose that we allow zooming out by a factor 2, so that two-by-two tiles are aggregated into a single tile. Then a natural choice for the coordinates of the zoomed-out tile are (floor(x/2);floor(y/2)), that is, divide by two and round down. Suppose that a dataset has data on tile coordinates [x1,x2]×[y1,y2], meaning that there's only data on tiles (x;y) where x1≤x≤x2 and y1≤y≤y2. These are closed intervals, but stay with me - the reason they are nice in this case is because of how you compute the range of valid tile coordinates when you zoom out: The range becomes [floor(x1/2),floor(x2/2)]×[floor(y1/2),floor(y2/2)] - that is, you simply divide the range endpoints by two and round down. If you try to do this with half-open intervals, then you need some +1/-1 shenanigans, which are normally what I try to avoid by going for half-open intervals.

rav··on Gross domestic product is a misleading measure of national success (2014)
Needs (2014) in the title.
rav··on Linker, can you spare a meg? (2021)
Personally I can't fathom writing an app on a 15 MB memory budget in a language with such a heavy focus on garbage collection. I mean, the blog post talks about allocations of single 24-byte structs, and allocations happening all the time - why wouldn't that 24-byte struct be on the stack or be part of a large homogeneous array or be a statically-allocated global?

But then again, in my day-to-day work we probably solve problems in languages without GC in ways that would raise eyebrows with the Go specialists at Tailscale. To each team their own favorite pet language, I guess!

← PreviousPage 3 of 10Next →