Stream: general

Topic: rustc_args_required_const in traits


Luca Barbato (May 25 2019 at 10:56, on Zulip):

I'm trying to implement an intrinsic that takes a literal value as argument:

    impl VectorCtf for vector_signed_int {
        type Result = vector_float;
        #[inline]
        #[target_feature(enable = "altivec")]
        #[rustc_args_required_const(1)]
        unsafe fn vec_ctf(self, b: i32) -> Self::Result {
            vec_vcfsx(self, b)
        }
    }

This leads to:

error: argument 2 is required to be a constant
   --> crates/core_arch/src/powerpc/altivec.rs:447:13
    |
447 |             vec_vcfsx(self, b)
    |             ^^^^^^^^^^^^^^^^^^

Am I doing something silly or there is a limitation to be addressed in rustc?

Luca Barbato (May 25 2019 at 11:02, on Zulip):

simpler testcase here

Luca Barbato (May 25 2019 at 11:04, on Zulip):

even calling function from function fails https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=f2a2a96e4d0019048c6661668a782088

oli (May 25 2019 at 15:24, on Zulip):

I don't think these were ever intended to be used this way. To be honest that feature is a total hack that I don't know how it ever got exposed to users without an RFC

oli (May 25 2019 at 15:25, on Zulip):

I don't think this will get addressed any time soon (if ever). Const generics should give us a much cleaner way to use these

RalfJ (May 25 2019 at 15:30, on Zulip):

AFAIK, rustc attributes are generally expected to be used only inside rustc

RalfJ (May 25 2019 at 15:30, on Zulip):

we can't stop you (on nightly) from using them yourself, but dont expect documentation, dont expect any kind of stability, and dont expect them to work for anything beyond what rustc needed them for

oli (May 25 2019 at 15:50, on Zulip):

If I understand it correctly the above is actually for "inside rustc" (isn't core_arch related to core::arch?)

oli (May 25 2019 at 15:51, on Zulip):

I want a time machine and just implement a crappy version of const generics (that can't handle being used in array lengths) and just allows the intrinsic use case

centril (May 26 2019 at 00:29, on Zulip):

To be honest that feature is a total hack that I don't know how it ever got exposed to users without an RFC

It was never approved by the language team; the libs team inappropriately approved it. That's how :slight_smile:

centril (May 26 2019 at 00:29, on Zulip):

I would have never approved it had I been on the language team at that point

centril (May 26 2019 at 00:29, on Zulip):

and yeah, it's a total hack; if we want to make a sane version out of it you'd need fn foo(const N: usize)

centril (May 26 2019 at 00:30, on Zulip):

which is basically "const generics but not an implicit argument"

RalfJ (May 26 2019 at 07:53, on Zulip):

oh, "exposed to users" not as in "users can use this attribute" but "users can use methods that have that attribute"... yeah that's sad :(

Luca Barbato (May 26 2019 at 10:29, on Zulip):

well, the alternative is to have a first class literal-arg.

Luca Barbato (May 26 2019 at 10:30, on Zulip):

And we need it to expose intrinsics

Luca Barbato (May 26 2019 at 10:31, on Zulip):

(and yes it is used in what will be core::arch::altivec :P)

oli (May 26 2019 at 10:52, on Zulip):

what's the stabilization timeline on core::arch::altivec?

oli (May 26 2019 at 10:53, on Zulip):

like can this just wait on const generics?

Luca Barbato (May 26 2019 at 11:28, on Zulip):

I can postpone those instructions

Luca Barbato (May 26 2019 at 11:28, on Zulip):

what's the const generics timeline?

oli (May 26 2019 at 12:31, on Zulip):

From current events I'd guess this year?

gnzlbg (May 28 2019 at 09:25, on Zulip):

@oli @RalfJ @centril this was required for x86 SIMD on stable, so... without this "hack", we couldn't have stabilized SIMD last year

gnzlbg (May 28 2019 at 09:25, on Zulip):

also const-generics wouldn't be enoug

oli (May 28 2019 at 09:25, on Zulip):

@gnzlbg I'm not complaining about the feature, I'm complaining about the lack of a story of how to get rid of the hack and have an actual feature that users can use, too

oli (May 28 2019 at 09:26, on Zulip):

also const-generics wouldn't be enoug

please elaborate!

gnzlbg (May 28 2019 at 09:26, on Zulip):

the lang team was consulted, and the recommendation was to actually go with this attribute, because the features required only make sense designing after const-generics has been fully implemented and stabilized, so the timeline for what's required would be "maybe start thinking about more const generics feature after const generics is stable"

gnzlbg (May 28 2019 at 09:26, on Zulip):

@oli these would need const function arguments

oli (May 28 2019 at 09:26, on Zulip):

I don't understand, what's the difference?

gnzlbg (May 28 2019 at 09:27, on Zulip):

the same as between impl Trait in argument position and generics

gnzlbg (May 28 2019 at 09:27, on Zulip):

e.g. you can't foo::<3>() for example

oli (May 28 2019 at 09:27, on Zulip):

you can foo::<{3}>(), right?

oli (May 28 2019 at 09:28, on Zulip):

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=587dde74a85e3762b9a03928e39d8547

oli (May 28 2019 at 09:29, on Zulip):

jup, that works

oli (May 28 2019 at 09:30, on Zulip):

oh, wait, now I understand

oli (May 28 2019 at 09:30, on Zulip):

you mean if we get argument position const generics, we can't specify those in generic brackets?

oli (May 28 2019 at 09:32, on Zulip):

I mean this all seems fairly reasonable, and I want it. But the lack of an RFC for a feature that is user visible and basically (due to backwards incompat rules) insta-stable forever, makes me uncomfortable.

oli (May 28 2019 at 09:33, on Zulip):

I don't see any problem with the current feature, but extending it so the arguments appear as constants inside the function is dangerous

oli (May 28 2019 at 09:34, on Zulip):

const generics is implemented far enough for an RFC to be written for argument position const generics, so I suggest to go down that route

gnzlbg (May 28 2019 at 09:35, on Zulip):

i mean that we need fn foo(x: const usize) which AFAICT needs supports for existential const generics

gnzlbg (May 28 2019 at 09:36, on Zulip):

the lang team argued _back then_ that it made little sense to design existential const types when const generics aren't even a thing

gnzlbg (May 28 2019 at 09:38, on Zulip):

if that changed, an RFC for that would be great

gnzlbg (May 28 2019 at 09:39, on Zulip):

I don't see any problem with the current feature, but extending it so the arguments appear as constants inside the function is dangerous

I don't think anybody is requesting that. A user misunderstood what the feature should do, and filled an issue, but that has been clarified, and the issue can be closed.

gnzlbg (May 28 2019 at 09:40, on Zulip):

const generics is implemented far enough for an RFC to be written for argument position const generics, so I suggest to go down that route

I suppose that an RFC for existential const types can be written now, e.g., exploring fn foo(x: const usize);, fn bar() -> const usize;, etc. and proposing some feature that mixes well with the language

oli (May 28 2019 at 09:41, on Zulip):

how would argument position constants be different from const generics?

oli (May 28 2019 at 09:41, on Zulip):

arent's arguments universal (that's what I got from impl Trait at least)

oli (May 28 2019 at 09:42, on Zulip):

I understand that return position constants are a different story, but that doesn't need to be solved right now

gnzlbg (May 28 2019 at 09:42, on Zulip):

IIRC impl Trait is always an existential type, but in argument position it is isomorphic to a similar universally quantified type

oli (May 28 2019 at 09:42, on Zulip):

ah, yea, that argument

gnzlbg (May 28 2019 at 09:42, on Zulip):

i think @varkor wrote something showing that

oli (May 28 2019 at 09:42, on Zulip):

I don't like it :P

oli (May 28 2019 at 09:42, on Zulip):

I held a presentation about that ;)

