Skip to content

Use for to introduce universal quantification #157

New issue

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

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Conversation

glaebhoerl
Copy link
Contributor

@lilyball
Copy link
Contributor

lilyball commented Jul 5, 2014

Interesting proposal. I would prefer adding the keyword forall here though, because for already has a distinct semantic meaning and I don't really like overloading it. I think it would be confusing to people who aren't already aware of the meaning, and it would be rather difficult to search for. Whereas seeing forall is a bit more obviously something unique, it's significantly easier to search for, and for people who are aware of universal quantification it will likely be immediately obvious what's going on (but for is not so obviously universal quantification).

That said, I think that the idea of explicit quantification could be useful with e.g. a revised form of RFC PR 105 (Unboxed, abstract return types). In the case of wanting to return some value that conforms to Iterator<T> without having to explicitly write out the full type, one could use exists on a type parameter. But in that case, the keyword would be expected to appear inside the type parameter list, so it would look something like

fn my_transform<T, Iter: Iterator<T>, exists RIter: Iterator<T>>(iter: Iter) -> RIter { ... }

But if we allow exists inside a type parameter list like this, it seems weird to use forall outside the list. Furthermore, it would suggests that one could not use exists inside a forall<...> and that is an unnecessary restriction.

This suggests that instead we should have a different keyword to introduce a type parameter list for the use of higher-rank lifetimes. I don't have a good suggestion for what to use, though. Alternatively, we could just use nothing and continue to allow un-prefixed type parameter lists to appear in type position in a function signature like we do today.

@lilyball
Copy link
Contributor

lilyball commented Jul 5, 2014

I suppose an approach that allows the prefix style again is to use exists prefix-style, which I was ignoring because I didn't think it would work well with functions, but it's not really that awful if you're willing to also use a forall prefix-style list on the same function:

forall<T, Iter: Iterator<T>>
exists<RIter: Iterator<T>>
fn my_transform(iter: Iter) -> RIter { ... }

But it's not that great either. And allowing a prefix-style forall on a function like this would suggest that the normal style of fn foo<A,B,C>() should be disallowed (in favor of TIOOWTDI). But that then conflicts with the very nearly use-follows-declaration style of specializing the call site as foo::<A,B,C>(). That kind of specialization would be very strange when coupled with a prefix-style forall.

Given that, I'm not in favor of this approach. But I thought it was worth documenting.

The other problem is this requires forall/exists to be full keywords, when the <exists A> style would allow exists to be a context-sensitive keyword (which, yes, we don't currently have any precedent for, but we keep using that as a justification for not introducing context-sensitive keywords, and we now have a number of keywords that could reasonably be made context-sensitive, such as in).

@glaebhoerl
Copy link
Contributor Author

I would prefer adding the keyword forall here though, because for already has a distinct semantic meaning and I don't really like overloading it.

What I was trying to point out in the Motivation is that these distinct semantic meanings are very similar.

That said, I think that the idea of explicit quantification could be useful with e.g. a revised form of RFC PR 105 (Unboxed, abstract return types).

I don't think existential quantification is necessarily the right way to think about this.

And allowing a prefix-style forall on a function like this would suggest that the normal style of fn foo<A,B,C>() should be disallowed (in favor of TIOOWTDI).

Are you opposed to syntactic sugar on principle? Should we remove for..in loops in favor of using Iterator::next() explicitly?

(I personally think TIOOWTDI is important on the semantic level, but inconsequential on the syntactic one.)

@lilyball
Copy link
Contributor

lilyball commented Jul 6, 2014

Are you opposed to syntactic sugar on principle?

No, but I don't see forall<T> fn foo() as being syntactic sugar for fn foo<T>(). I see it as just being two ways to express the same thing. The forall version is not any more abstract, does not provide any additional functionality, etc. as the current form.

@glaebhoerl
Copy link
Contributor Author

I think of for<T1..Tn> item or for<T1..Tn> { ...items... } as being the longform general case, and e.g. fn foo<T1..Tn>(...), struct Foo<T1..Tn> { ... }, and so forth as sugar for it. (Ditto for where clauses, where we'd be adding a more general form, and the existing form turns into sugar for it.)

Anyway, this branch of the discussion belongs in #122.

@jfager
Copy link

jfager commented Jul 11, 2014

I personally don't see the current syntax as problematic. Even if it were, adding more characters and making people sort out another meaning of for strikes me as a cure worse than the disease.

@bstrie
Copy link
Contributor

bstrie commented Jul 11, 2014

-1. It is widely acknowledged that function signatures (and typaram declarations specifically) are a problem, but this does nothing to solve any of the verbosity that we currently suffer (it makes it worse, in fact). We need a more widespread and cohesive redesign here, rather than having everyone chuck syntax at the wall independently.

@glaebhoerl
Copy link
Contributor Author

@bstrie

It is widely acknowledged that function signatures (and typaram declarations specifically) are a problem, but this does nothing to solve any of the verbosity that we currently suffer (it makes it worse, in fact). We need a more widespread and cohesive redesign here, rather than having everyone chuck syntax at the wall independently.

I suspect, but am not sure, that you might be misreading the proposal. The motivation has nothing to do with solving the "problem" of function signatures and typaram declarations, and the RFC isn't proposing any change to them.

The motivation is only to (a) make the syntax for higher-rank types a bit more obvious and (b) suggest for as the keyword for introducing universal quantification for those cases where one is desired or necessary. The two are related by the fact that the former is the one and only instance in the current language of the latter.

The only proposed change to the current language is to the syntax of higher-rank closure types. To repeat the example from the RFC:

Before:

<'x> |&'x A| -> &'x B

After:

for<'x> |&'x A| -> &'x B

RFC PR #122 was only brought up as another example where such a keyword would be appropriate if we were to adopt it.

(This kind of thing - an example to clarify the proposal or its motivation getting confused for the proposal itself - seems to be a recurrent problem with my RFCs. I guess I need to make this even more explicit in the future.)

@glaebhoerl
Copy link
Contributor Author

@jfager

adding more characters

Higher-rank lifetimes seem like an excellent place to add more characters if it makes them more distinctive / makes them easier to read / makes their meaning clearer. They're going to be a new and unfamiliar concept to the vast majority of people, so clear and distinctive is good, and occur infrequently, so verbosity is not a significant issue.

@glaebhoerl
Copy link
Contributor Author

And because we're supposed to respond to things from the recommended-for-discussion-at-meeting emails in the PR comments instead of to the email, even though I still feel strange doing this:

#157 - Use for to introduce universal quantification - glaebhoerl
Use for rather than <...> syntax for type-parametric items.
Not much feedback, some discussion.
Recommend close - we're not up for changing the syntax of Rust in such a fundamental way at this stage and want to keep with the curly-brace-language heritage.

Once again this is a fundamental misreading of the proposal. I refer you to my previous response to @bstrie.

@nrc
Copy link
Member

nrc commented Jul 13, 2014

@glaebhoerl ah, apologies for misreading the proposal. I got the wrong impression from the title and summary and skimming the comments. I'll have a proper read through (as advice, I would say that the smaller the effect of an RFC the more likely it is to be accepted, so you should write your title and summary to give a clear indication of the scope of the changes. In this case, the reader does not find out that the proposal only applies to closures and not all functions until line 28, by which point I had given up, assuming (presumptuously) it would never be accepted and there was no point in spending more time).

@brson
Copy link
Contributor

brson commented Jul 17, 2014

Thank you for this proposal. Although closures have a lot of knobs to tweak, we are reasonably happy with the current syntax. Closing.

@brson brson closed this Jul 17, 2014
@glaebhoerl
Copy link
Contributor Author

Although closures have a lot of knobs to tweak, we are reasonably happy with the current syntax.

Just to clarify:

You (plural) don't think the proposed change (<'a> |&'a Foo| -> for<'a> |&'a Foo|) is an improvement, or you don't think it's an improvement worth making?

@liigo
Copy link
Contributor

liigo commented Jul 20, 2014

Unreadable, not improvement

@glaebhoerl
Copy link
Contributor Author

@liigo My question was addressed to @brson and anyone else who was involved in the determination.

withoutboats pushed a commit to withoutboats/rfcs that referenced this pull request Jan 15, 2017
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants