HNHacker News
TopNewBestAskShowJobs

Hercuros

126 karma · joined May 9, 2019

submissionscomments
Hercuros··on US Senate votes unanimously to make daylight savings time permanent
I don't really think it simplifies things to change every single meeting/appointment/agreed-upon time an hour forward/backward two times a year without changing the actual clock time. If I have a weekly appointment at 11:30 for the whole year, I don't want to be putting that at 10:30 in some months and 11:30 in others. But if you move the clock an hour forward or backward, it can just stay at 11:30 on every day (though the effective time will of course be different).
Hercuros··on Bounded dynamicism with cross-modifying code
This looks pretty interesting, and it's also cool to see situations where the hardware manual says you should not do something, while in practice it is okay due to the way the hardware is actually implemented (basically, relying on undocumented guarantees).

It would be nice to see some performance numbers for this as well, since CPUs obviously also have branch predictors and might be able to make branches really cheap if they always take a certain branch, especially in a hot loop, where this kind of optimization is most likely to happen.

I could also imagine that the use of inline assembly for control flow makes the compiler able to do less optimizations due to having less understanding of the control flow (the effect of that is harder to test in a microbenchmark). Maybe it's okay though if it's not volatile inline assembly.

Another way to achieve something similar to this is to use C++ templates to generate multiple versions of your code where you hardcode the branches so they get removed at compile time. Of course, for N branches this requires 2^N versions of your code, so it doesn't scale well to large number of branches, but it might allow you to push a few branches out of your hot loop into a higher level where it gets tested less often.

Hercuros··on Data races in Python, despite the Global Interpreter Lock
There are still some points in your explanation of data races that are not entirely correct (partly a matter of definitions).

A data race occurs when two memory accesses race, and at least one of them is a write. In C/C++, data races using non-atomic accessed are undefined behavior, and that's why those can be very bad and you definitely want to avoid those.

You can also have a data race using atomic accesses, but there the behavior (ignoring some of the issues with the C/C++ memory model) is well-defined, and therefore it is not by definition incorrect.

I would say that the Python code in the post does have a data race (since it has unsynchronized accesses to a variable, and at least one is a write). But the behavior of that code is still precisely defined (though non-deterministic), since Python just guarantees that you will see some interleaving of the individual atomic steps of each of the threads due to the GIL). Hence the data race in Python is not undefined behavior as in C/C++, and hence it does not have the same negative connotations. Basically, Python variable accesses behave like sequentially consistent atomic reads/writes in C/C++.

Note that data races in C/C++ being undefined behavior is in large part due to compiler optimizations and preventing accesses from being reordered by the compiler or the CPU. If you're working with 32-bit (or 64-bit) cacheline aligned memory accesses, then "clobbering" or "tearing" of memory accesses is not likely to be affect you, but your code can still be broken by reordering in the compiler or the CPU (either due to instruction reordering or caches/bus communication). Hence if you have a data race on say an int variable, you probably will never see 65536 there if you didn't write that value there, but you might see older/newer values than you would expect.

Hercuros··on Case against OOP is understated, not overstated (2020)
Speaking as someone with experience with many of those things (PL theory/formal verification background), I don't think they're even close to being a silver bullet.