gnzlbg (May 28 2019 at 09:43, on Zulip):

in any case, maybe now it is the time for that feature, but stable SIMD shipped in Februrary last year, and this attribute was added like 6 months before, so back then, this attribute was the best solution we had

gnzlbg (May 28 2019 at 09:44, on Zulip):

it was also clear that this attribute should just error if an argument isn't const, and that's it. It was never intended to be "const generic arguments" or something like that, just something that allows us to change these APIs to use "const generic arguments" in a backward compatible way once those become available

gnzlbg (May 28 2019 at 09:45, on Zulip):

@oli i think I wrote an RFC about const generic arguments back then, you might want to scavenge it ;)

oli (May 28 2019 at 09:45, on Zulip):

:+1: Still could use some documentation love in https://github.com/rust-lang/rust/blob/e70d5386d7abcf39adf54feb43a655c4f8a1bcb6/src/libsyntax/feature_gate.rs#L1465

oli (May 28 2019 at 09:45, on Zulip):

all it says there is "will never be stable" :D

oli (May 28 2019 at 09:46, on Zulip):

heh, I already have a const RFC open, one thing at a time

gnzlbg (May 28 2019 at 09:47, on Zulip):

that should be enough for those that need to use it :P in this case it wasn't, so i'm sorry that @Luca Barbato wasted time on this, but I don't know if a comment there would have helped much

gnzlbg (May 28 2019 at 09:47, on Zulip):

we don't want to encourage anybody to use this, this is for libstd consumption only

gnzlbg (May 28 2019 at 09:47, on Zulip):

@oli i thought the const RFC was already merged ?

gnzlbg (May 28 2019 at 09:48, on Zulip):

w/oboats one i mean

oli (May 28 2019 at 09:48, on Zulip):

not sure which one you mean, but I'm talking about https://github.com/rust-lang/rfcs/pull/2632

gnzlbg (May 28 2019 at 09:51, on Zulip):

ah no, i meant this one: https://github.com/rust-lang/rfcs/pull/2000

centril (May 28 2019 at 09:51, on Zulip):

this has nothing to do with "existential consts"

oli (May 28 2019 at 09:51, on Zulip):

we don't want to encourage anybody to use this, this is for libstd consumption only

yea, sorry about overreacting. It's just not been an easy feature to work with when changing things in the compiler's const qualifier.

centril (May 28 2019 at 09:52, on Zulip):

the only difference between fn foo(const A: B) and fn foo<const A: B>() is that the latter allows for value inference whereas the latter doesn't

gnzlbg (May 28 2019 at 09:53, on Zulip):

is the const B in the first one part of the function generic parameters ?

centril (May 28 2019 at 09:53, on Zulip):

to de-hack this we will therefore need to introduce fn foo(const A: B)

centril (May 28 2019 at 09:54, on Zulip):

@gnzlbg I would suggest not thinking of this in terms of "generic parameters"

centril (May 28 2019 at 09:54, on Zulip):

we have implicit arguments and explicit arguments

centril (May 28 2019 at 09:54, on Zulip):

the things in <...> are implicit and the things in (...) are explicit

gnzlbg (May 28 2019 at 09:54, on Zulip):

Would fn foo<const A: B>(const A: B)work ?

centril (May 28 2019 at 09:55, on Zulip):

@gnzlbg that would be like saying fn foo(x: u8, x: u8)

centril (May 28 2019 at 09:55, on Zulip):

i.e. you are introducing A twice

gnzlbg (May 28 2019 at 09:56, on Zulip):

Maybe fn foo<const A: usize>(x: A)

centril (May 28 2019 at 09:56, on Zulip):

A is not a type so x: A is not well-formed

centril (May 28 2019 at 09:57, on Zulip):

The smart thing to do here would have been to introduce fn foo<const A: B>() for these arguments but not put in place the inference

gnzlbg (May 28 2019 at 09:57, on Zulip):

so one has to pick between fn foo<const A: usize>(); foo::<3>(), and fn foo(const x: usize); foo(3), but foo::<3>(3); is never a thing

centril (May 28 2019 at 09:57, on Zulip):

so that you have to specify as foo::<3>()

centril (May 28 2019 at 09:58, on Zulip):

@gnzlbg well unless you have fn foo<const A: usize>(const B: usize)

centril (May 28 2019 at 09:58, on Zulip):

there's no link between the 3 in the <..> and the 3 in the (..)

gnzlbg (May 28 2019 at 09:59, on Zulip):

That makes A and B different - my point was about whether they can be the same

gnzlbg (May 28 2019 at 09:59, on Zulip):

like, say I want to create a fn()->() to a fn foo(const A: usize) where A==3

gnzlbg (May 28 2019 at 10:00, on Zulip):

let ptr: fn(3)->() = foo::<3>(); would not work

oli (May 28 2019 at 10:01, on Zulip):

let ptr: fn() = foo::<{3}>(); should work out of the box I think

centril (May 28 2019 at 10:01, on Zulip):

@gnzlbg we don't have partial application

oli (May 28 2019 at 10:01, on Zulip):

but just like with impl trait in argument position, that won't work for const in arugment position

centril (May 28 2019 at 10:01, on Zulip):

which is what you'd need for htis

gnzlbg (May 28 2019 at 10:01, on Zulip):

@oli if foo<const A: usize>(); yes, but if foo(const A: usize); then only if there is some link between <{3}> and (...)

oli (May 28 2019 at 10:01, on Zulip):

@centril we do for generics

oli (May 28 2019 at 10:01, on Zulip):

ah yes

centril (May 28 2019 at 10:02, on Zulip):

@oli no that's not partial application

oli (May 28 2019 at 10:02, on Zulip):

if we find a solution for impl trait in arg position we have a solution for const in arg position

centril (May 28 2019 at 10:02, on Zulip):

if you supply 1 argument to the <...> you must provide all

oli (May 28 2019 at 10:02, on Zulip):

it's exactly the same problem

gnzlbg (May 28 2019 at 10:02, on Zulip):

yes

centril (May 28 2019 at 10:03, on Zulip):

The difference between <...> and (...) is well studied in type theory really

centril (May 28 2019 at 10:03, on Zulip):

and the only difference is one of type inference

gnzlbg (May 28 2019 at 10:03, on Zulip):

so given that fn foo<const A: usize>() already exists, the question is how to extend that to fn bar(const A: usize), such that one can still specify the A parameter for bar

gnzlbg (May 28 2019 at 10:04, on Zulip):

or to decide that we don't want to support that at all

gnzlbg (May 28 2019 at 10:04, on Zulip):

we currently don't support that for impl Trait

centril (May 28 2019 at 10:04, on Zulip):

@gnzlbg we already have fn bar(const A: usize) in the type system

centril (May 28 2019 at 10:04, on Zulip):

just with weird syntax

centril (May 28 2019 at 10:05, on Zulip):

and you can already specify the A parameter for bar

gnzlbg (May 28 2019 at 10:05, on Zulip):

that's why i said that this is a given

varkor (May 28 2019 at 10:05, on Zulip):

this isn't related to impl Trait at all

gnzlbg (May 28 2019 at 10:05, on Zulip):

@centril how would you pass the A parameter for bar ?

centril (May 28 2019 at 10:05, on Zulip):

@gnzlbg bar(3)

gnzlbg (May 28 2019 at 10:06, on Zulip):

how do you take a function pointer to that ?

varkor (May 28 2019 at 10:06, on Zulip):

I think the only difference is whether parameters can be inferred or not, as @centril says

varkor (May 28 2019 at 10:06, on Zulip):

although if you need pointers too...

gnzlbg (May 28 2019 at 10:06, on Zulip):

@centril bar(3) passes the parameter to bar, and calls it

centril (May 28 2019 at 10:06, on Zulip):

@gnzlbg let x: fn(const A: usize) = bar;

