sciolizer
Joined 19 years ago
Joined 19 years ago
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.
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.
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 associated types are no more than the return of a type-level function, 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".
> This isn’t true (yet)
It's at least partially true:
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.
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.
1: https://www.lesswrong.com/posts/AnHJX42C6r6deohTG/bell-s-the...
2: https://kantin.sabanciuniv.edu/sites/kantin.sabanciuniv.edu/...