Coming up with the right abstractions and the right domain model is difficult (especially if you just sit down and try to come up with stuff, you're likely to get it wrong the first time around). Knowing about some of those things could help you come up with better abstractions, but it's neither necessary nor sufficient to ensure that you will.

Take dependent types for example. They allow you to express more program invariants or correctness properties in your types. But actually using them requires you to write proofs (at least, if you're using them to their full potential). And I do think that in general System F like type systems hit a nice sweet spot and are generally good enough for the stuff that you might actually want to handle on the type system level.

I've also run into similar "proof-like" situations with much simpler type systems like those of Haskell and Rust, where I was structuring my types to "make illegal states unrepresentable", but in the process ended up complicating my program due to having to match the structure of my program to the expected structure of the types. Sometimes it is nice to _not_ to have the type system enforce some of your invariants. (Such things are also doable with dependent types of course, but this is just an example of some of the tradeoffs involved).

You can also still have a shitty domain model even if you use all of those fancy tools. They just allow you to be very formal/precise about the domain model (and do perhaps encourage some more uniformity by making it more annoying to express ugly or complicated things).

Hercuros··on Thread Safety in C++ and Rust
Another option instead of using Rc/Arc is to use integer indices/handles into (e.g.) a vector holding your objects. Then you can have safety (in the sense of there being no language-level UB) by bounds checking your indices (you can do even better if you use a generational arena and attach a generation counter to your indices), and you can still have arbitrary object graphs that way.

I think that this pattern is common in C++ game programming as well (e.g. when using entity component systems), because using pointers or references everywhere and building complicated object graphs is a recipe for object lifetime issues.

I would be surprised if anyone could handle the mental complexity of managing ownership in arbitrary object graphs without there being some simplifying idea (like that of an ownership tree) involved, even if it's not enforced at the compiler level (as it is in Rust, but it isn't in C++).

Hercuros··on Tokio Console
I sometimes wonder what is the fundamental distinction between a callback-based API and this wakeup-based task API. I guess the main difference is that in a callback you generally provide the result as an argument whereas with a wakeup-based API you just wake the task and it has to look for the result in some stored state somewhere.

But ultimately both of them take the "rest of the computation"/continuation and store it somewhere (i.e. on some sleeping task/callback list) to be awakened/invoked later.

Hercuros··on Is it stealing to read by the light of your neighbour’s lamp?
It's an interesting thought experiment IMO and you can't really resolve moral questions by looking at what the law says. After all, the law tends to be based on some moral principles, and laws can fail or be ineffective/corrupt.

It is quite conceivable that when it comes to working-from-home (and having the employer contribute to the costs that you make at home), the laws simply aren't in place yet, because we have never seen WFH on the scale that we see during the pandemic. So it is ultimately silly to try to determine what is reasonable based on the currently existing law here.

Hercuros··on What memory model should Rust use?
Having "unsafe" mean "can wreak havoc if used incorrectly" is fine, as long as it's clear what constitutes incorrect usage, and what the behavior of correct usages is. And it does not have to be clearly defined what "havoc" is (just like undefined behavior can cause any behavior).

My issue is with using "unsafe" to mean "watch out, you might be using this incorrectly, but no one even knows the exact rules that you should stick to to make sure your code is correct."

Of course, having it be in the "unsafe" part of Rust is better than having it be in safe Rust. But ideally you would be able to look at any part of a Rust program and be able to tell what it does, without having to think in terms of specific compiler optimizations or hardware details. Otherwise formal verification of concurrent algorithms and data structures becomes hopeless.

Hercuros··on What memory model should Rust use?
Relegating parts of the memory model with unclear/hard-to-specify semantics (i.e. relaxed or consume) to the "unsafe" part of the language is an interesting idea, but it kind of goes against the spirit of "unsafe" (this point is debatable, of course).

The purpose of the unsafe keyword is to mark code that could cause safety issues (undefined behavior) if its expectations about the surrounding code are not met. (e.g., an unchecked array access expects its index to be in bounds).

With unlimited time and resources, it should be possible to give a mathematical proof about those unsafe blocks, showing that their expectations are met and that undefined behavior will not actually occur (by for example proving that the array index supplied will always be in bounds).

But since relaxed and consume have unclear semantics, it hard to formally reason about the correctness of any code that uses them (and it is also hard to build tools to do that checking, as mentioned).

So in an ideal world, we would have a 100% clear semantics for all parts of the language, _including_ the unsafe fragment. Unsafe should not be a place to put poorly specified languages features.

Of course, we don't live in this ideal world, but I would rather hope for fixing the memory model so that it be made completely formal and precise (if necessary, giving up some currently allowed compiler/hardware optimizations if they're more trouble than they are worth). As an extreme example, sequential consistency is easy to understand as long as you don't mix it with other types of atomic accesses and avoid non-atomic data races.