gnzlbg (May 28 2019 at 10:06, on Zulip):

that's different from just passing the parameter to bar

centril (May 28 2019 at 10:07, on Zulip):

as I said, we don't have partial application

varkor (May 28 2019 at 10:07, on Zulip):

do you need a pointer to a function with a specific value?

centril (May 28 2019 at 10:07, on Zulip):

@varkor I think that's what they want

gnzlbg (May 28 2019 at 10:08, on Zulip):

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=28eae3d99eef208f35b54448607c792a

gnzlbg (May 28 2019 at 10:08, on Zulip):
fn foo<T>(x: T) -> T { x }

fn bar() {
    let _ptr: fn(i32) -> i32 = foo::<i32>;
}
gnzlbg (May 28 2019 at 10:08, on Zulip):

that works today

centril (May 28 2019 at 10:08, on Zulip):

@gnzlbg yes because that's in the <...>

kennytm (May 28 2019 at 10:09, on Zulip):

you shouldn't be allowed to take a function pointer of fn(const)

gnzlbg (May 28 2019 at 10:09, on Zulip):

exactly, and my question is, should (...) forbid you from doing that ?

centril (May 28 2019 at 10:09, on Zulip):

if you write fn foo(x: usize) we don't allow you to partially apply foo either

gnzlbg (May 28 2019 at 10:09, on Zulip):

that's a big different between ITAP and generics

centril (May 28 2019 at 10:09, on Zulip):

ITAP?

gnzlbg (May 28 2019 at 10:09, on Zulip):

impl trait in argument position

varkor (May 28 2019 at 10:09, on Zulip):

APIT

kennytm (May 28 2019 at 10:09, on Zulip):

APIT :upside_down:

varkor (May 28 2019 at 10:09, on Zulip):

:P

centril (May 28 2019 at 10:09, on Zulip):

@varkor damn you! :P

centril (May 28 2019 at 10:10, on Zulip):

you don't need the ability to partially apply explicit const generic parameters to have #[rustc_whatever_it_was_named] be removed

gnzlbg (May 28 2019 at 10:13, on Zulip):

that's correct

gnzlbg (May 28 2019 at 10:13, on Zulip):

an RFC for adding a feature to allow #[rustc_whatever] to be removed might need to argue that this is not required, desired, a future compatible extension, etc.

centril (May 28 2019 at 10:14, on Zulip):

maybe; it is not expected by any type theory I know of

gnzlbg (May 28 2019 at 10:15, on Zulip):

https://internals.rust-lang.org/t/pre-rfc-const-function-arguments/6709

gnzlbg (May 28 2019 at 10:15, on Zulip):

that one argues that this is not supported

kennytm (May 28 2019 at 10:16, on Zulip):

#[rustc_args_required_const] already forbids taking a function pointer ("this function can only be invoked directly, not through a function pointer"). i don't see any controversy disallowing fn(const) pointers

gnzlbg (May 28 2019 at 10:18, on Zulip):

An RFC today would probably need to discuss fn foo() -> const usize as well

gnzlbg (May 28 2019 at 10:18, on Zulip):

At least say that this is out-of-scope for the RFC

varkor (May 28 2019 at 10:19, on Zulip):

why would you want to return a const?

varkor (May 28 2019 at 10:19, on Zulip):

why not just use const X: usize = { .. };?

centril (May 28 2019 at 10:19, on Zulip):

or rather to rephrase: why do you want to require that the return value be a compile time value?

varkor (May 28 2019 at 10:19, on Zulip):

