Stream: general

Topic: zero-cost futures


gnzlbg (Dec 12 2018 at 13:09, on Zulip):

Are futures really zero-cost ? I can't seem to figure out how to use them without adding overhead, or unsafety :/

gnzlbg (Dec 12 2018 at 13:10, on Zulip):

Like, is there a project using them to map to hardware network I/O ?

oli (Dec 12 2018 at 13:12, on Zulip):

We're using them on embedded for all I/O, even network, but it's not quite finished yet

gnzlbg (Dec 12 2018 at 13:28, on Zulip):

@Oli so I find it impossible to use with DMA without pushing the responsibility of pinning, which is unsafe, onto the user

gnzlbg (Dec 12 2018 at 13:28, on Zulip):

The only way I've found of making this safe is to heap allocate the future

gnzlbg (Dec 12 2018 at 13:29, on Zulip):

I also found the LocalWaker API extremely weird - if you are doing DMA then there is no LocalWaker

gnzlbg (Dec 12 2018 at 13:31, on Zulip):

This makes Poll very weird too: Poll::Pending means "don't poll me again until the LocalWaker is awoken", but since there is no way for that to happen, futures will never get polled

RalfJ (Dec 12 2018 at 13:31, on Zulip):

the responsibility of pinning, which is unsafe, onto the user

hu? no, you can create Pin in safe code. or do you mean specifically pinning on the stack? AFAIK there's a safe stack pinning macro in some crate

gnzlbg (Dec 12 2018 at 13:32, on Zulip):

One could emulate a LocalWaker using a second thread, but... that's definetely not zero-cost.

gnzlbg (Dec 12 2018 at 13:32, on Zulip):

@RalfJ there is pin_mut! in pin_utils, is that what you mean? Take a look at the macro implementation. . .

gnzlbg (Dec 12 2018 at 13:33, on Zulip):

https://github.com/rust-lang-nursery/pin-utils/blob/master/src/stack_pin.rs

RalfJ (Dec 12 2018 at 13:33, on Zulip):

you aren't asking for transitively safe code, are you? you're not going to get far with that^^ (anywhere in Rust)

gnzlbg (Dec 12 2018 at 13:34, on Zulip):

no, i'm just saying that this is very limiting

gnzlbg (Dec 12 2018 at 13:35, on Zulip):

if you want to pin within a method, and store the pin as an struct field, then this macro won't help

RalfJ (Dec 12 2018 at 13:35, on Zulip):

fair. but what you said above was basically "pinning requires the user to use unsafe", and that's definitely wrong

gnzlbg (Dec 12 2018 at 13:35, on Zulip):

let me rephrase: the responsibility of pinning properly is pushed down to the user

RalfJ (Dec 12 2018 at 13:36, on Zulip):

sure. you asked for zero-cost yourself, that's the only way to get zero-cost :D

gnzlbg (Dec 12 2018 at 13:37, on Zulip):

I think that's bad, as in, there is no real way to abstract over pinning

gnzlbg (Dec 12 2018 at 13:37, on Zulip):

if I want to create a type that takes ownership of a future, and pins it, that cannot be done at zero-cost

gnzlbg (Dec 12 2018 at 13:37, on Zulip):

The type cannot be !Move, the type cannot "pin itself", etc.

gnzlbg (Dec 12 2018 at 13:38, on Zulip):

Pushing the responsibility of pinning to the user is the only thing that my code can do, that's good for my code, but bad for its users

RalfJ (Dec 12 2018 at 13:39, on Zulip):

it's no less and no more bad than pushing the responsibility of safe mutation out to the user using &mut self

RalfJ (Dec 12 2018 at 13:39, on Zulip):

and it's just as compositional

RalfJ (Dec 12 2018 at 13:40, on Zulip):

if I want to create a type that takes ownership of a future, and pins it, that cannot be done at zero-cost

your type then needs to expose that it requires pinning, just like existing code exposes that it requires mutation