Hercuros··on Algebraic data types: things I wish someone had explained about FP (2019)
My point was basically that you can implement the array abstract data type (creation, set value at index, get value at index) in a lot of ways, including by using ADTs (although it seems hard to get an O(1) implementation if you use ADTs, unless you have some clever compiler or language mechanism). But just because you can implement arrays in terms of ADTs doesn't mean that arrays ARE ADTs.

Now that I think of it a bit more, it seems to be a category error to say that a "set" or an "object" or a "dictionary" is an algebraic data type. Algebraic data types are types (values) constructed out of simpler types (values) in a certain way, and that can be deconstructed in a way that mirrors the way they were created. You can implement various APIs/interfaces on top of that, including dictionaries and sets and whatnot.

But my point was that you can do the same on top of just integers (assuming you have the common integer operations), and you could even package it up in a type safe way so that the fact that you used integers in the implementation does not leak out, assuming the language has some modularity/abstraction mechanism so that you can make stuff private to a module. But based on this it seems to be a stretch to say that dictionaries are REALLY just integers or bitstrings.

And just like you probably wouldn't want to bring "integer reasoning" to bear on dictionaries, you probably don't want to use ADT reasoning to reason about dictionaries either. Because then you are really reasoning about the concrete implementation details and generally speaking those details are hidden from clients of the dictionary (and subject to change at any time).

Hercuros··on Algebraic data types: things I wish someone had explained about FP (2019)
This is not true for classical logic, because AND can be written using NOT and OR using DeMorgan's law.
Hercuros··on Algebraic data types: things I wish someone had explained about FP (2019)
Although if you just consider 1-1 correspondence, then basically any type with a countable number of inhabitants is isomorphic to the integers (when the type is viewed as a set of inhabitants). And that makes sense, because we can always just take the binary representation of any data type in memory.

And if you just have unit type, empty type, sums and products, then you can only make types with finitely many inhabitants. Adding the integers to that makes you able to make any countable type, but potentially in a trivial way as described above.

Therefore just viewing the types as sets does not give a very satisfactory basis for determining whether a type is an "algebraic data type". Maybe we could do better if we consider some more aspects related to type safety, but it's not immediately obvious to me how.

