Recent submissions

Comment · 5 months ago
You can't use a worktree without write access to the shared object database. You can use worktrees, or you can containerize your agents, but you can't do both.
Comment · 5 months ago
> hardlinks the index

I think you mean hardlinks the object database? The index (staging area) changes constantly. Not much point in hardlinking it.

Hardlinking the object database is the default behavior with you clone locally on linux. It's great for one-off clones such as CI/CD pipelines and agentic containers, but the benefit in terms of disk space saved is short-lived: as repos evolve independently, they replace their packfiles with new ones, and the new ones will not be hardlinked because they don't contain the same objects.

I like to keep bare repositories in dropbox, but I use `--no-hardlinks` when cloning, because before I did that, on one occasion, dropbox corrupted the bare repo, and my working repo was corrupted as a result.

Comment · 8 months ago
His Sarah Paine episodes have way more listeners than his normal fare. I doubt that's the whole story, but that's surely part of it.
Comment · 1 year ago
`man perl` and `man perlintro` are the easiest way to get started. Not sure about Raku.
Comment · 1 year ago
Comment · 2 years ago
Good question. Technically, ToOwned counts:

  pub trait ToOwned {
    type Owned: Borrow<Self>;
    fn clone_into(&self, target: &mut Self::Owned) { ... }
  }
Here the `Owned` is technically an input to `clone_into`, but of course semantically it's still an output.

A more subtle one is `StreamExt`:

  pub trait StreamExt: Stream {
    type Item;
    fn map<T, F>(self, f: F) -> Map<Self, F>
       where F: FnMut(Self::Item) -> T,
             Self: Sized { ... }
  }
Here, the associated type `Item` is the input to the mapping function, and since the mapping function is an input to the map function, it is an input-to-an-input - which basically makes it an output. i.e. the stream "outputs" the items into the mapping function. (aka two contravariants make a covariant).

I couldn't find any more direct examples.

Comment · 2 years ago
To clarify things a bit further, I find it helpful to think of traits as open compile-time functions that input types (including Self) and output both types and functions.

  pub trait Mul<Rhs> {
      type Output;
  
      fn mul(self, rhs: Rhs) -> Self::Output;
  }
This begins the open declaration of the compile-time `Mul` function. It has two inputs: `Rhs` and `Self`. It has two outputs: `Output` and `mul` (the top-level runtime function).

Note that we haven't defined the compile-time `Mul` function yet. We've only opened its definition. It's sort of like writing down the type of a function before we write down its implementation.

The implementation is never written down, though, because it is always the same: a lookup in a table that is constructed at compile-time. Every impl fills in one cell of the compile-time table.

  impl Mul<f32> for i32 {
    type Output = f32;
  
    fn mul(self, rhs: f32) -> Self::Output {
      self as f32 * rhs
    }
  }
This adds a single cell to the `Mul` table. In psuedo-code, it's like we are saying:

  Mul[(i32,f32)] = (Output=f32, mul={self as f32 * rhs})
The cell is a pair of a type and a function. For traits with lots of functions, the cell is going to be mostly functions.

The main thing I'm pointing out (that the author didn't already say) is that `mul={self as f32 * rhs}` is also part of the compile-time table, not just `Output=f32`. The author says that asso­ci­ated types are no more than the return of a type-level func­tion, and I want to clarify that this isn't a metaphor or mental short-hand. Traits ALWAYS HAVE BEEN type-level functions. They input types and output mostly functions. Associated types just allow them to output types in addition to outputting functions. Notice how associated types are defined inside the curly braces of an `impl`, just like the functions are.

Once you realize this, it's all very simple. I think there are a few things that obscure this simplicity from beginners:

1. `Self` is an implicit input to the compile-time function, with its own special syntax, and for many traits it is the ONLY input. When reading a book on rust, the first examples you encounter won't have (other) type parameters, and so it's easy to overlook the fact that traits are compile-time functions.

2. Rust traits are syntactically similar to object-oriented polymorphism, but semantically duals of each other, so experienced OO programmers can jump to wrong conclusions about rust traits. Rust traits are compile-time and universally typed. Object-oriented polymorphism is run-time and existentially typed.

3. Because the trait-as-compile-time-function's implementation is so highly structured (it's just a table), it can actually be run backwards as well as forwards. Like a prolog predicate, there are 2^(#inputs+#outputs) ways to "invoke" it, and the type-inference engine behaves more like a logical language than a functional language, so from a certain perspective associated types can sometimes look like inputs and type parameters can sometimes look like outputs. The reason we call them functions and not merely relations is because they conform to the rule "unique inputs determine unique outputs".

Comment · 2 years ago
Do you decelerate in both axes?
Comment · 4 years ago
Why do you need runtime codegen? What exactly needs to be "instantiated"? Ultimately the runtime representation of a type parameter comes down to sizes and offsets. Why not have the caller pass those values into the generic method?
Comment · 4 years ago
Comment · 4 years ago
Depends on what you mean by "decline". But if you're talking about stock price, then the current Shiller PE Ratios are:

Amazon = 238.08 Netflix = 219.32 Google = 73.95 Facebook = 68.36 Apple = 63.17

The Shiller PE Ratio of the S&P 500 is current ~30. All of these companies are overpriced, and Amazon and Netflix significantly so.

Comment · 5 years ago
Answer to #1:

In the google search results, click the three vertical dots above the link and to the right of the domain. If using mobile, you'll need to switch to desktop mode to see the three dots. After clicking, an "About this result" pane will pop up to the right, probably[1]. In that pane you'll see the true link, and you can Right Click > Copy Link.

[1]: On my computer, the "About this result" pane says "BETA", so not sure if everyone can use it. It works for me in a private window, though.

Comment · 6 years ago
Comment · 6 years ago
I have to disagree strongly with point 2. IDEs are much better at the read path than simple text editors are. Critical to reading code quickly is being able to navigate it quickly, answering questions like "What are the subclasses of this?", "Where is this called?", "What are the methods in this interface?", "What does super do?", etc. Grep can only take you so far. Language server protocol is definitely improving things, but it still can't answer questions like "What is the chain of function calls linking the creation of this object to its eventual use?"
Comment · 8 years ago
If I wanted to gain a more intuitive appreciation of the patterns described in the presentation by learning a language, which is the best place to start: APL, J, K, or something else?

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton