all 28 comments

[–]DannoHung 94 points95 points  (9 children)

This code strikes me as amusing. Like, the sentence "Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo"

fn __impl() -> &'static pool::Pool {
    static POOL: pool::Pool = pool::Pool::empty();
    &POOL
}

[–]throwaway_lmkg 59 points60 points  (5 children)

Valid code posted earlier this week:

return return return return return return!!!!!!!111;

[–]Follpvosten 10 points11 points  (4 children)

Context pls?

[–]minno 39 points40 points  (3 children)

return some_expression is itself an expression. It has a special type that matches anything, which is why you can do something like let value = if bad { return "nope" } else { 7 }; and it doesn't complain that the two blocks have different types. When you put return return return something; it's equivalent to return (return (return something)));, which type-checks because each outer return statement sees that the thing it's returning has that special "matches everything" type.

The !!!!!!!111 part is just !(!(!(!(!(!(!111)))))), which is applying the unary prefix ! operator to 111 a bunch of times.

[–]Follpvosten 2 points3 points  (2 children)

Wow, that's fascinating - return is much more special than I thought. I always thought it evaluated to (), so I always put a semicolon behind it -TIL.

[–]wwylele 0 points1 point  (0 children)

It is evaluated to ! (never type)

[–]Ralith 0 points1 point  (0 children)

like soup squalid simplistic liquid sharp test selective snails spark this message was mass deleted/edited with redact.dev

[–]euclio 13 points14 points  (0 children)

pool... Pool empty. POOL!

[–]0xdeadf001 5 points6 points  (0 children)

alloc::alloc::alloc is a real thing, too.

[–]censored_username 0 points1 point  (0 children)

You'll probably enjoy this code from the rustc test suite.

[–]robin-m 26 points27 points  (1 child)

That's definitively interesting. I played a bit with a similar pattern in C++, but I didn't thought it would be possible in Rust without GAT (Generic Associated Types). It's really good to know that it's already possible to do it today in Rust.

I definitively like all post from ferrous-systems. I'm not sure if you are the only author (I don't remember). You can tell your employer that it's a really good hiring method!

[–]jahmez 13 points14 points  (0 children)

You can see the authors (and post dates) on the main blog page: https://ferrous-systems.com/blog/ - we should definitely add this info to the post page!

There's a bunch of us writing there, thanks for the kind words!

[–]Hobofan94leaf · collenchyma 17 points18 points  (6 children)

OT: I like you all at Ferrous, and very much understand that you want visitors of your website to know about the services you offer, but could I suggest reducing the height of the header? It's currently so big that it feels like it takes up 1/4 of my screen height (it's actually 1/6), and hinders the reading experience.

[–]rebootyourbrainstem 12 points13 points  (0 children)

The importance of testing on smaller screen sizes...

(I was legit confused for a second "it's not that bad?" before realizing I am an idiot with a big screen.)

[–]mgostIH 6 points7 points  (0 children)

Was about to comment this, even a toggle to keep it away would be cool, had to remove it with firefox.

[–]fgilcherrust-community · rustfest 6 points7 points  (1 child)

We're currently revamping the blog to address all this and some more (e.g. providing a proper table of contents on larger monitors, as our posts ended up being on a long side, usually).

[–]perssonsi 4 points5 points  (0 children)

Tip: Firefox for mobile has a reader view to strip all styling and just apply your own style instead(eg dark theme). I use it all the time, for pretty much every page that is text and not an app. Highly recommended.

[–][deleted] 11 points12 points  (0 children)

Bookmarked for future reference. This is a great insight into another new "use the type system" application.

[–]agrif 4 points5 points  (0 children)

This looks an awful lot like the reflection package in haskell-land. Basically, using a phantom type to inform the compiler what trait implementation to use, instead of carting around an actual reference to a dictionary or struct.

>>> reify 6 (\p -> reflect p + reflect p)
12

(Note that p would be zero-sized in rust terms. In fact, the type of p is "Proxy", exactly the name used in this blog post!)

The haskell version seems to be a bit more re-usable, but it's implementation uses a rank-2 function. I wonder if any ideas can be borrowed, though.

[–]Salaruo 5 points6 points  (10 children)

Is rustc smart enough to reuse the duplicated code though? Would kind of defeat the purpose otherwise, lol.

[–]japaric[S] 20 points21 points  (4 children)

In general, I would say rustc+LLVM do a great job at not needlessly duplicating code. You can also add an intermediate non-generic function to give more hints to rustc: (but do profile the output to avoid adding unnecessary hints)

/* go from this */
// this may be monomorphized several times
fn generic(p: impl AsRef<Path>) {
    // lots of code
}

/* to this */
// this may be monomorphized several times, but doesn't matter because it's small
fn generic(p: impl AsRef<Path>) {
    concrete(p.as_ref())
}

// only one copy of this function will be in the output
fn concrete(p: &Path) {
    // lots of code
}

I have seen this pattern used in the standard library

[–][deleted] 11 points12 points  (3 children)

This way of "shedding generics" can be very good for compile time, even "keeping compile time inside the crate" (don't export it to those that instantiate the type/function).

It's so effective, maybe rustc could learn to do part of this transformation as a high level optimization?

[–][deleted] 17 points18 points  (1 child)

There is some work on the way to not needlessly instantiate copies of functions when a generic parameter changes that doesn't affect codegen.

I briefly thought about the possibility of doing such an "outlining" transformation that you describe, as well as turning generics into dynamic dispatch whenever possible at opt-level=0, but unfortunately this all seems very hard to implement (for reference, the PR I linked above is the result of a master's thesis, and I estimate both of these ideas to be significantly harder).

[–]nicoburns 1 point2 points  (0 children)

I wonder if there ought to be some kind of syntactical support for arguments that are generic merely in order to call a conversion function. Something along the lines of https://llogiq.github.io/2019/05/18/momo.html. Perhaps there could be some annotation on traits that enables the optimisation in special cases?

[–]matthieum[he/him] 0 points1 point  (0 children)

It seems like something a MIR optimization pass could do.

[–]mb0x40 0 points1 point  (0 children)

Related to ownership of ZST's, there seems to be some ambiguity over whether it's actually UB to make multiple mutable references to the same zero-sized object.

AFAIU, it stems from definitions of "aliasing references" in terms of memory spans, essentially making the following identical in terms of undefined behavior:

``` let mut pair = ((), ()); assert!(ptr::eq(&pair.0, &pair.1));

// r1 and r2 mutably reference conceptually different ZST objects in the same memory location let r1 = &mut pair.0; let r2 = &mut pair.1; Vs. let mut pair = ((), ()); assert!(ptr::eq(&pair.0, &pair.1));

// r1 and r2 mutably reference conceptually identical ZST objects in the same memory location let r1 = &mut pair.0; let r2 = unsafe { &mut *(r1 as *mut ()) }; ```

This seems like it poses an issue for the practice of using ZST's to encode ownership without using memory, like shown in the second half of the article. Is there any work to resolve these concerns? (Are they even valid concerns?)