Skip to content
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 and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Remove the ' from lifetime parameters #134

Closed

Conversation

pcwalton
Copy link
Contributor

  • Start Date: 2014-06-23
  • RFC PR #: (leave this empty)
  • Rust Issue #: (leave this empty)

Summary

Remove the ' from lifetime parameters. Instead, infer whether each generic parameter is a lifetime or a type.

Motivation

As punctuation, the ' notation is visually noisy, and it turns out to be unnecessary for both the compiler and the reader. The compiler can infer whether each generic parameter is a lifetime or a type parameter from its use, and a reader can infer the identity of a generic parameter from its case.

' as a generic parameter comes from the ML syntactic tradition, which is quite different from that of C. In particular, the overloading of ' to mean both characters and lifetimes can be jarring for anyone not used to OCaml or Perl 4. And mixing of ML-style ' generics and C++-style <> generics is entirely without precedent.

This has been presented (by some members of the Chromium team) as a particularly egregious example:

fn get_mut<'a>(&'a mut self) -> &'a mut T;

With the ' dropped, this becomes significantly less noisy:

fn get_mut<a>(&a mut self) -> &a mut T;

Detailed design

We replace the LIFETIME token with the IDENT token in all productions in the grammar. This will affect type parameters, reference types, and labels.

When determining the semantics of a type declaration, the compiler looks for uses of each generic parameter within <> to ascertain its identity (type parameter or lifetime):

  • If the generic parameter is bounded, it is a type parameter.
  • If the generic parameter is used after an &, it is a lifetime.
  • If the generic parameter is used as a type, it is a type parameter.
  • If the generic parameter is used in a lifetime position in a type's generic parameter, it is a lifetime parameter.
  • Otherwise, the generic parameter is a type parameter. (Note that these rules mean that phantom—unused—parameters become type parameters.)

The labeled block syntax is unambiguous because we have solved the ambiguity between structure literals and labeled statements by syntactically restricting the positions in which structure literal expressions may be used per Rust PR #14885.

A lint pass will be added that warns if lifetimes do not begin with a lowercase letter or if type parameters do begin with a lowercase letter. This is important because code that does not maintain this style may mislead readers (though not the compiler).

Drawbacks

  • Syntax highlighters will have a more difficult time determining the difference between lifetimes and type parameters, because lifetimes will no longer constitute a distinct lexical class.
  • It may be more difficult for casual readers to tell the difference between lifetimes and type parameters at a glance, because case is not as lexically distinctive as punctuation.
  • Phantom lifetimes will no longer work, though they will continue to work via marker types.
  • Loop labels will shadow variable names, and vice versa. This is fallout from the way the macro hygiene algorithm works.

Alternatives

The impact of not doing this is that the drawbacks noted in "Motivation" above will persist.

Unresolved questions

None.

@emberian
Copy link
Member

I'm in favor. It looks cleaner in all the cases I've considered.

@o11c
Copy link
Contributor

o11c commented Jun 23, 2014

What about: fn get_mut<a: Lifetime>(&a mut self) -> &a mut T;

@bachm
Copy link

bachm commented Jun 23, 2014

Or fn get_mut<'a>(&a mut self) -> &a mut T;

(just to add an alternative to the discussion - not to express disapproval)

@mcpherrinm
Copy link

IMHO the best way to reduce lifetime noise is to unify variable names and lifetimes:

fn(x: &T) -> &'x Y { ... }

I haven't thought about this too much, so I'm not sure if it would work outside the context of function signatures, but it seems to work very well there.

Combined with dropping the ' elsewhere, this would allow 'x to mention a variable name as a lifetime.

@steveklabnik
Copy link
Member

I like this for two reasons:

  1. unmatched quotes make my eyes twitch, and many other peoples' too.
  2. lifetimes are part of the type. Makes sense that they'd look the same.

@thehydroimpulse
Copy link

+1. I definitely think this will help with the noise aspect (although, I didn't mind the ' syntax tbh). If there's a convention to use lowercased letters (like it currently is), then I'm in favour of it.