gnzlbg (Dec 12 2018 at 13:41, on Zulip):

is it possible to express that? I have literally 1 day of experience with async / futures, on Discord nobody suggested that it was doable.

RalfJ (Dec 12 2018 at 13:43, on Zulip):

you need "recursive" or "structural" pinning, which (bad for you but not for your users) is not very ergonomic to do currently. and then your methods take Pin<&mut self>, propagating the requirements outwards.

RalfJ (Dec 12 2018 at 13:43, on Zulip):

see https://docs.rs/pin-utils/0.1.0-alpha.3/pin_utils/macro.unsafe_pinned.html

gnzlbg (Dec 12 2018 at 13:55, on Zulip):

@RalfJ but then my users still need to pin my type right?

gnzlbg (Dec 12 2018 at 13:59, on Zulip):

yes they do :/ its unclear to me whether the difference between pinning my type or pinning the future matters

gnzlbg (Dec 12 2018 at 14:03, on Zulip):

Do you know how to implement Futures for which LocalWaker makes no sense?

RalfJ (Dec 12 2018 at 14:11, on Zulip):

@RalfJ but then my users still need to pin my type right?

of course. if you mutate anything, you propagate the &mut outwards. if you access pinned data that you cann promise yourself is pinned (because you boxed it or so), you propagate the Pin outwards

RalfJ (Dec 12 2018 at 14:11, on Zulip):

you cannot magically disappear the fact that data needs to be pinned

RalfJ (Dec 12 2018 at 14:12, on Zulip):

Do you know how to implement Futures for which LocalWaker makes no sense?

I'm afraid not -- I don't know anything about futures.
I was just commenting on the pinning aspect as that's something I studied in some depth :)

gnzlbg (Dec 12 2018 at 14:13, on Zulip):

it took a bit to grok the most important pieces of pinning, but I don't think i groked them all

RalfJ (Dec 12 2018 at 14:13, on Zulip):

it is quite an interesting abstraction

gnzlbg (Dec 12 2018 at 14:14, on Zulip):

I ended up wishing !Move a couple of times while playing with it, but now I think its more flexible than !Move

gnzlbg (Dec 12 2018 at 14:15, on Zulip):

it lets you make objects any type !Move when you need it

gnzlbg (Dec 12 2018 at 14:17, on Zulip):

anyways, now I still need to figure out how to make the futures actually work with other people executors expecting a LocalWaker that does something

Jake Goulding (Dec 12 2018 at 15:13, on Zulip):

Also, remember that "zero-cost" means "the abstraction has no more runtime overhead than the non-abstracted version"

Jake Goulding (Dec 12 2018 at 15:14, on Zulip):

But not "I don't like the abstraction" or "it's not a very abstract abstraction" or "it's a leaky abstraction"

gnzlbg (Dec 12 2018 at 16:26, on Zulip):

The non-abstraction version does not require spawning threads nor allocating memory.

gnzlbg (Dec 12 2018 at 16:26, on Zulip):

With respect to LocalWaker, the non-abstracted version works, the abstracted version "doesn't"

gnzlbg (Dec 12 2018 at 16:27, on Zulip):

One can make it work by not using the abstraction how it is intended to be used.

gnzlbg (Dec 12 2018 at 16:27, on Zulip):

But then one might arguable be better off with a different abstraction

gnzlbg (Dec 12 2018 at 16:28, on Zulip):

Sadly, that's not allowed, because Rust async fn requires using Future

Zoxc (Dec 13 2018 at 02:06, on Zulip):

I plan to avoid the Future trait with #[async] proc macros, which was originally the plan for them

gnzlbg (Dec 13 2018 at 11:38, on Zulip):

@Zoxc does that mean that I can use async fn that return -> impl MyFutureTrait ?

Zoxc (Dec 13 2018 at 15:51, on Zulip):

It would be #[async] fn, but yes

Last update: Nov 20 2019 at 11:30UTC