Hercuros··on Stack size invisibility in C and the effects on "portability"
Wouldn't the compiler be allowed to elide the memory accesses that are being used to poke the memory region? If you are doing the poking before the memory has been initialized, then I'm not sure there are any guarantees that the compiler will read from the actual memory region (since it's uninitialized). And if you do writes to do the poking then there might be similar issues if the result of the write is never used. Even for reads you would have to make sure that the result gets used. Also not sure if casting to volatile is allowed if the object itself is not volatile. This is all true regardless of UB.

It seems to me like it is impossible to do poking in a way that could not be elided by the compiler, because removing poking never alters the semantics of the program (stack overflow or guard pages are not part of the semantics of C, I believe).

Of course, in practice you'll probably get the right behavior, but I'm personally always interested in language lawyery questions. I do believe that there are cases of security issues introduced by compilers eliding memset operations on password buffers, because the compiler can tell that the result of memset is never used and so it doesn't actually clear the memory. These sorts of things are tricky to get right.

Hercuros··on Asynchronous Programming in C#
You can have UI workflows just as well with a language that has (runtime-managed) green threads, like Go and Elixir. It's just that you sometimes have to make sure that certain green threads have their actions scheduled on the UI (OS) thread for backwards compatibility reasons. For example, the Scala ZIO library provides the means to control where (on which OS thread) code is scheduled in a very intuitive way that does not involve ConfigureAwait hacks. ZIO is not green threads and rather more like async/await, but a similar approach could be implemented in languages with runtime-managed green threads as well.
Hercuros··on A proof P = NP was accidentally published in TOCT
It's also important to realize that the standard Turing machine doesn't actually have an infinite tape, but rather it has a tape that can grow to hold an arbitrarily long, but still finite, sequence. At any point during the execution of the Turing machine, only a finite part of the tape will be occupied.

So we can construct approximations of it in the sense that we can create computers with varying, finite amounts of RAM. This might seem like a pedantic/obvious point to make, but it is actually also possible to design abstract computational machines that operate on truly infinite quantities, like a machine that has random access to an infinite, uncomputable sequence.

From a simplicity perspective, it also makes more sense to consider machines with an arbitrarily large amount of RAM (you can always hotplug more RAM), compared to setting some arbitrary limit because that is the most RAM we happen to be able to achieve in this universe.

Hercuros··on Why I no longer contribute to Racket
> I've had a professor like that and it takes a while to realize that those people are needed. For lazy students it may be a proper wake up call to the real world

Though it should be mentioned that just as frequently (if not more) such behavior can cause "lazy" students to feel even more discouraged, if their discouragement is what is demotivating them. I would question the premise that to motivate "lazy" students one should give them "tough love." Of course, there are some cases where it might be helpful, but even then it should never be the kind of behavior described in the article, IMO.

Hercuros··on New evidence that British workplaces are losing viewpoint diversity
I think it is still understandable though that making those kinds of technical corrections about a study could be perceived as "defining away the problem" or getting too technical about a (potentially) real societal issue.

The mere fact that you are talking about "TV reporters" way of talking about things communicates that you have a disdain for the way such issues are commonly discussed in the media or by the general public, and correcting their statement about the study also seems to suggest that according to you really there is no gender wage gap (or it's less of an issue than people would seem to generally think), it's all just due to personal choice or preference in what type of jobs they do or something to that effect.

You can of course agree or disagree about a lot of these things, but I do think that sometimes a "mere factual correction" can have additional connotations that are much more political and not just neutral statements. It's often the opinion or suggestion behind the factual correction that causes more offense.

Hercuros··on Graphical Linear Algebra
Note that Kevin Buzzard is talking in the context of convincing "mainstream" mathematicians to use a proof assistant. He specifically clarifies somewhere (not sure where in this video, but I've seen other videos where he clarifies it) that when he talks about "proper mathematics" he is doing so in kind of a tongue-in-cheek, British way and does not mean to suggest that other kinds of mathematics are not proper (don't remember the exact wording).

In the context of that video, his comments about category theorists and type theorists make a lot of sense: type theory people and (perhaps to a more limited extent) category theory people tend to be more easily sold on using a proof assistant since the kind of mathematics they do translate more easily into current proof assistants than, say, analysis or topology.

I definitely do not think that Kevin Buzzard is suggesting that type theorists and category theorists are not doing interesting and/or useful work (after all, the proof assistant he is advocating for is based on type theory). At best, he is making a sociological observation that there is a gap between the type theory/category theory community and "mainstream" mathematicians making the widespread adoption of proof assistants in mathematics more difficult.

Hercuros··on All these companies were a lot smarter than us. What we had was luck (1984)
To be fair, you don't hear (as much) about all the Mark Zuckerbergs who weren't quite so successful. If you're going to look at some of the richest people on the planet, then of course you'll see a string of successes, because without a long string of successes they wouldn't have been the richest people on the planet. I also think that as the string of successes becomes longer (or you become richer), you have more of a chance at further successes as well.

Looking at the most successful people in any situation is not a good way to get a sense of the underlying probabilities involved. If you let 1000 people flip coins 1000 times and count the number of heads, you'll see an extraordinarily high number of heads among the most successful people.

The mere fact that there are really few people as rich as Zuckerberg indicates a big luck / network effect factor in my opinion. Zuckerberg is probably more skilled than the average person, but there are many more people like him in terms of skills (I believe), and the vast majority of them didn't get anywhere near as rich. Zuckerberg also didn't accumulate his wealth by lots of small repeated increments: he won big by Facebook becoming successful (and there was no guarantee of that, despite Zuckerberg's skills). Without that big win, I doubt that Zuckerberg would have ended up anywhere near #3.

Hercuros··on Rust Is Surprisingly Good as a Server Language
If you can afford a garbage collector, then you can also just use something like Haskell or OCaml or Python, which also gets you memory safety. No need to think about lifetimes or different types of smart pointers. Not saying that it’s a lot of mental overhead, but it’s definitely a trade-off.
Hercuros··on Gravity: An embeddable programming language without any external dependencies
What does it mean for a type system to be “complete”? Type soundness means that well-typed programs do not “get stuck”, but it is not obvious at all (at least to me) what it means for a type system to be complete, formally speaking.

If you just mean that a program has certain properties (like performing IO) that are not expressed in its type, then I can see what you mean. But even in Haskell, some properties like “this function might fail to terminate or throw an exception” are not expressed in the type (although you can use monads for those things in languages where all functions terminate by default). There are no distinctions between a function that performs network accesses and one that does not, or functions that never return odd numbers, etc. There are infinitely many program properties that you can come up with which are not expressible in Haskell types.

Even dependently typed languages with very expressive type systems cannot capture all possible program properties due to logical incompleteness results.

Hercuros··on The case against CS master's degrees
I think that just because most people do not write compilers for a living does not mean that it’s not useful to have implemented one. Writing a toy compiler properly is an interesting programming exercise that involves steps such as parsing/validating input and transforming it in a structured way. Even if you never write a compiler again, it can teach you many things of how to approach similar problems.

(Also, Apple didn’t exactly repurpose LLVM for Swift. LLVM is just the backend, and Swift has quite a sophisticated frontend with its own optimization passes and intermediate language. It is safe to say that a lot of compiler theory and programming language design went into writing it. As another example, the compiler for Go was basically written from scratch and does not use something like LLVM for code generation.)

I do agree that learning CS theory is no substitute for actually writing software, and doesn’t make you a good software developer by itself. And there are probably plenty of excellent software developers who couldn’t recall what a Turing machine is. That said, a good knowledge of CS fundamentals is indispensable for some types of software development.

Hercuros··on Tips for the depressed
I never really understood the point of view that depressed people somehow are more realistic, seeing things as they “really are”, while non-depressed people are overly optimistic. Maybe it’s true in the limited setting of a study, but depressed people tend to behave in ways that are basically irrational and counterproductive: staying in bed, passively ruminating about the future, procrastinating and avoiding useful/enjoyable activities, etc. These are not the actions of a rational person, and many (perhaps not all) depressed people would feel somewhat better if they didn’t engage in these types of activities. It’s definitely hard to change this type of behavior, and change is not a magic cure, but it is a useful component.

The reason why I believe the “depressed people are just seeing the world as it really is” line of thinking is harmful is that it encourages people to believe that their depression is simply the result of their accurate world view, and that trying to change things in order to feel better would mean they have to fool themselves.

Hercuros··on Why Rust, or a Trip Report from My Satori with Rust and Functional Programming
I don’t think they are going to be phased out, since including lifetime specifiers is a means of documenting intent (they are part of a function’s public interface). Removing them would mean that seemingly irrelevant internal changes to functions would cause mysterious compiler errors elsewhere.
Hercuros··on Seneca on The Shortness of Time (2017)
That's a fair point. I do think that we essentially live in a world that is built up largely out of psychological/social constructs and mental abstractions. In a lot of ways, a psychological or social construct can be a lot more "real" than the "raw" universe (which I don't think can be perceived directly and is more of an abstraction). Therefore, I think it's often more useful to look at the world as it is experienced by people, rather than how it "really is".
Hercuros··on Seneca on The Shortness of Time (2017)
> This might all sound pretty dark, but the good news is that nothing you do is really important. The universe will remain unperturbed no matter what actions you take (or don't)! So if you're stressing about how well you live, remember that you're merely chasing fictions in a framework that someone else cooked up.

I'm not really convinced by this type of reasoning. Things do matter if people care very deeply about them. If someone murdered someone close to you (to take an extreme example), would you still say that that is fine, because in the grand scheme nothing matters? You might say that you're an irrational human being, and that's why you care. But why should we take a definition of "meaningful" that is so disjoint for everyday human experience?

What would a hypothetical world look like in which life does have meaning, according to your definition? If no such world is even imaginable, then it isn't even clear what we are talking about.

Furthermore, I think some people use the supposed "meaninglessness" of life to justify passivity. If the universe is truly meaningless, then doing nothing is as meaningful as doing something traditionally considered meaningful.

Yet, people often base their behavior on their current emotional state. That is not the behavior of someone who believes in the complete meaninglessness of everything. Clearly, that person believes that his emotions matter and are a good guide to choose which actions to take. Playing Xbox on the couch or ruminating about the meaninglessness of life being good examples of this. Such actions are choices that are ultimately derived from value judgments.

Hercuros··on A scalable photonic computer solving the subset sum problem
Mixed integer programming is a more specialized task than SMT solving, therefore an MIP implementation is likely to be more optimized for the task, even if you might be able to use an SMT solver to solve the same problem. Moreover, SMT solvers are focused on finding some solution to some constraints, whereas MIP solvers are focused on finding the best solution to the constraints according to some linear objective. Finally, an SMT solver is basically a SAT solver combined with a theory solver for reasoning about integers, etc. If the problem can be expressed just as a conjunction of constraints (i.e, it has no interesting propositional structure), then you don’t really need the SAT solver part and can just use a specialized theory solver (optimizer, in this case) directly.
Hercuros··on Haskell Problems for a New Decade
Dependent types are not just useful for proving correctness properties, and in fact I think dependent types in Haskell are not really intended to prove really complex properties, like the full functional correctness of a compiler. Hence, I think the use of Coq or Agda proofs as an example of impracticality is a strawman argument. You might need a research team and several years to show the correctness of an operating system in Coq. You do not need that to have type-safe database access or statically checked matrix sizes. Not all non-research uses of dependent types are impractical.

You could use many of the same arguments you’re making against dependent types against most programming language features. Why should a language have generics? Or first-class functions? Or even any kind of static typing whatsoever? Should Java not have added lambdas because it already had anonymous inner classes? You can clearly get by just fine in a lot of business applications without some of these features.

I think we should rather be discussing whether dependent types are useful for relatively simple applications, like providing type-safe database access or REST APIs in a library, rather than looking at them as tools for proving functional correctness. It’s not so clear that dependent types are too complex a solution there, especially if you look at a library like Servant, which already uses some advanced type system features, and which is actually a really practical library that is probably used in production applications as well. A library like Servant might be able to expressed more clearly with dependent types than with a hodgepodge of type system extensions. I think that wanting type-safe REST API access is already an order of magnitude more practical than model checking kernel code.

Hercuros··on A Kaggle Grandmaster cheated in $25k AI contest with hidden code
People are saying that you do not just submit your trained model to Kaggle. You also submit the code that was used to train the model from the training set, which is used in the winning models to train them from scratch on the training set. Of course, that wouldn't have prevented this type of cheating of course, but it does mean that you can't submit a model that was trained on your own private data set.
Hercuros··on An alternative argument for why women leave STEM
It should also be mentioned that general statements or studies about the relative mathematical or technical abilities of men and women do not necessarily have any direct bearing on specific groups of men and women, like “people who have successfully completed a STEM PhD”. In fact, it’s quite plausible that any differences between men and women disappear once you only look at those people who have a PhD, even if those differences did exist in the general population (which is debatable, and even if it is true, it is not clear which factors are responsible for it). Since this article talks about gender disparity in the population of people who have a PhD, statements or studies which apply to the general population are not really all that relevant.
← PreviousPage 2 of 3Next →