Calling methods on generic parameters of const fns by oli-obk · Pull Request #2632 · rust-lang/rfcs (original) (raw)

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Conversation230 Commits37 Checks0 Files changed

Conversation

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters

[ Show hidden characters]({{ revealButtonHref }})

oli-obk

TLDR: Allow

const fn add<T: Add>(a: T, b: T) -> T::Output { a + b }

and

pub struct Foo<T: Trait>(T); impl<T: ?const Trait> Foo { fn new(t: T) -> Self { // not calling methods on t, so we opt out of requiring // <T as Trait> to have const methods via ?const Self(t) } }

cc @Centril @varkor @RalfJung @eddyb

This RFC has gone through an extensive pre-RFC phase in rust-lang/const-eval#8

Rendered

Triage: pFCP comment: #2632 (comment)

varkor, cramertj, ebkalderon, clarfonthey, gnzlbg, solson, Centril, japaric, Thomasdezeeuw, taiki-e, and 79 more reacted with thumbs up emoji RalfJung, cramertj, mark-i-m, clarfonthey, 00imvj00, gnzlbg, solson, Centril, japaric, taiki-e, and 23 more reacted with hooray emoji clarfonthey, gnzlbg, solson, Centril, japaric, burdges, wesleywiser, jieyouxu, darksv, ohsayan, and 12 more reacted with heart emoji kennytm, mental32, peter-lyons-kehl, lvyitian, and Creative-Difficulty reacted with eyes emoji

@varkor

One alternative syntax design that is not mentioned here is the question of const impl versus impl const.

There are strong arguments that const impl is the more consistent syntax, as it is consistent both with the existing practice of prefixing modifiers to impl (default impl, unsafe impl, etc.) and prefixing const to keywords to indicate const variants (e.g. const fn [and the hypothetical const trait]).

Conversely, as far as I'm aware, impl const is not consistent with any existing syntax in the language or this RFC.


(I don't like to start the discussion with syntax bikeshedding, but as mentioned in the original post, this RFC has already ungone significant design discussion and I'm satisfied it's close to the optimal conservative design.)

l4l, rpjohnst, mark-i-m, ssokolow, matthieu-m, DDOtten, huhlig, gnzlbg, maksimsco, taiki-e, and 19 more reacted with thumbs up emoji DDOtten, huhlig, gnzlbg, kestred, izik1, oilaba, and lvyitian reacted with heart emoji

cramertj

cramertj

fbstj

@Centril Centril added T-lang

Relevant to the language team, which will review and decide on the RFC.

A-syntax

Syntax related proposals & ideas

A-typesystem

Type system related proposals & ideas

A-const-eval

Proposals relating to compile time evaluation (CTFE).

labels

Feb 5, 2019

@rpjohnst

How do we want -> impl Trait and arg: dyn Trait to interact with const fn? If you must specify -> impl const Trait, does it also make sense to require arg: dyn const Trait? Both cases feel more existential-y and thus less tied to the function's type parameters, so I kind of lean that way for consistency.

@varkor

I imagine it makes most sense to use the same (syntactic) rules for impl Trait and dyn Trait as for parameter bounds: that is, in const fn, an impl Trait actually means impl const Trait/const impl Trait (and similarly for dyn) and impl ?const Trait/?const impl Trait allows opting-out of constness.

@mark-i-m

This comment has been minimized.

@fbstj @oli-obk

Co-Authored-By: oli-obk github35764891676564198441@oli-obk.de

@ExpHP

I'm not sure why const Drop must be recursive on fields. In my mental model, the body of drop doesn't have calls to the fields' drop impls inserted, but rather, it's the role of drop glue to piece them all together:

{ let local = get_thing();

// Implicitly inserted
// (each one is individually omitted if that type
//  does not explicitly implement Drop)
Drop::drop(&mut local);
Drop::drop(&mut local.field_1);
Drop::drop(&mut local.field_2);

}

Requiring const Drop on fields increases churn when library A cannot write const Drop yet due to a non-const Drop in library B. (so to use A in a const context, changes now need to be made to both library B and A in that order, instead of just B).


(one could argue that allowing impl const Drop in library A when a field is non-const Drop could lead to misleading documentation; but another thread of discussion on this PR seems to be arriving at the conclusion that we additionally require an auto-trait like ConstDrop, which partially mitigates this concern)

@oli-obk

I don’t think this has been mentioned before, but putting const before impl would be more consistent with other modifiers like unsafe and pub if we decided to do that.

It has been mentioned before. This was even the original syntax. Reasoning for the change can be found at rust-lang/const-eval#8 (comment)

cc @scottmcm for consistency (not in semantics, but user expectations) I have slowly come back around to const impl Trait for Type being the best syntax.

@ExpHP

Ultimately the location of const is really nothing but the color of the bikeshed. impl const may be different from the other things, but it is not that hard to remember this "exception" when you have things like T: ?const Trait.

Conceptually, the keyword is attached to the trait. I.e. it's not an impl const of a Trait, but rather an impl of a const Trait.

fstirlitz, oli-obk, Lokathor, scottmcm, Coder-256, CAD97, demurgos, RagibHasin, Zenithsiz, o-x-e-y, and 2 more reacted with thumbs up emoji

@oli-obk

@scottmcm

Conversely, as far as I'm aware, impl const is not consistent with any existing syntax in the language or this RFC.

I think that's looking at it from the wrong perspective.

It's not that it's (impl const) Trait, but that it's impl (const Trait), the same as you can impl (dyn Trait). And that's consistent with something like struct Foo<T: const Default>(T); or similar.

@mark-i-m

But as far as I can tell, the Constness is not a property of the Trait, but of the impl, which is not the same for dyn, right?

@Centril

It's not that it's (impl const) Trait, but that it's impl (const Trait), the same as you can impl (dyn Trait). And that's consistent with something like struct Foo<T: const Default>(T); or similar.

I agree with this in particular when viewed in light of effect systems. Moreover, impl const Trait also has composability benefits, e.g. arg: impl Add + ?const Clone + const Debug vs. arg: const impl Add + Cone + Debug are probably not the same semantically.

But as far as I can tell, the Constness is not a property of the Trait, but of the impl, which is not the same for dyn, right?

Traits can be seen as logical requirements and implementations are proofs that those requirements are satisfied. In that light, e.g. T: const Foo can be seen as a constraint that T satisfies const Foo and impl const Foo for MyT is a witness for that.

@oli-obk

@oli-obk

Centril

@Centril @oli-obk

Co-Authored-By: oli-obk github35764891676564198441@oli-obk.de

@luser luser mentioned this pull request

Mar 23, 2021

@RalfJung

A problem came up with the original plan, described in rust-lang/rust#83452 and on Zulip: under some conditions, we currently accept const fn on stable that have trait bounds in scope; if we say that all trait bounds on const fn are implicitly const Trait (as proposed in this RFC), that would be a breaking change for callers of these functions.

@nikomatsakis

Should we try to revert that support, @RalfJung? I think it was accidental.

@RalfJung

@nikomatsakis That might be good if we want to keep our options open -- but @oli-obk has the overview here, I'm just reporting what came up elsewhere. I don't currently have the bandwidth to work on this.

I personally am leaning towards a different design than the one proposed in the RFC, one where there is no implicit "callable in const context" -- that would be more consistent with &dyn Trait and fn() which can already be created in const. That design doesn't mind this accident. But this is a discussion for the RFC.

@jhpratt

What's the status of the RFC? FCP was proposed over two years ago, and is currently blocked by @withoutboats. I will note that boats is an alumnus of the lang team. While I am not dismissing their concerns outright, they have had zero public activity on GitHub in over six months. At this point, is it worth cancelling and restarting the checkboxes? This would permit the current lang team to register the same concerns if they still exist.

cc lang team: @joshtriplett @nikomatsakis @cramertj @pnkfelix @scottmcm

@burdges

I'd assume experimentation going on based upon #2632 (comment) ? If I read correctly, there was a rather extensive discussion around boats' third issue, which prompted a desire to experiment.

@jhpratt

Yeah, the main reason I asked is because said experimentation had taken place and been on nightly for a while now.

@oli-obk

There are currently still a few things that make the experimental feature useless in practice. We don't have the implementation capacity right now to work on it, but I do plan on more things happening here this year.

@nikomatsakis

I talked to @oli-obk today and we agreed that we will close this RFC for now. The content is likely still desired but we want to do more experimentation and will re-open when the design seems closer to settled.

@pubfnbar

IIUC, this RFC would make trait-associated constants unusable in const contexts if the trait bound is not declared const (possibly implicitly). I think this would be a design mistake - an unnecessary reduction of usability. Conceptually, associated constants should be usable in const contexts always, irrespective of the constness of the trait implementation or the trait bound (setting aside for now the implementation difficulties of proving the equality of different constant expressions). Here's an example that wouldn't compile given the current design:

trait Foo { fn foo(value: u8) -> u8; }

trait Bar { const BAR: u8;

fn bar(value: u8) -> u8;

}

const fn baz() -> u8 where T: Foo + ?const Bar { T::foo(T::BAR) // error: <T as Bar> used in a const context }

Reviewers

@fbstj fbstj fbstj left review comments

@comex comex comex left review comments

@pnkfelix pnkfelix pnkfelix left review comments

@RalfJung RalfJung RalfJung left review comments

@kpp kpp kpp left review comments

@Centril Centril Centril left review comments

@gnzlbg gnzlbg gnzlbg left review comments

@ExpHP ExpHP ExpHP left review comments

@cramertj cramertj cramertj left review comments

@CAD97 CAD97 CAD97 left review comments

@jD91mZM2 jD91mZM2 jD91mZM2 left review comments

@RustyYato RustyYato RustyYato left review comments

@eira-fransham eira-fransham eira-fransham left review comments

Labels

A-const-eval

Proposals relating to compile time evaluation (CTFE).

A-effects

Effects related proposals & ideas

A-syntax

Syntax related proposals & ideas

A-typesystem

Type system related proposals & ideas

T-lang

Relevant to the language team, which will review and decide on the RFC.