@pnkfelix
Copy link
Member

we may want syntax for explicit bounds on lifetimes, in order to deal with issues like rust-lang/rust#13703

i.e. something like this might be needed at some point:

fn foo<'a, 'b: 'a>(...) { ... }

That could conflict with this rule from above (from the first bullet): "If the generic parameter is bounded, it is a type parameter." (But maybe that condition is not necessary to preserve, I have not thought too hard about it.) Or maybe we would express that has fn foo<a, b: LifetimeOutliving<a>>(...) { ... }

@o11c
Copy link
Contributor

o11c commented Jun 23, 2014

@mcpherrinm that fails for structs that need to take a lifetime as a parameter, but for which you don't have a variable

e.g. fn frob<'a>(v: Option<& 'a Foo>) -> Option<&'a Bar>

Edit: stupid github not autocompleting reliably ... stupid people with one letter difference between IRC nick and github nick ...

@mcpherrinm
Copy link

@o11c Yeah, it definitely doesn't work in all cases (and may only work in the one specific case I presented). As I said, I haven't thought too hard about making that idea work. I don't think it really affects this RFC meaningfully so it probably doesn't merit further noise in this discussion.

@netvl
Copy link

netvl commented Jun 23, 2014

I don't like this. Lifetimes parameters and type parameters are different and not interchangeable, so they have to differ syntactically. &'a looks nicer than &a, IMO. For me, the presented drawbacks are heavier than advantages.


# Drawbacks

* Syntax highlighters will have a more difficult time determining the difference between lifetimes and type parameters, because lifetimes will no longer constitute a distinct lexical class.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a really major concern. Visual distinction of lifetime parameters via syntax coloring is very helpful. You said here that syntax highlighters will have a "more difficult time", but I'm inclined to say that they simply cannot tell the difference as long as they're based on simple parsing rules. Determining the difference will require either using libsyntax to actually do the parsing (which is rather at odds with the normal goal of highlighting incomplete or buggy code) or reimplementing its logic for determining the role of each parameter. And that's not something most editors are capable of doing (for example, I don't see how Vim could ever highlight a lifetime).

@glaebhoerl
Copy link
Contributor

I agree with the motivation. I find the single-quote ' syntax in the C-like context of the rest of the language to be jarring as well (albeit less so than the earlier / syntax).

If the generic parameter is used after an &, it is a lifetime.

I'm assuming that "if it is then followed by a type" is implied?

Can we also disambiguate term-level code like let c: &int = &a b;, where a is a lifetime?

An alternative implementation:

We could turn our capitalization conventions into hard rules (I think we should do this anyway), and then we can determine whether a parameter is a type parameter or a lifetime parameter by simply observing whether or not it is capitalized. The term level (see example above) would still be tricky.

@lilyball
Copy link
Contributor

I agree with @netvl. I'm inclined to say I don't like this change, and not just for the syntax highlighting reason I already commented about.

I like @mcpherrinm's suggestion, which I would have made if he had not done so already, although his use of fn(&x: T) is a bit backwards. I would suggest merely that if any lifetimes are used in a function without being declared, then the function's arguments are searched for a matching argument. The argument must have a type &T, and the lifetime is then associated with the &. That would make it

fn foo(x: &T) -> &'a Y;

Or, perhaps more commonly,

fn get_mut(&mut self) -> &'self mut T;

I think this is less verbose and more readable than fn get_mut<a>(&a mut self) -> &a mut T.

And of course this is merely an addition to the current rules, so you can still declare your 'a lifetimes anywhere that this rule doesn't apply.


Besides this, one thing to consider would be if there's a different syntax for lifetime's that's just as concise but doesn't have the issues that 'a does (namely, confusion with character literals, or being annoyingly with auto-balancing editors that insert the closing ').

@dobkeratops
Copy link

What about HKT in future: would it be possible to carry lifetime information in borrowed smart pointer types.
Could that qualify as another way of 'specifying lifetime information thats' less visually jaring'.. in that we already write Box, Rc as pointer types.

fn foo<'a,'b,T>(x:&'a T ,  y:&'a T,z:&'b T) -> &'a T 
fn foo<ra,rb,T>(x:ra<T> ,  y:ra<T>,z:rb<T>) -> ra<T> 

ra<T>  // 5 chars
&'a T  // 5 chars

I'd probably prefer to stick with & (the anonymous lifetime case &T is a lot nicer than r<T> would be ) , but, i certainly found ' visually jarring when i first saw it and ran into the issue with text editors thinking its' a string literal.
One thing thing thats' jarring is the use of a space between the & and the variable it refers to.

any problem solving (syntax highlighting, IDE assists) applied to generics would carry over.

I even wondered if 'ints in type system' could work with lifetimes, imagine if there's a way to get the nesting level as an int, could you write expressions on that.

@pcwalton
Copy link
Contributor Author

Lifetimes parameters and type parameters are different and not interchangeable, so they have to differ syntactically.

They do differ syntactically. By case.

@pcwalton
Copy link
Contributor Author

I would suggest merely that if any lifetimes are used in a function without being declared, then the function's arguments are searched for a matching argument.

I think this would make lifetimes more confusing, because you'd end up seeing the ' syntax anyway when you deal with lifetime-parameterized types. (For your self example, what if Self is itself lifetime-parameterized? The way the syntax works now is at least explicit and consistent.)

Could that qualify as another way of 'writing lifetime parameters thats' less visually jaring'.. in that we already write Box, Rc as pointer types.

Like kballard's suggestion above, this does not handle lifetime-parameterized types well.

Besides this, one thing to consider would be if there's a different syntax for lifetime's that's just as concise but doesn't have the issues that 'a does (namely, confusion with character literals, or being annoyingly with auto-balancing editors that insert the closing ').

There is one. The case convention proposed here. :)

For those bringing up syntax highlighting, remember that we don't syntax highlight type parameters either. Yet nobody is proposing a sigil for type parameters, because that would almost certainly be too noisy. This just makes lifetime parameters consistent with type parameters.

@bill-myers
Copy link

Why not instead create, for each variable, a lifetime of the same name that is the intersection of all lifetimes in the variable type?

Then the example just becomes

fn get_mut(&mut self) -> &'self mut T;

which I suspect is the way most people mentally think of the example declaration anyway.

Regarding the proposal, the thing is that variables and types also don't need to be distinguished, yet they are by snake_case vs PascalCase, and there is no case convention left for single-letter lifetimes (t is a variable and T is a type, there is no third case).

Unless we are crazy enough to use greek letters (problem of that is of course that barring copy&paste, a custom keyboard layout is needed to type them efficiently). For the record, it would look like this:

fn get_mut<α>(&α mut self) -> &α mut T;

@pcwalton
Copy link
Contributor Author

Why not instead create, for each variable, a lifetime of the same name that is the intersection of all lifetimes in the variable type?

I think this would add complexity to the lifetime system.

variables and types also don't need to be distinguished, yet they are by snake_case vs PascalCase, and there is no case convention left for single-letter lifetimes (t is a variable and T is a type, there is no third case).

Types and variables are in separate syntactic positions and separate namespaces. Types and enum variants are both in CamelCase, yet this has rarely been a source of confusion.

Unless we are crazy enough to use greek letters (problem of that is of course that barring copy&paste, a custom keyboard layout is needed to type them efficiently). For the record, it would look like this:

This proposal in fact supports that.

@bill-myers
Copy link

I think this would add complexity to the lifetime system.

Yes, although it's probably easier to understand a direct "the return value the lifetime of the receiver" than "the return value and the receiver have both lifetime 'a, so 'a will be inferred to be the lifetime of the receiver, so the return value has the lifetime of the receiver" which are the deductions one must mentally make with the current syntax to be able to understand how to use it.

Types and enum variants are both in CamelCase

Well, enum variants are types in a natural extension of the Rust type system, which of course is not the case for lifetimes or variables, so it's not quite the same.

@smosher
Copy link

smosher commented Jun 24, 2014

This has been presented (by some members of the Chromium team) as a particularly egregious example

Is this a valid motivation? Are they taking potshots or are they genuinely interested in using Rust? If the latter, has this change been run past them? Is this considerably less egregious to them?

It isn't to me, in fact it's worse. The unfortunate thing is you have the same lifetime appear thrice in an otherwise simple signature. Removing the tick makes the lifetime harder to scan past, introduces a naming conflict for the sake of a syntax change but doesn't alter the fact that the lifetime shows up three times. Inferred lifetimes made a lot of this go away and, if I recall correctly, solved this case neatly. But it was agreed that being explicit was better. We hated /-notation, and rejoiced at 'lt after our eyes came into focus surprisingly quickly. I doubt it's the tick's fault. I think we'll meet resistance as long as we have explicit lifetimes.

At the risk of sounding newbie-hostile (quite the opposite in fact), I argue that optimizing for the aesthetics of those new to the language is a dead-end road. You can't write good code until you understand the language sufficiently well and at that point seeing 'lt isn't scary. Papering over things that look ugly to the new, yet are concrete divergences from what they understand can only be a disservice. The fact is the lifetime has to be there and it's not in the C programmer's glossary. Going the other way, I have heard complaints that Rust looks too much like the worst of C++ template messes. It doesn't, but some people will make that complaint as soon as they see <T>.

tl;dr - Nothing about the motivation rings true to me. I have a preference for being able to scan/scan past lifetimes easily in signatures. And there are drawbacks. Instead of just being harder to read for people new to the language, I would turn that around and say this proposal makes it easier to read for virtually no-one at all, save those who refuse to read 'lt.

@pcwalton
Copy link
Contributor Author

But a lexical distinction remains, namely case. So I don't see this as comparable to the changes to remove inference. In practice this will be exactly as explicit as today.

@lilyball
Copy link
Contributor

@pcwalton Case is not a sufficient lexical distinction to use when manually tokenizing code with your eyes. After all, when glancing past &a, is that a lifetime, or is that a reference to a variable named a? You need more context than just the token to figure that out.

@pcwalton
Copy link
Contributor Author

I don't think it's a big deal as long as the case distinctions are within one nonterminal/namespace. For instance, as I mentioned above, we already use the same case conventions between type parameters and constants and between types and enum variants. (We actually used to use a sigil to separate the latter two, and we removed it in favor of inference, a decision that was heavily resisted at the time but was obviously the correct one in retrospect.)

@smosher
Copy link

smosher commented Jun 24, 2014

But a lexical distinction remains, namely case. So I don't see this as comparable to the changes to remove inference. In practice this will be exactly as explicit as today.

Sure, but I'm not arguing any comparison between this change and removal of inferred lifetimes.

The point about inferred lifetimes (which I don't think anyone really wants) is that it is the kind of thing needed to satisfy everyone unfamiliar with the language. I still doubt that anyone put off by 'lt is going to be satisfied by the change proposed here. I doubt the operating theory behind this change. I won't be convinced without data from the vocal objectors [edit] of the current syntax:

  • Is this change considerably better?
  • Is it the tick itself?
  • Is having a sigil in the marker a problem?
  • Would subbing dot (or whatever) for tick be roughly as good as this change?

Lexical distinction in the form of case is fine for a compiler, but it doesn't pop for me the way a tick does. As much as I don't like the change, my preference isn't my main concern. It's the unknown effectiveness of the change versus the costs listed.

But is it even fine for the compiler? Why should this change cause interaction between loop labels and variable names, the explanation being interaction with yet another part of the system? I mean, why has nobody batted an eye at that? I'm not saying we need to name loops and variables the same, but it sounds fragile. (This bit isn't really about the proposed change, except maybe we shouldn't be putting stress on the fragile bits.)

@lilyball
Copy link
Contributor

Honestly, the inferred lifetime thing is really just to reduce typing. I don't think it affects readability in the slightest.

@chris-morgan
Copy link
Member

I presume that the complaint by the Chromium team that you are referring to is https://twitter.com/damienmiller/status/476207923702423552:

Rust's designers sure screwed up on readability.

pub fn inner<'a>(&'a mut self) -> &'a mut R {
    &mut self.h.r
}

Strong +1 on what @mcpherrinm voiced first, that this could be improved by being able to use variable names automatically as lifetimes, which permits what I am sure is the most common case:

pub fn inner(&mut self) -> &'self mut R {
    &mut self.h.r
}

As for removing the single quotation mark, I’m ambivalent about that. Overall I don’t think I like it at present, but I’d want to wait longer before deciding that definitely.


With the ' dropped, this becomes significantly less noisy:

Significantly less noisy!? Selection bias, of course, as I already know Rust, but the removal of those three characters makes it harder for me to parse it. Now @mcpherrinm’s suggestion is “significantly less noisy”, and every bit as explicit.


At present, lifetime parameters are hidden from types in most error messages. This, incidentally, is a source of enormous pain to people starting out with lifetimes as it renders some of the error messages that they care about most useless, as they complain about type T not being the same as type T—each one just having different lifetime parameters, perhaps. This attitude becomes, I think, less tenable once lifetime parameters are even using the same syntax.

Currently lifetime parameters must come first in type parameter lists. This restriction appears to be removed under this proposal.

Closures of the form 'lifetime |…| …: seems to me that they’re going to suffer with this. (If a syntax highlighter, for example, does not distinguish between types and expressions—which most don’t—the lifetime cannot be distinguished as it may require arbitrary lookahead; in the probably-flawed example of T ( lifetime | foo , bar , baz | -> T), it’s only when you finally get to the -> token that you know that lifetime was a lifetime.)

Labels on loops, 'label: loop { break 'label; }: well, I guess they’ll work with just an identifier there.


But a lexical distinction remains, namely case. So I don't see this as comparable to the changes to remove inference. In practice this will be exactly as explicit as today.

@pcwalton: I can only accept this as a valid argument if case is enforced: that types must be upper-case and lifetimes must be lower-case. Otherwise this distinction is not truly there.


For syntax highlighting, I do perceive a technique that will satisfy most cases: if you have an ampersand followed by a word other than mut, followed by another word, that first word is a lifetime.

Labels can be highlighted by a separate rule with no difficulties (in fact, they can be highlighted as Label in Vim, which would be an improvement—not that we couldn’t do that already, if we desired.

But these things does not satisfy highlighting inside type parameters, nor for closures, nor can it do much for macros. Remember that ease of syntax highlighting is in many ways a good proxy of readability. Here we have a change which makes general syntax highlighting of what is a distinct concept impossible, though the most common cases are possible, without semantic parsing of the structure of the language: it must know where lifetimes are permissible, which, among other things, includes making distinction between types and expressions in a way that hitherto has not been necessary (I will admit that that part of the argument alone is moderately weak).

(Side thought, distinctly off-topic: by using librustc, actually running all the macros, and seeing what each token is parsed as, can one provide general syntax highlighting in macros?)


I am surprised to find that 'static has not been mentioned at all yet; will it be the case, then, that static can be a bound, e.g. T + static + Clone?

@pcwalton
Copy link
Contributor Author

this could be improved by being able to use variable names automatically as lifetimes, which permits what I am sure is the most common case:

As I've noted, this doesn't work very well with lifetime-parameterized types. I know everyone wants this but we internally debated this years ago and decided it didn't work. Furthermore, it preserves the unnatural-looking '.

Significantly less noisy!? Selection bias, of course, as I already know Rust, but the removal of those three characters makes it harder for me to parse it. Now @mcpherrinm’s suggestion is “significantly less noisy”, and every bit as explicit.

I disagree. I think that anything with ' is not much of an improvement, and it's a significant improvement in readability to not have the '.

That suggestion is also less explicit, again because of lifetime-parameterized types. You could solve it by making the inferred region the intersection of any reference lifetimes and any type parameters, but that's adding a lot of complexity and magic and is also no longer explicit. You are only thinking of easy cases; consider something like x: (&'a Foo<'b>, &'c &'d Vec<Bar<'e>>) (which would become x: (&a Foo<b>, &c &d Vec<Bar<e>>), which is much easier on my eyes).

Currently lifetime parameters must come first in type parameter lists. This restriction appears to be removed under this proposal.

No, I wouldn't remove this restriction.

I am surprised to find that 'static has not been mentioned at all yet; will it be the case, then, that static can be a bound, e.g. T + static + Clone?

Yes. static is a keyword, so it's not a problem.

@pcwalton: I can only accept this as a valid argument if case is enforced: that types must be upper-case and lifetimes must be lower-case. Otherwise this distinction is not truly there.

I am totally fine with enforcing the case conventions, actually. I didn't bring it up because I felt it would be too controversial and getting away from C syntax.

@bstrie
Copy link
Contributor

bstrie commented Jun 24, 2014

We could turn our capitalization conventions into hard rules

-1 to any hard capitalization rule. It would prevent us from ever allowing identifiers to be written in non-Western languages.

@lilyball
Copy link
Contributor

this could be improved by being able to use variable names automatically as lifetimes, which permits what I am sure is the most common case:

As I've noted, this doesn't work very well with lifetime-parameterized types. I know everyone wants this but we internally debated this years ago and decided it didn't work. Furthermore, it preserves the unnatural-looking '.

I don't understand why the fact that this rule wouldn't apply to lifetime-parameterized types means the rule is not useful. The vast majority of lifetimes (at least, in my experience) would be able to use this rule. Sure, some lifetimes would still have to be explicitly declared, but nobody is saying they wouldn't.

@mjburgess
Copy link

"And there's no reason to believe that random people you find who dislike ' will find case to be any better"

Except a thread full of people saying exactly this? I have been consistently pushed away from Rust after seeing heaps of syntactic noise up front. A lot of the responses have been "theyre not heavy users, what do they know!" but, arent non-users the people you're trying to attract? If you make a language look complex, detailed and intimidating no one is going to use it.

I am quite serious when I say this kind of noise is turning off a lot of people. The intimidation-factor behind a language is very important for its adoption, and syntax is a very big part of that.

@huonw
Copy link
Member

huonw commented Jul 1, 2014

FWIW, just a general point (not specific to ', or any particular comment made above) that may've been made before: people who hate the syntax are more likely to pipe up with a complaint (on github, reddit, HN, etc.), those who don't care or even like it will mostly just continue their day without making any comment at all, so there's a (possibly small?) inherent bias to consider.

@asb
Copy link

asb commented Jul 1, 2014

I agree with @huonw. Additionally, although many have expressed a dislike of the syntax, referring to examples that include the 'a lifetime syntax, very few have indicated they would prefer a version where lifetimes are not prefixed with '. This is an untested assumption.

@mjburgess
Copy link

I'm always more inclined to weight decision making by level-of-interest/caring. If people do not care, what do they matter either way? There is no barrier to entry to the discussion (a free github account...).

If you're concerned about representing the interests of the entire user base then the thing to do is publicize the issue to them, not have this discussion in a clairvoyant manner try to guess what the tastes of the people who dont care are.

@conradkleinespel
Copy link

For me, the sigils is why I first liked Rust. It looked unique and fun.

What puts me off in a language is things like lack of static typing or
unintuitive automatic type conversions. Not a sigil. Honestly, I
preferred ~"boxed string" to the new "boxed string".to_string().

On Tue, Jul 1, 2014, at 11:07 AM, Michael John Burgess wrote:

"And there's no reason to believe that random people you find who dislike
' will find case to be any better"

Except a thread full of people saying exactly this? I have been
consistently pushed away from Rust after seeing heaps of syntactic noise
up front. A lot of the responses have been "theyre not heavy users, what
do they know!" but, arent non-users the people you're trying to attract?
If you make a language look complex, detailed and intimidating no one is
going to use it.

I am quite serious when I say this kind of noise is turning off a lot of
people. The intimidation-factor behind a language is very important for
its adoption, and syntax is a very big part of that.


Reply to this email directly or view it on GitHub:
#134 (comment)

@Thiez
Copy link

Thiez commented Jul 1, 2014

It seems to me that the rust community was growing quite rapidly even back when we still had more sigils (~ and @) so they can't be all that off-putting. At the end of the day you can't please everyone, and lifetimes are always going to be something strange and difficult for newcomers. I think trying to hide them by removing ' will ultimately make them more difficult.

@simias
Copy link

simias commented Jul 1, 2014

For me the "weird" syntax for lifetimes (out of place for a language that took a lot from the C syntax) helped me understand that they were something different that needed deeper investigation. As others have pointed out, lifetime annotations are not found in python, C or Java, so in my opinion it's no use to pretend "nothing to see here, move along" to newcomers.

Lifetimes are something you need to understand in order to use Rust effectively and blurring the distinction between types and lifetimes in declarations is not going to help that (the distinction between 'a and T is greater than between a and T IMHO, you know it's not just some weird coding convention, 'a and T are obviously different things, even if you don't know what yet).

Even Python uses sigils for certain things like function decorators. Lisp and its famously simple syntax uses ' as a shorthand for the quote operator.

So I think after reading this entire thread I'll side with the people saying that lifetimes annotations should be removed when they can be inferred. And when they can't it's no use pretending they're not weird. They are weird for 99% of the coders out there and that's part of what makes Rust interesting.

Alternatively, if sigils are really an issue, I like the idea of having a "scope" keyword instead. Slightly more verbose but also much more explicit and (perhaps most importantly) google-able. Again, the verbosity wouldn't be much of an issue if the need for lifetime annotations is removed in the vast majority of cases.

@mjburgess
Copy link

When did removing/replacing ' become the same as dooming newcomers to rust to confusion and complacency about lifetimes? I think most of the tutorials ive ever read about rust start with a discussion of ownership and lifetimes... I dont think an unclosed quote littered throughout source code has anything to do with whether a person will learn about a language feature or not. The danger here is Ugly == Important.

Importance is very difficult to build into language design. Everything is important, must everything "stand out". IF so We''RE l.e.f.t. with A languageWhich MAKES EVERYTHING unread able.

Readability and a flow aesthetic which makes readability paramount has been time-and-again the right decision for syntax choices. Learning the language cannot be substituted by using its syntax to clobber people over the head.

@schmee schmee mentioned this pull request Jul 1, 2014
@bluss
Copy link
Member

bluss commented Jul 1, 2014

@kballard's comment #134 (comment)

Lifetimes are omitted today where they have very simple inference (No relations to other references or values at all).

In spite of this, I prefer simplifying lifetime syntax instead of removing (inferring) in yet more cases: Making lifetime ties between input and output parameters inferred and thus invisible would be very confusing I think.

@Valloric
Copy link

Valloric commented Jul 6, 2014

Removing ' from lifetime params would improve readability for newcomers to Rust. I know several people who I've tried to introduce to Rust who have balked upon seeing ' in the lifetimes (comments like "oh great they're taking readability cues from Perl" were unfortunately common). I know I personally also hated seeing it, although now I've gotten completely used to it... which I think is the root of the objections. People commenting against the removal of ' have all gotten used to it; it looks "normal" and familiar. This change is aimed at making Rust syntax more palatable to those new to the language which none of us here probably are.

I also agree with @pcwalton's point that people would be universally against introducing ' for lifetime params (because of extra noise) had the language started without it. And yes, ' looks completely out of place as part of a param name in a modern language.

Further, #141—while a great idea on its own—is completely orthogonal to this issue. Both RFCs should be evaluated independently (and IMO accepted).

@pczarn
Copy link

pczarn commented Jul 13, 2014

So I was thinking about parameterizing over mutability. Then I realized that @bstrie's proposal could make it really simple in terms of syntax. Keep in mind that the let x = &'a ...; syntax seems to be gone.
This is how I'd like to parameterize a function over all properties of a borrow:

fn get<a&m>(a&m self) -> a&m T {
    &m self.field
}

And this syntax for lifetime parameters alone emerges from the above:

fn foo<a&>(bar: &T, baz: a&T) -> a&T;

@lilyball
Copy link
Contributor

@pczarn That's really quite unreadable.

@errordeveloper
Copy link

The ' sigil does feel quite right, perhaps replacing it with something else, e.g. # would be better?

fn get_mut<#a>(&#a mut self) -> &#a mut T;

@cburgdorf
Copy link

I also think the sigil is right especially since most lifetimes are automatically inferred by the compiler so they don't have to be written by the developer.

Why not use a $ sign as character? The dollar sign has a history for it's usage in programming languages (BASIC, Pascal, PHP).

fn get_mut<$a>(&$a mut self) -> &$a mut T;

@lilyball
Copy link
Contributor

Given the recent work to allow inferring of a lot more lifetimes, perhaps we should suspend any discussion on this RFC until we see how often people will still end up typing lifetimes.

@cburgdorf
Copy link

@kballard I know what you mean but I still see the problem of thousands of ugly syntax-highlighted StackOverflow questions. I don't think this is going away because the syntax is also used in error messages etc.

Take a look at any StackOverflow question with Rust code that scratches lifetime issues. They are all formatted poorly because the syntax highlighting confuses Rust lifetimes with strings.

http://stackoverflow.com/questions/17490716/lifetimes-in-rust

@errordeveloper
Copy link

Syntax highlighters are not something worse discussing here. Rust syntax has evolved and will continue to evolve, people will need to update their Rust code and so they will need to update syntax highlighters.

@errordeveloper
Copy link

The point is that ' is not great and would be nice to change for something that doesn't stick out above a lower-case character.

@cburgdorf
Copy link

@errordeveloper I think the syntax highlighting issue is pretty much the only thing that makes me support a change. Sure you can tell everyone to update their syntax highlighting but given that ' is almost exclusively used for strings and code is posted to hundred of websites (StackOverflow, wordpress etc. pp) I think it is worth to be considered.

@lilyball
Copy link
Contributor

The syntax highlighter used on StackOverflow (which is apparently google-code-prettify) needs to be updated to handle lifetimes correctly. That's not an issue that requires fixing on Rust, it can be trivially fixed in the highlighter.

Note that StackOverflow does not apply generic code highlighting but instead highlights code blocks for specific languages. The language is usually inferred from the tags on the post, but can also be specified explicitly with a particular syntax (using an HTML comment, I always forget exactly how). This means that there is no concern about some sort of generic highlighting getting it wrong for Rust, the only problem is that the Rust-specific highlighter is apparently not very good.

@errordeveloper
Copy link

#bikeshed

@brson
Copy link
Contributor

brson commented Jul 22, 2014

Closing. Although improving the ergonomics of the language is an important topic and we're going to continue making improvements in this area, this specific proposal is not going to happen.

@brson brson closed this Jul 22, 2014
@mjburgess
Copy link

If it makes any difference I gave up on rust finally after trying to write some ML stuff in it. The syntax was the issue.

@ticki
Copy link
Contributor

ticki commented Dec 7, 2015

It's still possible to introduce this change while having backwards compatibility, by allowing ' in the lifetime namespace (or even ignoring it).

withoutboats pushed a commit to withoutboats/rfcs that referenced this pull request Jan 15, 2017
[RFC] Add an unordered buffer stream adapter.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.