(similarly, you cannot return lifetimes — so the generic parameters a function takes as input doesn't have to line up with the output)

centril (May 28 2019 at 10:20, on Zulip):

if you want to have the possibility, use const fn

kennytm (May 28 2019 at 10:20, on Zulip):

are we talking about fn x(const y: usize) (const applied to arg) or fn x(y: const usize) (const applied to type)

centril (May 28 2019 at 10:20, on Zulip):

@kennytm they are functionally equivalent, no?

gnzlbg (May 28 2019 at 10:20, on Zulip):

@varkor >why would you want to return a const?

pub fn init_buffer(const X: usize) -> (*ptr, const usize) {
      const MIN_BUFF_SIZE: usize = ...const fn(x)...;
      ...alloc...
     (ptr, MIN_BUFF_SIZE)
}

maybe

centril (May 28 2019 at 10:21, on Zulip):

unless you try to do fn foo(x: (const u8, String))

kennytm (May 28 2019 at 10:21, on Zulip):

@centril the implication of latter is more powerful :upside_down:

centril (May 28 2019 at 10:22, on Zulip):

@kennytm yea it is

centril (May 28 2019 at 10:22, on Zulip):

@varkor and I discussed it a bunch

centril (May 28 2019 at 10:22, on Zulip):

we got into some category theory and talked about functors iirc

kennytm (May 28 2019 at 10:23, on Zulip):

meanwhile the former is just a nicer form of #[rustc_args_required_const]

centril (May 28 2019 at 10:24, on Zulip):

@kennytm one might imagine fn foo<T: const usize>(...) and fn foo<T: usize>(...) converesely

centril (May 28 2019 at 10:24, on Zulip):

dependent types :rocket:

RalfJ (May 28 2019 at 10:28, on Zulip):

IIRC impl Trait is always an existential type, but in argument position it is isomorphic to a similar universally quantified type

that's actually quite nice, somehow this had not occurred to me even though I otherwise use that isomorphism all the time :)

RalfJ (May 28 2019 at 10:29, on Zulip):

though the question remains... and now I have a deja-vu, I feel I discussed this at some point but not sure in which context... when you start nesting things, like fn foo(fn(impl Trait) -> impl Trait), the "proper" thing you'd expect is that the existentials are like fn foo(fn(exists T: Trait, T) -> (exists T: Trait, T)).

RalfJ (May 28 2019 at 10:30, on Zulip):

but I guess in Rust it translates to fn foo(exists (T1: Trait) (T2: Trait), fn(T1) -> T2). which is not the same.

centril (May 28 2019 at 10:31, on Zulip):

It should be equivalent to (using the isomorphism): exists A: Trait. forall B: Trait. fn foo(fn(A) -> B)

RalfJ (May 28 2019 at 10:33, on Zulip):

no

RalfJ (May 28 2019 at 10:33, on Zulip):

it is equivalent to fn foo(forall A: Trait, fn(A) -> (exists B: Trait, B))

centril (May 28 2019 at 10:33, on Zulip):

actually... it is not clear what this means because of function pointers

RalfJ (May 28 2019 at 10:33, on Zulip):

which is not representable in Rust

RalfJ (May 28 2019 at 10:34, on Zulip):

though if we think of the Fn trait instead, if we had higher-ranked trait bounds for types, we could write

fn foo<F: for <T: Trait> Fn(T) -> impl U>(f: F)

not sure if the U part would work though^^

centril (May 28 2019 at 10:38, on Zulip):

where did you get the U from?

centril (May 28 2019 at 10:39, on Zulip):

(this is probably a different thread tho)

gnzlbg (May 28 2019 at 10:58, on Zulip):

@centril would you be willing to champion an RFC of the form of the internal one, for adding const function arguments support (only, no return type, no way to specify types via <...> for (...) arguments, etc. ?

centril (May 28 2019 at 10:59, on Zulip):

@gnzlbg champion as in write it up?

gnzlbg (May 28 2019 at 11:00, on Zulip):

no, champion as in "help" pushing it through the process. That is, I'll update and improve the internals one, send a github link to you, maybe @varkor and @kennytm for initial feedback, proof reading, etc. and then once that looks good, submit it as a PR to the RFC repo

gnzlbg (May 28 2019 at 11:00, on Zulip):

but i don't think we should do any of that if there is no interest in tackling this issue in the next months by the lang team

centril (May 28 2019 at 11:01, on Zulip):

There probably isn't -- I think we should see to RFC 2000 (const generics) first before doing any extensions -- also, it is the "maturity" year

centril (May 28 2019 at 11:01, on Zulip):

I've almost stopped all new language design

gnzlbg (May 28 2019 at 11:01, on Zulip):

so by champion i mean, "facilitator" (is that the new term?) - pinging the appropriate team, making sure that either there is progress, or that it is clear why there isn't, so that something can be done about it (or just postpone)

gnzlbg (May 28 2019 at 11:02, on Zulip):

so, this is precisely why #[rustc_whatever_const_arg] exists

centril (May 28 2019 at 11:03, on Zulip):

you could have done other hacks which would have relied on <..> instead of (...)

gnzlbg (May 28 2019 at 11:03, on Zulip):

that wouldn't have allowed us to match the C intrinsics

centril (May 28 2019 at 11:03, on Zulip):

e.g. always emit "ambiguous type"

gnzlbg (May 28 2019 at 11:03, on Zulip):

being able to call foo(...) was a requirement, instead of foo::<{ ... }>(...)

centril (May 28 2019 at 11:04, on Zulip):

@gnzlbg why is that a requirement?

gnzlbg (May 28 2019 at 11:04, on Zulip):

we RFC'ed that the C intrinsics should look like.. well.. C

gnzlbg (May 28 2019 at 11:04, on Zulip):

C does not have "generics", turbofish, etc.

centril (May 28 2019 at 11:05, on Zulip):

seems unimportant to me that you should be able to call them as (...) instead of <...> if that complicates the type theory

gnzlbg (May 28 2019 at 11:05, on Zulip):

it doesn't have const generics, overloading, etc. either - all C compilers make these builtins

centril (May 28 2019 at 11:05, on Zulip):

yeah, not important

gnzlbg (May 28 2019 at 11:05, on Zulip):

i didn't rfc'ed that

gnzlbg (May 28 2019 at 11:05, on Zulip):

i was just working within the rfc'ed constraints, and that was a constrait: we don't change the API of the intrinsics

centril (May 28 2019 at 11:06, on Zulip):

I think the thing one should care about is discoverability and having the actual hardware capabilities

gnzlbg (May 28 2019 at 11:06, on Zulip):

there is zero Rust documentation about the 5000 intrinsics that we expose today

centril (May 28 2019 at 11:06, on Zulip):

the simd intrinsics are not ergonomic in any case

gnzlbg (May 28 2019 at 11:06, on Zulip):

so being able to reuse the C documentation, was considered very valuable

gnzlbg (May 28 2019 at 11:07, on Zulip):

IIRC, that was the main reason, the second main reason was not doing any new API design, because if we have to do API design for the 10000 intrinsics that are in the list, that would take forever

gnzlbg (May 28 2019 at 11:07, on Zulip):

and each new API design would need to be reviewed, RFC, manually verified, etc.

centril (May 28 2019 at 11:07, on Zulip):

I think it would be fairly easy to communicate that the sole <const: A: B> parameter is the one that corresponds to the C one in all cases

centril (May 28 2019 at 11:08, on Zulip):

and you could do this translation mechanically

gnzlbg (May 28 2019 at 11:08, on Zulip):

some intrinsics take multiple const argument IIRC

centril (May 28 2019 at 11:08, on Zulip):

and each new API design would need to be reviewed, RFC, manually verified, etc.

I don't see why... just shuffle any const argument to be in <..>

centril (May 28 2019 at 11:08, on Zulip):

OK; then do them in order, left to right

gnzlbg (May 28 2019 at 11:08, on Zulip):

I'm not saying it is impossible, i'm saying, that's what was RFCed

centril (May 28 2019 at 11:09, on Zulip):

complicating the type theory for some vague "should be like C" benefits seems like not taking complexity in the type theory seriously enough

centril (May 28 2019 at 11:09, on Zulip):

Yeah I understand

gnzlbg (May 28 2019 at 11:09, on Zulip):

and back then, nobody rejected #[rustc_const_arg_...] either, because const function arguments seemed worth doing anyways

gnzlbg (May 28 2019 at 11:09, on Zulip):

so it wasn't that const function arguments weren't explored either _before_ adding #[rustc_const_arg]

gnzlbg (May 28 2019 at 11:10, on Zulip):

nobody suggested using <...> instead of (...)

centril (May 28 2019 at 11:10, on Zulip):

because const function arguments seemed worth doing anyways

I hope this turns out to be true...

centril (May 28 2019 at 11:10, on Zulip):

would be pretty sad to have #[rustc_const_arg...] forever

gnzlbg (May 28 2019 at 11:10, on Zulip):

there are some intrinsics that we can't implement right now because it isn't

gnzlbg (May 28 2019 at 11:11, on Zulip):

so i hope so too

RalfJ (May 28 2019 at 11:12, on Zulip):

"because it isn't" it isn't what?

gnzlbg (May 28 2019 at 11:13, on Zulip):

because it isn't a true const

gnzlbg (May 28 2019 at 11:13, on Zulip):

just a lint

gnzlbg (May 28 2019 at 11:13, on Zulip):

as in, #[rustc_const_arg(N)] is only a lint, so some intrinsics cannot be implemented right now with it

varkor (May 28 2019 at 11:19, on Zulip):

I do think it's a shame that this was stabilised like this, rather than as const generics, as it's essentially just a less powerful version with different syntax... but if it hadn't been, it would have had to remain unstable for a lot longer, because of const generics
(though we could probably just have used the CG syntax without true CGs...)

varkor (May 28 2019 at 11:23, on Zulip):

I don't see any reason to make this feature available to users, though, because as far as I see, it's completely subsumed by CGs

varkor (May 28 2019 at 11:23, on Zulip):

the only difference being whether the arguments can be inferred or not

gnzlbg (May 28 2019 at 11:26, on Zulip):

Then the fix for these would actually be not to add a "const function arguments" feature, but to keep #[rustc_const_arg] forever and extend it to make those arguments actually implicitly const generic "somehow"

gnzlbg (May 28 2019 at 11:27, on Zulip):

many intrinsics can be implemented without doing this, but doing it that way has a big cost, and the intrinsics that cannot be implemented with this today, aren't implemented not because writing the code is impossible, but because doing so makes compile-times explode

gnzlbg (May 28 2019 at 11:28, on Zulip):

last time we tested, the compilation time of the standard library increased by ~10min per each time one of these intrinsics is used

gnzlbg (May 28 2019 at 11:28, on Zulip):

so if you call them 4 times in the std library, you bump the compilation time of libstd by 40 minutes

centril (May 28 2019 at 11:28, on Zulip):

@varkor Agda and Idris both have {A: Type}and (A: Type) so it doesn't seem strange to me

centril (May 28 2019 at 11:30, on Zulip):

being able to pick whether something should be inferrable or not seems like a nice thing to give users

gnzlbg (May 28 2019 at 11:30, on Zulip):

users can't build abstractions on top of these intrinsics today

varkor (May 28 2019 at 11:30, on Zulip):

@centril: if we want to control inference specifically, it should be extended to all parameters, not just consts

gnzlbg (May 28 2019 at 11:30, on Zulip):

and they wouldn't be able to do this even if const generics was stable

centril (May 28 2019 at 11:30, on Zulip):

@varkor I mean... I agree that fn foo(A: type) would be nice

varkor (May 28 2019 at 11:31, on Zulip):

also, it's not the same as Agda, etc. because you have an additional compile-time requirement

centril (May 28 2019 at 11:31, on Zulip):

@varkor but I don't think we have to do "all or nothing"

varkor (May 28 2019 at 11:31, on Zulip):

@gnzlbg: we might be able to retroactively change that, so the syntax is just sugar for const generics, which would allow them to interact nicely

gnzlbg (May 28 2019 at 11:32, on Zulip):

its sad having to add this feature just for this

varkor (May 28 2019 at 11:32, on Zulip):

@centril: it's possibly less useful though

varkor (May 28 2019 at 11:32, on Zulip):

(though maybe still valuable)

centril (May 28 2019 at 11:32, on Zulip):

removing the #[rustc_const_arg] hack through const A: B seems like a useful intermediary step

gnzlbg (May 28 2019 at 11:32, on Zulip):

one advantage is not having to write the ::<{ ... }>, but i wish we could gain that independently of whether const generics are used or "this"

gnzlbg (May 28 2019 at 11:33, on Zulip):

i mean, if we provide (...), why would a user write const generics ?

varkor (May 28 2019 at 11:33, on Zulip):

(that would be nicer without turbofish :smiling_devil:)

centril (May 28 2019 at 11:33, on Zulip):

@gnzlbg it's still const generics

varkor (May 28 2019 at 11:33, on Zulip):

we've essentially just got two ways of writing the same thing now

centril (May 28 2019 at 11:33, on Zulip):

the only difference is inference/no

gnzlbg (May 28 2019 at 11:33, on Zulip):

If we provide fn foo(const X: T); why would anyone prefer fn foo<const X: T>() instead ?

centril (May 28 2019 at 11:34, on Zulip):

@gnzlbg cause you get inference

gnzlbg (May 28 2019 at 11:34, on Zulip):

so that's useful, but why wouldn't you be able to get inference with const X: T syntax as well ?

gnzlbg (May 28 2019 at 11:34, on Zulip):

e.g. fn foo(const X: usize) where X == 0 { .. }

gnzlbg (May 28 2019 at 11:36, on Zulip):

I'd find the trade-off: const-generics: inference but {...}-syntax vs const-arg: no-inference but nice-syntax unnecessary

centril (May 28 2019 at 11:39, on Zulip):

cause that's what you have with (...)

gnzlbg (May 28 2019 at 11:39, on Zulip):

Sure, I just think it is sub-optimal to have to make that choice

varkor (May 28 2019 at 11:39, on Zulip):

this is the problem

varkor (May 28 2019 at 11:39, on Zulip):

we now have two syntaxes, and the "proper" one looks uglier

gnzlbg (May 28 2019 at 11:40, on Zulip):

yeah :/

centril (May 28 2019 at 11:40, on Zulip):

well it's two syntaxes for two different things

gnzlbg (May 28 2019 at 11:40, on Zulip):

slightly-different things

centril (May 28 2019 at 11:40, on Zulip):

being able to force non-inference is useful

centril (May 28 2019 at 11:41, on Zulip):

"I really want people to specify things explicitly here"

gnzlbg (May 28 2019 at 11:41, on Zulip):

can we get inference + being able to use the type in where clauses, bounds, etc. ?

gnzlbg (May 28 2019 at 11:41, on Zulip):

e.g., fn foo<A: [i32; N]>(const N: usize, x: Vec<A>) where N > 0, A: SomeTrait -> A { ... } ?

centril (May 28 2019 at 11:42, on Zulip):

I mean you can assign that meaning to that syntax if you want

centril (May 28 2019 at 11:42, on Zulip):

it's surprising tho.

gnzlbg (May 28 2019 at 11:44, on Zulip):

if we were to do that, the only reason for an user to prefer fn foo<const X: usize>() over fn bar(const X: usize) is "i explicitly want to forbid inference"

gnzlbg (May 28 2019 at 11:45, on Zulip):

that's sometimes desirable, but most of the time APIs with inference are more appropriate

centril (May 28 2019 at 11:45, on Zulip):

<A: [i32; N]> presumably is runtime dependent typing

gnzlbg (May 28 2019 at 11:47, on Zulip):

no, i screwed the type signature up, what i meant is:

fn foo<A>(const N: usize, x: B<N>, z: A) where N > 0 , A: SomeTrait<N> -> C<N> { ... }

gnzlbg (May 28 2019 at 11:47, on Zulip):

so that N is inferred, but it still can be used in where clauses / trait bounds, etc.

centril (May 28 2019 at 11:49, on Zulip):

Aside: where N > 0 , A: SomeTrait<N> -> C<N> <-- that's going to be fun in terms of parser ambiguity

gnzlbg (May 28 2019 at 11:49, on Zulip):

if we were to allow this, fn foo<const X: usize>() would become super rare, and so would having to write { ... } when passing const generics to functions in function calls

gnzlbg (May 28 2019 at 11:49, on Zulip):

so it isn't necessarily a bad thing

gnzlbg (May 28 2019 at 11:49, on Zulip):

@centril we could have where { N > 0 }

centril (May 28 2019 at 11:50, on Zulip):

yeah

centril (May 28 2019 at 11:50, on Zulip):

where N > 0 , A: Fn() -> C<N> :joy:

centril (May 28 2019 at 11:51, on Zulip):

(you can pick a parse, so it's not so bad)

gnzlbg (May 28 2019 at 11:54, on Zulip):

it seems that here it is just better to wait for stable const generics, and then re-consider this as something to build on top of that

varkor (May 28 2019 at 12:34, on Zulip):

re. inference: it's not clear that not inferring the arguments is an intentional decision, rather than just being easier to implement

varkor (May 28 2019 at 12:34, on Zulip):

in which case it's an implementation limitation and should hence be equivalent exactly to const generics

centril (May 28 2019 at 12:37, on Zulip):

The distinction between <..> and (..) in terms of inference seems clear to me at least

centril (May 28 2019 at 12:37, on Zulip):

it's very much intentional in Agda/Idris

RalfJ (May 28 2019 at 12:43, on Zulip):

TBH I always viewed <...> vs (...) as compile-time vs run-time

varkor (May 28 2019 at 12:43, on Zulip):

@centril: yes, but this isn't Agda

RalfJ (May 28 2019 at 12:43, on Zulip):

and not as having anything to do with implicit/explicit arguments in agda/idris (coq has them too and I assume they are similar)

varkor (May 28 2019 at 12:43, on Zulip):

it's a coïncidence here

rkruppe (May 28 2019 at 12:44, on Zulip):

I also prefer to draw the distinction at <...> holding static / compile time parameters and arguments while (...) hold dynamic / run time ones. I understand that Centril would like to eliminate this distinction but current and historical Rust does have it and I don't see any consensus that should definitely change. With that in mind the presence vs absence of inference seems subordinate to me, a byproduct of type inference (for Rust's type system) being a neatly solved problem while expression synthesis is much more difficult.

RalfJ (May 28 2019 at 12:44, on Zulip):

basically, what @rkruppe said :)

varkor (May 28 2019 at 12:44, on Zulip):

I prefer thinking about the compile time distinction too

centril (May 28 2019 at 12:44, on Zulip):

If we allow (const A: B) then that compiletime/runtime distinction goes away

varkor (May 28 2019 at 12:45, on Zulip):

I think we should treat that as a mistake

varkor (May 28 2019 at 12:45, on Zulip):

or "FFI sugar"

varkor (May 28 2019 at 12:45, on Zulip):

and not propagate it further

centril (May 28 2019 at 12:46, on Zulip):

I personally don't find the compile-time/run-time distinction important nor useful pedagogically, especially when const itself helps to qualify things

centril (May 28 2019 at 12:48, on Zulip):

It's also not clear to me why the inference aspect is subordinate to the staging aspect

rkruppe (May 28 2019 at 12:48, on Zulip):

Having one argument list just for compile time arguments and a separate one for run time arguments has the advantage that one doesn't need (to worry about) partial application to nail down the compile time parts and get e.g. a function pointer.

centril (May 28 2019 at 12:49, on Zulip):

We don't have partial application for either part

centril (May 28 2019 at 12:50, on Zulip):

From what @gnzlbg says, having (const A: B) with or without seems like a necessity for some of the intrinsics

centril (May 28 2019 at 12:51, on Zulip):

that, or we use <...> for some of the intrinsics

RalfJ (May 28 2019 at 12:51, on Zulip):

well we have "apply all the compile-time things but none of the run-time things"

RalfJ (May 28 2019 at 12:51, on Zulip):

which is partial application if we start mixing those

varkor (May 28 2019 at 12:51, on Zulip):

I thought we established partial application was not necessary

RalfJ (May 28 2019 at 12:51, on Zulip):

I also find this exact distinction extremely helpful pedagogically

rkruppe (May 28 2019 at 12:52, on Zulip):

Yes I was getting at what @RalfJ said: we can currently go from fn foo<...>(...) -> R to a fn(...) -> R by supplying everything for the <...>. If you intermingle the statically-given parts in the (...) as well, there's no nice way to specify the static parts and get a monomorphic function without partial application.

centril (May 28 2019 at 12:52, on Zulip):

You don't have partial application within either of the lists

rkruppe (May 28 2019 at 12:53, on Zulip):

Yes? I know that. I'm saying is we can do a useful thing now without having partial application, because there are two separate argument lists you can fill in entirely or not.

centril (May 28 2019 at 12:54, on Zulip):

you can just not allow getting a function pointer when it has (const A: B) -- function pointers are of marginal utility anyways (eddyb hates them I hear... ^^)

centril (May 28 2019 at 12:54, on Zulip):

i.e. what @varkor said

rkruppe (May 28 2019 at 12:54, on Zulip):

It's not just function pointers, it's also non-higher-rank Fn()s

centril (May 28 2019 at 12:54, on Zulip):

@rkruppe trait objects?

rkruppe (May 28 2019 at 12:55, on Zulip):

For example. But also it's a pain to work with higher rank things (at least today, we'll see how much of that chalkification can fix)

centril (May 28 2019 at 12:56, on Zulip):

Speaking of... going back to reviewing the most boring PR ever ^^

gnzlbg (May 28 2019 at 13:03, on Zulip):

I don't know how we could make (...) run-time only

centril (May 28 2019 at 13:03, on Zulip):

Well it is right now

gnzlbg (May 28 2019 at 13:03, on Zulip):
struct One;
impl TypeNum for One {}
fn foo<T: Num>(x: T) { ... }
gnzlbg (May 28 2019 at 13:03, on Zulip):

is foo(One) run-time ?

RalfJ (May 28 2019 at 13:03, on Zulip):

yes?

RalfJ (May 28 2019 at 13:03, on Zulip):

One is a run-time value?

centril (May 28 2019 at 13:04, on Zulip):

well it isn't "compile time only"

gnzlbg (May 28 2019 at 13:04, on Zulip):

it isn't a run-time thing either, your CPU won't execute stuff with one

RalfJ (May 28 2019 at 13:04, on Zulip):

the compile-time argument is One, too (we use the same name for the type and the value but that does not make them the same thing)

RalfJ (May 28 2019 at 13:04, on Zulip):

It's foo::<One>(One) really.

gnzlbg (May 28 2019 at 13:05, on Zulip):

if you use typenum, you can do arithmetic at compile-time, by passing "run-time" values like that

gnzlbg (May 28 2019 at 13:05, on Zulip):

It's foo::<One>(One) really.

Well, yes.

centril (May 28 2019 at 13:05, on Zulip):

LLVM or rustc may optimize away things but that's different

RalfJ (May 28 2019 at 13:05, on Zulip):

the arithemtic you are doing then is on the type One, not the value One

RalfJ (May 28 2019 at 13:05, on Zulip):

it isn't a run-time thing either, your CPU won't execute stuff with one

that's an implementation detail (that ZSTs optimize away)

centril (May 28 2019 at 13:05, on Zulip):

@RalfJ aside: having a separate type and value namespace makes me sad

gnzlbg (May 28 2019 at 13:06, on Zulip):

from a user-pov, i think it would be a disservice to const generics to have to teach the difference

RalfJ (May 28 2019 at 13:06, on Zulip):

well in a language without dependent types it's kinda useful ;)

gnzlbg (May 28 2019 at 13:06, on Zulip):

it would be bad if const generics APIs end up being worse than using typenum

centril (May 28 2019 at 13:06, on Zulip):

@RalfJ yea but then you suddenly want ~dependent types (const generics in this case) and it gets bad

gnzlbg (May 28 2019 at 13:06, on Zulip):

because typenum can be inferred, but const generics cannot

RalfJ (May 28 2019 at 13:06, on Zulip):

@gnzlbg uh? I think if someone doesnt understand the difference between the type and value One they'll have a hard time

RalfJ (May 28 2019 at 13:06, on Zulip):

but for const generics this is different anyway

RalfJ (May 28 2019 at 13:06, on Zulip):

so I dont follow

RalfJ (May 28 2019 at 13:07, on Zulip):

then it'd be foo::<{1}>() or so. no runtime argument. right?

gnzlbg (May 28 2019 at 13:07, on Zulip):

with typenum I can write: let one = ..; let two = ..; let three = add(one, two); and get a three value that's computed at compile-time

gnzlbg (May 28 2019 at 13:07, on Zulip):

with const generics i'd gave to write let three = add::<{one, two}>();

RalfJ (May 28 2019 at 13:08, on Zulip):

same amount of information though

RalfJ (May 28 2019 at 13:08, on Zulip):

just more annoying to type

RalfJ (May 28 2019 at 13:08, on Zulip):

what happens here is that you are using singleton types, basically

centril (May 28 2019 at 13:08, on Zulip):

eww

centril (May 28 2019 at 13:08, on Zulip):

@RalfJ have you seen the singletons haskell package?

RalfJ (May 28 2019 at 13:08, on Zulip):

but really @gnzlbg you'd write const THREE = ONE+TWO;

RalfJ (May 28 2019 at 13:08, on Zulip):

RalfJ have you seen the singletons haskell package?

no

centril (May 28 2019 at 13:09, on Zulip):

let three = add::<{one, two}>(); -- is this supposed to be a tuple?

oli (May 28 2019 at 13:09, on Zulip):

just a typo I think. let three = add::<{one}, {two}>();

RalfJ (May 28 2019 at 13:09, on Zulip):

still not sure why you'd call const addition by going through const generics^^

RalfJ (May 28 2019 at 13:09, on Zulip):

what's the return type of add anyway?

centril (May 28 2019 at 13:09, on Zulip):

no

good :slight_smile: -- it's a monstrosity (the author agrees)... hacking in dependent types through singleton types

oli (May 28 2019 at 13:10, on Zulip):

what's the return type of add anyway?

Add<One, Add<One, One>> or the binary version of that

RalfJ (May 28 2019 at 13:10, on Zulip):

no I mean in the const generics version, not in the numtypes version

oli (May 28 2019 at 13:10, on Zulip):

ah

oli (May 28 2019 at 13:11, on Zulip):

you don't do that :P

centril (May 28 2019 at 13:11, on Zulip):

Just 3 ?

centril (May 28 2019 at 13:11, on Zulip):

:P

RalfJ (May 28 2019 at 13:11, on Zulip):

that's what I mean :D

RalfJ (May 28 2019 at 13:11, on Zulip):

it'd be const fn add(x: i32, y: i32) -> i32 or so

oli (May 28 2019 at 13:11, on Zulip):

I mean you can, but it would be TypeNumber<3> in that case

RalfJ (May 28 2019 at 13:11, on Zulip):

not const fn<X: i32, Y: i32>() -> Add<X, Y> or whatever

RalfJ (May 28 2019 at 13:11, on Zulip):

@gnzlbg const usize? what the heck is that?^^

gnzlbg (May 28 2019 at 13:12, on Zulip):

that's what TypeNumber<3> is

oli (May 28 2019 at 13:12, on Zulip):

I'm very confused

RalfJ (May 28 2019 at 13:12, on Zulip):

TypeNumber is a hack you need when you dont have const generics

RalfJ (May 28 2019 at 13:12, on Zulip):

why do you still want to use that hack with const generics...?

centril (May 28 2019 at 13:12, on Zulip):

@RalfJ It's an idea me and @varkor had about lifting Type to a ConstType universe

gnzlbg (May 28 2019 at 13:12, on Zulip):

with typenum, what one writes is fn<const X: usize, const Y: usize>() -> const Z: usize

RalfJ (May 28 2019 at 13:12, on Zulip):

with typenum, what one writes is fn<const X: usize, const Y: usize>() -> const Z: usize

uh, why would one do that??

centril (May 28 2019 at 13:13, on Zulip):

e.g. let x: const usize = random(); // nope

oli (May 28 2019 at 13:13, on Zulip):

@centril that's orthogonal :P

RalfJ (May 28 2019 at 13:13, on Zulip):

@centril I don't know what that means^^

centril (May 28 2019 at 13:14, on Zulip):

@oli well you'd write fn foo<N: const usize> instead of fn foo<const N: usize> in that case

centril (May 28 2019 at 13:14, on Zulip):

@RalfJ we barely know what it means as well :P

gnzlbg (May 28 2019 at 13:15, on Zulip):

uh, why would one do that??

That's how typenum is implemented

RalfJ (May 28 2019 at 13:15, on Zulip):

as far as I am concerned both are just <N: usize>. as in, compile-time usize.

RalfJ (May 28 2019 at 13:15, on Zulip):

uh, why would one do that??

That's how typenum is implemented

yes because it doesnt have const generics

RalfJ (May 28 2019 at 13:15, on Zulip):

no need to kludge to an awful hack when you got the proper thing

centril (May 28 2019 at 13:16, on Zulip):

@RalfJ well... the gist of it is that const T is { x: T | is_constexpr(x) }

gnzlbg (May 28 2019 at 13:16, on Zulip):

I don't know what type of argument you are trying to make

RalfJ (May 28 2019 at 13:16, on Zulip):

RalfJ well... the gist of it is that const T is { x: T | is_constexpr(x) }

that's ill-typed, x is a value and you are passing it to a term expecting an expression

gnzlbg (May 28 2019 at 13:16, on Zulip):

with typenum you can write fn foo(X: Typenum, y: usize) -> usize

RalfJ (May 28 2019 at 13:16, on Zulip):

so that would become fn foo<X: usize>(y: usize) -> usize

gnzlbg (May 28 2019 at 13:16, on Zulip):

so that i can write let three = foo(N, run_time_val);

gnzlbg (May 28 2019 at 13:17, on Zulip):

I consider having to write let three = foo::<{N}>(run_time_val); a regression

RalfJ (May 28 2019 at 13:17, on Zulip):

to me it looks like you want to recreate an old unergonomic API in a new framework that was specifrically designed to not require having to do those unergonomic things.

gnzlbg (May 28 2019 at 13:17, on Zulip):

if you think that foo::<{N}>(val) is nicer than foo(N, val), then just say so

gnzlbg (May 28 2019 at 13:17, on Zulip):

i disagre, and we can call it a day

RalfJ (May 28 2019 at 13:18, on Zulip):

I think that's just syntax and I thought were were talking about something deeper than that

gnzlbg (May 28 2019 at 13:18, on Zulip):

no

gnzlbg (May 28 2019 at 13:18, on Zulip):

or not AFAICT

RalfJ (May 28 2019 at 13:18, on Zulip):

because currently what you are really writing is foo::<{N}>(N, val), just you get some inference

centril (May 28 2019 at 13:18, on Zulip):

@RalfJ I don't follow; I'm using refinment type notation here for "Given a type, all the expressions of that type computable at compile time"

RalfJ (May 28 2019 at 13:18, on Zulip):

@centril yeah but types classify values, not expressions

gnzlbg (May 28 2019 at 13:19, on Zulip):

@RalfJ but because there is inference, I don't have to write ::<{N}>

RalfJ (May 28 2019 at 13:19, on Zulip):

so I dont see how that would work. unless you are going with thunks or call-by-name or so.

gnzlbg (May 28 2019 at 13:19, on Zulip):

or is the argument that inference isn't important?

gnzlbg (May 28 2019 at 13:19, on Zulip):

the only difference betwee const generics, and const function arguments is inference

RalfJ (May 28 2019 at 13:19, on Zulip):

@centril sounds to me like you are looking for some kind of staged type system

RalfJ (May 28 2019 at 13:20, on Zulip):

then you get types on each stage -- like, a compile-time T and a run-time T

RalfJ (May 28 2019 at 13:20, on Zulip):

these are not really sigma types though, that's a very different thing

RalfJ (May 28 2019 at 13:20, on Zulip):

it's more like a modality

centril (May 28 2019 at 13:20, on Zulip):

@RalfJ me and @varkor were discussing something like that yes

centril (May 28 2019 at 13:20, on Zulip):

I don't literally mean a sigma type

RalfJ (May 28 2019 at 13:21, on Zulip):

or is the argument that inference isn't important?

inference is important. I was just under the impression that we talked about something else.^^

centril (May 28 2019 at 13:21, on Zulip):

hence universes and "lifting" :slight_smile:

RalfJ (May 28 2019 at 13:21, on Zulip):

the only difference betwee const generics, and const function arguments is inference

no. the only difference is where you have to put your argument.

RalfJ (May 28 2019 at 13:21, on Zulip):

foo::<{N}>(y) and foo(N, y) have the exact same amount of inference going on

RalfJ (May 28 2019 at 13:22, on Zulip):

assuming the latter is a const fn argument

centril (May 28 2019 at 13:22, on Zulip):

@RalfJ I think what @gnzlbg is getting at is that the former would permit inference whereas the latter wouldn't

RalfJ (May 28 2019 at 13:22, on Zulip):

inference only comes into play when you consider the hack that is currently used to encode values in types

centril (May 28 2019 at 13:22, on Zulip):

i.e. implicit vs. explicit arguments

RalfJ (May 28 2019 at 13:22, on Zulip):

then the two variants are foo::<{N}>(N, y) and foo(N, y), but thanks to inference you can leave away one N in the former

gnzlbg (May 28 2019 at 13:23, on Zulip):

that confused me before centril, but as @ralfj says, you get the same inference with both

gnzlbg (May 28 2019 at 13:23, on Zulip):

@RalfJ note that today foo::<{N}>(N) is not allowed, only foo::<{N}>()

RalfJ (May 28 2019 at 13:23, on Zulip):

my impression here is that the complaint about using const generics to encode const fn arguments is only about syntax and has nothing to do with being implicit/explicit, or synax

RalfJ (May 28 2019 at 13:24, on Zulip):

RalfJ note that today foo::<{N}>(N) is not allowed, only foo::<{N}>()

hu? I was assuming use of typenum there

RalfJ (May 28 2019 at 13:24, on Zulip):

then it's add::<One, One>(One, One), right? in the code you wrote above (with struct One;)

centril (May 28 2019 at 13:24, on Zulip):

well with const generics you can say: fn foo<const N: usize>(x: [u8; N]) and then just write foo([]) such that N is inferred to 0

gnzlbg (May 28 2019 at 13:24, on Zulip):

I thought you were talking const generics

RalfJ (May 28 2019 at 13:24, on Zulip):

oh no so much talking past each other^^

gnzlbg (May 28 2019 at 13:24, on Zulip):

well with const generics you can say: fn foo<const N: usize>(x: [u8; N]) and then just write foo([]) such that N is inferred to 0

having to do that, would suck

RalfJ (May 28 2019 at 13:25, on Zulip):

with const generics there is just one N

centril (May 28 2019 at 13:25, on Zulip):

whereas if you wrote fn foo(const N: usize, x: [u8; N]) then you'd be forced to write foo(0, [])

centril (May 28 2019 at 13:25, on Zulip):

at least assuming the implicit/explicit distinction

RalfJ (May 28 2019 at 13:26, on Zulip):

we have three systems that came up in this discussion: typenum, const generics, const fn arguments. typenum needs inference to avoid repetition.

centril (May 28 2019 at 13:26, on Zulip):

typenum needs to go away :slight_smile:

gnzlbg (May 28 2019 at 13:26, on Zulip):

but what replaces it shouldn't be worse

centril (May 28 2019 at 13:26, on Zulip):

worse? huh...

RalfJ (May 28 2019 at 13:27, on Zulip):

const generics can sometimes be inferred like when the value also occurs in a type. but the cases we are talking about are such that that's not possible (I thought)

centril (May 28 2019 at 13:27, on Zulip):

how can const generics be worse than singleton hacks to fake dependent types

gnzlbg (May 28 2019 at 13:27, on Zulip):

by forcing people to write foo::<{....}>() vs just foo(...)

RalfJ (May 28 2019 at 13:28, on Zulip):

so @centril please stop with your inference stuff because I dont think that applies here :) like in @gnzlbg's foo(N, run_time_val), there is no inferring N.

gnzlbg (May 28 2019 at 13:28, on Zulip):

i consider having to change a function from fn foo(x: i32) callable as foo(x) to fn foo<const x: i32>() callable as foo::<{x}>() a regression - if the only intent is to encode in the type that x must be a const

centril (May 28 2019 at 13:29, on Zulip):

@RalfJ I'm so confused now... :P

RalfJ (May 28 2019 at 13:29, on Zulip):

also I should get some work done, maybe you two can deconfuse yourselves easier without me being around :) ttyl

centril (May 28 2019 at 13:30, on Zulip):

@gnzlbg In the cases where you'd need to write foo::<{ ... }>() with const generics you'd presumably have to write fn foo::<{ ... }> to write out the singleton type in any case

gnzlbg (May 28 2019 at 13:30, on Zulip):

well no if the code was using typenum

centril (May 28 2019 at 13:30, on Zulip):

because the singleton type cannot be inferred unless constrained by a type

centril (May 28 2019 at 13:31, on Zulip):

@gnzlbg what sort of magic does typenum have :D

gnzlbg (May 28 2019 at 13:31, on Zulip):

fn foo<T>(x: T); foo(one: One);

centril (May 28 2019 at 13:32, on Zulip):

you need to write out the ZST expression there

centril (May 28 2019 at 13:32, on Zulip):

how is that ergonomic?

gnzlbg (May 28 2019 at 13:33, on Zulip):

i don't have to write foo::<One>(), I find writing foo(one) better

gnzlbg (May 28 2019 at 13:33, on Zulip):

I'm having the feeling that you all prefer foo::<{one}>() better than foo(one)

centril (May 28 2019 at 13:33, on Zulip):

No not really

centril (May 28 2019 at 13:33, on Zulip):

I think it's a minor papercut

centril (May 28 2019 at 13:34, on Zulip):

I do find foo::<1>() nicer tho

centril (May 28 2019 at 13:34, on Zulip):

1 vs. One

kennytm (May 28 2019 at 13:35, on Zulip):

tbh given the effort put trying to slay the turbofish i don't think this is a minor papercut :P

gnzlbg (May 28 2019 at 13:35, on Zulip):

as a user, having to remember which argument is a const generic and which one isn't isn't minor

centril (May 28 2019 at 13:35, on Zulip):

@kennytm that's mostly a matter of consistency :slight_smile:

gnzlbg (May 28 2019 at 13:35, on Zulip):

like if I call foo(x, y, z) and y needs to be a const, I probably get a really good error message with foo(x: i32, const y: i32, z: i32)

gnzlbg (May 28 2019 at 13:36, on Zulip):

but if I have foo::<const Y: usize>(x: i32, z: i32) instead, the error message might be weird

centril (May 28 2019 at 13:36, on Zulip):

@gnzlbg I'm in favor of (const A: B) where A must be provided explicitly, so it seems we are agreed practically speaking?

centril (May 28 2019 at 13:36, on Zulip):

the error message might be weird

Let's reserve judgement until @Esteban Küber has worked is magic shall we?

gnzlbg (May 28 2019 at 13:37, on Zulip):

the number of arguments doesn't match, a single type parameter is missing or can't be deduced, ...

gnzlbg (May 28 2019 at 13:37, on Zulip):

the best error message that I can imagine for this function would still be worse than "y is not a const but should be"

RalfJ (May 28 2019 at 13:39, on Zulip):

if we have this, can we declare this to be just syntactic sugar? so that later phases of the compiler dont even have to know about this any more?

gnzlbg (May 28 2019 at 13:40, on Zulip):

@RalfJ the main problem with making this just syntax sugar, is that we'd need to translate fn foo(const X: i32) to fn foo<const X: i32>() at some point

gnzlbg (May 28 2019 at 13:41, on Zulip):

and then the question about how this mapping works needs to be resolved

kennytm (May 28 2019 at 13:41, on Zulip):

kennytm that's mostly a matter of consistency :)

i suppose the issue at hand is _mm_shuffle_pd::<0b10>(x, y), if so written, is inconsistent with other SIMD APIs

gnzlbg (May 28 2019 at 13:42, on Zulip):

fn foo<'a, T>(const X: usize) => fn foo<const X: usize, 'a, T>(), fn foo<'a, const X: usize, T>, etc.

gnzlbg (May 28 2019 at 13:44, on Zulip):

@kennytm the desugared syntax needs to map to const generic syntax, so we need to put "const function arguments" somewhere in the type list

kennytm (May 28 2019 at 13:44, on Zulip):

@gnzlbg where the mapped parameter is placed should be internal to the compiler and irrelevant to the API user

gnzlbg (May 28 2019 at 13:45, on Zulip):

i thought it would impact name mangling, etc.

RalfJ (May 28 2019 at 13:45, on Zulip):

@gnzlbg it doesnt have to be a desugaring that is literally concerned with restrictions such as this list of parameters

RalfJ (May 28 2019 at 13:45, on Zulip):

but it could be conceptual

RalfJ (May 28 2019 at 13:45, on Zulip):

just have a 2nd invisible list that these desugared things are added to, or so

kennytm (May 28 2019 at 13:46, on Zulip):

@gnzlbg it's ok as long as the mangling is internally consistent?

RalfJ (May 28 2019 at 13:46, on Zulip):

and for mangling imagine that list to be at the end

gnzlbg (May 28 2019 at 13:46, on Zulip):

@RalfJ so i also would want this to just be desugaring

RalfJ (May 28 2019 at 13:46, on Zulip):

or just literally just have it at the end, and lift the restrictions we usually have about only giving none or all of the implicit arguments such that the desugared case where only the "const fn arg" parts are filled is okay

kennytm (May 28 2019 at 13:46, on Zulip):

i think it should have the same treatment as APIT regarding mangling

gnzlbg (May 28 2019 at 13:47, on Zulip):

that makes sense

varkor (May 28 2019 at 15:25, on Zulip):

const parameters must currently come last anyway, so there's a canonical choice of desugaring

varkor (May 28 2019 at 15:25, on Zulip):

(though that may not always be true)

centril (May 28 2019 at 15:28, on Zulip):

@varkor s/first/last ?

Luca Barbato (Jun 03 2019 at 08:59, on Zulip):

Good morning!

Luca Barbato (Jun 03 2019 at 09:11, on Zulip):

I'm all for having a mean to put constants as normal arguments :)

Luca Barbato (Jun 03 2019 at 09:12, on Zulip):

vec_splat_u8::<15>() is _quite_ a lot of noise

Last update: Nov 21 2019 at 23:30UTC