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: Add pub fn identity<T>(x: T) -> T { x } to core::convert #2306

Merged
merged 7 commits into from
Aug 19, 2018

Conversation

Centril
Copy link
Contributor

@Centril Centril commented Jan 19, 2018

RENDERED

TRACKING ISSUE


Adds an identity function pub fn identity<T>(x: T) -> T { x } as core::convert::identity.
The function is also re-exported to std::convert::identity as well as the prelude of
both libcore and libstd.


Linking rust-lang/rust#47562
cc @bluss @Manishearth

@Centril Centril added the T-libs-api Relevant to the library API team, which will review and decide on the RFC. label Jan 19, 2018

### Using `id` to concatenate an iterator of iterators

Given the law `join = (>>= id)`, we use the identity function to perform
Copy link
Member

Choose a reason for hiding this comment

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

This sentence needlessly complicates a simple operation; I don't see any use of including the monad reference

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The operation .flat_map(id) is equivalent to join and may have some use for Haskllers who are reading. I can make the used syntax more Rusty tho.

Copy link
Member

Choose a reason for hiding this comment

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

I mean, don't mention monad at all. Rust doesn't typically use that term. There is no reason to include it here. You're writing for Rustaceans, not Haskellers, just say "flatten" and "flat_map"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm trying to choose my battles here =) I tried to come up with a compromise solution... But I don't like the "don't mention the M word" attitude in general.. Rustaceans say "and_then", "flat_map", etc... but they may also say bind, "monad", and "join" at times since Rustaceans are a diverse group and some of them come from Haskell, Scala, F# and other such places. Also, I don't think that shying away from the word Monad helps learnability.

Copy link
Member

Choose a reason for hiding this comment

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

No, that's the point. You aren't optimizing for Haskellers Rustaceans by using "monad". Haskeller Rustaceans know the Rust terminology perfectly well. You only end up disoptimizing for non-FP Rustaceans.

Rustaceans are a diverse group, but there's an option here that is adequate for all Rustaceans.

This is literally the kind of thing that made folks confused by the pi types RFC. Now, this is at a much smaller scale, but I'm trying to stomp out the attitude of using unfamiliar terminology where not necessary in RFCs as much as possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We have a fundamental disagreement here.

Haskeller Rustaceans know the Rust terminology perfectly well.

Haskeller Rustaceans might not know that particular part of Rust... And nonetheless, there might be non-Rustacean functional programmers that might be interested in reading our RFCs or other documentation at some point. Besides, the current text of the RFC explains it in a way that is adequate for all Rustaceans since it includes the following language as well:

In other words we are concatenating an iterator of iterators into a single iterator,

However, in an effort to not make this RFC block on this disagreement I'll agree to remove the language from the RFC.

# Summary
[summary]: #summary

Adds an identity function `pub fn id<T>(x: T) -> T { x }` as `core::convert::id`.
Copy link
Member

Choose a reason for hiding this comment

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

I feel it should be called identity, id is really short and ambiguous.

Copy link
Contributor

Choose a reason for hiding this comment

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

id has pecedent in other languages like Haskell. I could go either way, but it being short and known as the identity function elsewhere is nice to have.

Copy link
Member

Choose a reason for hiding this comment

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

Identity is a better name in the prelude, if we keep that possibility open. I think we go for not overly abbreviated names of functions in Rust

Copy link
Member

Choose a reason for hiding this comment

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

It's also called identity in Java, which is probably more used than Haskell. Though that function may be used less in Java.

Familiarity arguments work if there's uniformity; there isn't, and it feels like plenty of folks won't have ever consciously noticed/used it, so I'd prefer to optimize for folks who don't know what it is. identity is clear and also should be obvious to those used to id

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Manishearth I've provided this motivation for the naming:

Naming the function identity instead of id is a possibility. However, to make the id function more appetizing than using a |x| x, it is preferrable for the identity function to have a shorter but still clear name.

Why is id ambiguous? Are you referring to a potential ambiguity with "identifier"?
And why is this potential ambiguity an overriding concern to the one I've listed?
I think id is clear from context - If there are other functions around in the context that look like T -> T, you know it's not going to be "identifier"...

Yes - I suspect it is used way less in Java than in Haskell. I prefer to optimize for folks who are most likely to use the operation, which are probably on balance more functional programmers.

Copy link
Contributor Author

@Centril Centril Jan 19, 2018

Choose a reason for hiding this comment

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

I do not find length to be that pressing a concern when it comes to ergonomics.

Just to clarify: it is the relative length I am concerned about, not the absolute. I'd like to encourage people to use id instead of |x| x, but that might be harder with identity... Does that make sense to you?

[..] more short things [..]

Out of curiosity - since you say more short things - which ones are you referring to?

[..] (but I can't articulate why :/ ) [..]

But if you can, that will make your concern more actionable for me =)

Copy link
Member

Choose a reason for hiding this comment

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

My point still stands. identity is more ergonomic than the closure even if it is longer, by virtue of being just an identifier. It also can be used in more contexts because it has the same type as other functions (almost).

I do not think that I'd being shorter than the closure has any benefit. We are rarely trying to optimize for less typing. See also

We already have short functions like drop in the prelude. drop is fine and well known, but adding more feels iffy to me. I feel this is going to clash with locals quite often. Clashes in the prelude are fine, but make things murkier because someone reading the code would expect it to be a local.

(Actually, for that matter there's a general argument to be made against adding functions to the prelude -- there are very few and it's going to be surprising for folks to see a different function that doesn't seem to be imported anywhere. Unless it becomes ubiquitous. Which I suspect it won't.)

Copy link
Contributor Author

@Centril Centril Jan 19, 2018

Choose a reason for hiding this comment

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

I guess I'll change it to identity then by popular demand. What tipped me over was this note by @nox:

88,618 lines with 'id' in Servo.

I think it is necessary and essential that this be in the prelude however and there's certainly precedent for it.

Copy link
Contributor

Choose a reason for hiding this comment

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

How embarrassing.

For the record, I forgot to filter the grep command to only *.rs files and thus it also included our local clone of web-platform-tests, a massive repository of Web tests running in browsers. There are actually only 1,533 lines with the word id in Servo.

That's still a huge number to me though, but nowhere near the one I mistakenly reported at first.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And the function shall henceforth be known as identity.

text/0000-convert-id.md Outdated Show resolved Hide resolved
@Centril Centril changed the title RFC: Add pub fn id<T>(x: T) -> T { x } to core::convert RFC: Add pub fn identity<T>(x: T) -> T { x } to core::convert Jan 19, 2018

It is already possible to do this in user code by:

+ using an identity closure: `|x| x`.
Copy link
Member

Choose a reason for hiding this comment

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

What specific advantages do you see of identity over |x| x? identity is longer, and I think its meaning would be less obvious to most users, as they'd then have to go looking for the definition of a function called identity. I suppose there are potential codegen advantages, but those are small at best.

Copy link
Member

Choose a reason for hiding this comment

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

A previous version of the RFC used id, but it was changed because id is ambiguous and for those who haven't heard of identity functions very non obvious (it's easy to guess what it means if you see "identity", but not "id")

I assert that length is not the defining factor of ergonomics. identity is still easier to read and type over the closure, but I agree that the closure just easier to grok for those who haven't seen this function.

Copy link
Member

Choose a reason for hiding this comment

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

identity is still easier to read and type

I guess that's what I'm disputing, but it's totally a matter of opinion. I'd expect people familiar with Rust's syntax to quickly grok |x| x, while identity could require looking around for a function called identity.

Copy link
Contributor

Choose a reason for hiding this comment

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

I can't speak for everyone, but I always double take when I see |x| x and the way I grok it is by going "oh right it's just the identity function"

Copy link
Contributor Author

@Centril Centril Jan 19, 2018

Choose a reason for hiding this comment

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

@cramertj

[..] I think its meaning would be less obvious to most users [..]

What users are you referring to specifically here? Current Rust users or all programmers in general? I think I believe you are correct in either case, but still - I have no evidence to offer myself that your assertion is correct, which is less than satisfactory.

What specific advantages do you see of identity over |x| x? identity is longer [..]

Now that the length "advantage" (if we believe it is that) of id has been removed with the renaming to identity, I can only offer these thoughts:

  • A lot of functional languages and others have this function, so functional programmers may expect the function to exist while they may be new to the language and don't understand what |x| x means without reading about it. Consistency with those (quite many) languages is an argument on its own.

  • Understanding identity for those that don't already understand (I think functional programmers will) it is a one time cost - this can also be said of closure syntax or any other identifier in the standard library, you have to learn it and that too is a one time setup cost. If you previously didn't know about identity, reading about it can also be a useful experience learning-wise.

  • I believe that using identity is more clearly showing that the identity-conversion was intentional compared to |x| x.

Copy link
Member

Choose a reason for hiding this comment

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

@Centril Thanks for explaining! Those arguments seem reasonable to me. I personally still think that identity is less clear, but I'll leave it to others to voice their opinions one way or another, and I won't object to the feature if general consensus is that it would be beneficial.

@mfarrugi
Copy link

Another argument for the function over the closure is auto-completion, as tools are getting better.

This might may also be an argument for not including it in the prelude, though I haven't seen good support for auto-import in any tools yet.

@Centril
Copy link
Contributor Author

Centril commented Jan 20, 2018

@mfarrugi I like your argument in general, however wrt. this:

This might may also be an argument for not including it in the prelude, though I haven't seen good support for auto-import in any tools yet.

I think that tools should take into account that there is a prelude, and if a user starts writing dro or id or Fr, then drop, identity, and From should be included in the suggestions. So I don't agree that it is an argument against including it in the prelude.

@kennytm
Copy link
Member

kennytm commented Jan 21, 2018

Strong 👎 👎 👎 for adding it to prelude. From #503,

The prelude is used to represent imports that would otherwise occur in nearly all Rust modules.

identity does not satisfy this at all, especially given the examples raised in the RFC. The use cases can be summarized into 3 classes:

  • (Dynamic) function pointer fn(T) -> T
  • .flat_map(identity) as an idiom for concatenation
  • Self-documented code

I don't see how any of these "would otherwise occur in nearly all Rust modules".

Furthermore, the rationale for including identity to prelude is rather weak as well.

the prelude-using variant is considerably shorter. To encourage the use of the function, exporting to the prelude is therefore a good idea.

Yes including it to prelude is shorter, so what? We are not trying to optimize the language for code-golfing. No one is going to avoid identity just because it is not in the prelude. Heck, std::iter::once(x) is the same as Some(x).into_iter(), but I am going to use std::iter::once because this makes the code looks more correct.

drop and other std::convert::* traits are not arguments in favor of identity in prelude.

  • drop is included because it is “One of Rust's fundamental principles is ownership, and understanding movement of types is key to this. The drop function, while a convenience, represents the concept of ownership and relinquishing ownership, so it is included.” (see RFC: Stabilize std::prelude #503). identity does not have a fundamental Rust principle backing it.

  • AsRef, AsMut, From and Into (RFC RFC: Generic conversion traits #529) are included because they do appear as trait bounds almost everywhere.

@Centril
Copy link
Contributor Author

Centril commented Jan 21, 2018

@kennytm

The prelude is used to represent imports that would otherwise occur in nearly all Rust modules.

So I agree that this does not hold for identity. But neither does it hold for drop, at all. But you quote a different rationale for the inclusion of drop namely the that it has a fundamental principle backing it. That may work as a teaching tool and to make dropping clearer than with { x; }, but I believe a simpler rationale is that in fact it is more likely to be used, and we encourage that, if it is in the prelude.

It is not about code golfing - it is about eliminating paper cuts for reaching for a trivial operation that you want to use for clarity. Length matters... I think println!("{:#?}", expr) vs. dbg!(expr) shows this well. The more trivial the operation, the more important that it be easier to use.

Furthermore, you could add to the rationale for inclusion into the prelude that this choice has precedent among other programming languages.

However, if there is consensus around not including it in the prelude, I'll agree to that consensus and change the RFC accordingly.

@kennytm
Copy link
Member

kennytm commented Jan 21, 2018

@Centril println!("{:#?}", expr) vs dbg!(expr) (#2173) is conceptually different: the number of arguments passed to the macro invocation differs. In that RFC they are semantically different as well. Meanwhile std::convert::identity vs identity is just the same thing with different name. The situations are incomparable.

Furthermore, just because drop gets included as prelude for a debatable reason (and thus forever stays due to stability guarantee) it still does mean that is valid for later additions like identity.

it is more likely to be used, and we encourage that, if it is in the prelude.

Prelude should not be an ad-space 😞.

@brendanzab
Copy link
Member

For historical context, Rust used to have a std::util::id function, but that was removed when that module was gutted (rust-lang/rust#7556). Would be nice to see its return at some stage!

@Centril
Copy link
Contributor Author

Centril commented Jan 22, 2018

@kennytm

println!("{:#?}", expr) vs dbg!(expr) (#2173) is conceptually different: the number of arguments passed to the macro invocation differs. In that RFC they are semantically different as well.

The semantic difference was more a later development =) The original frustration was with the longer syntax (that you easily can forget...) =)

Furthermore, just because drop gets included as prelude for a debatable reason (and thus forever stays due to stability guarantee) it still does mean that is valid for later additions like identity.

I guess that's a kind of "two wrongs don't make a right" argument that I accept. But I am not saying that drop was wrong and neither would identity be imo. For me, precedent from other languages is a good argument =)

Comparing the length of these lines, we see that there's not much difference in
length when defining the function yourself or when importing or using an absolute
path. But the prelude-using variant is considerably shorter. To encourage the
use of the function, exporting to the prelude is therefore a good idea.
Copy link
Member

Choose a reason for hiding this comment

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

But the prelude-using variant is considerably shorter.

This is true for literally every possible library addition, so I don't think its a good argument.

### Using `identity` to concatenate an iterator of iterators

We can use the identity function to concatenate an iterator of iterators
into a single iterator.
Copy link
Member

Choose a reason for hiding this comment

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

This section argues to me more that we should have a flatten or concat or something, since I don't find flat_map(identity) any clearer than flat_map(|x| x)—neither conveys the intent, to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, let's do .flatten() =)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And now .flatten() is in your nightly compiler in a day or so. Tracking issue: rust-lang/rust#48213

@KiChjang
Copy link
Member

KiChjang commented Jan 22, 2018

I want to bring up a point where the identity function does have a non-negligible effect in Rust. Due to the affine nature of Rust's type system, the argument passed into the function is being moved into the function body, and then moved back out. As such, the term identity itself is a misnomer -- the value being passed in is not logically identical as the value being returned, and in fact, it's best to think of it as them being two distinct and separate entities, one that gets destroyed/consumed, and one that gets created.

@bluss has a good blog post where they describe the effects of passing ownership into and immediately out of the identity function: https://bluss.github.io/rust/fun/2015/10/11/stuff-the-identity-function-does. In view of that, I'm casting some doubt on whether it is even desirable to this as a core functionality, where its side effects may become a major footgun for newbies who assume that this is similar to other FP's identity function, but run into borrowing issues after using it.

@bluss
Copy link
Member

bluss commented Jan 22, 2018

I think that std::convert::identity would be a useful addition no matter if it is in the prelude or not.

@KiChjang That's mostly trivia and fun. Here's another as a bonus, we already have an identity function in the prelude -- for any type T we have the function T::from of the From<T> trait, which all types implement. However, a real identity function would be useful in far more places, since it is more restricted.

@tbu-
Copy link
Contributor

tbu- commented Jan 25, 2018

Sounds similar to std::move from C++. :)

@phaylon
Copy link

phaylon commented Jan 29, 2018

As someone who has less experience with functional language jargon, if I see identity I'm thinking of a value containing some entity's identity. If I see convert::identity I think about some form of identity conversion. I wonder if something like passthrough would be more descriptive.

@Ixrec
Copy link
Contributor

Ixrec commented Jan 29, 2018

Additional bikeshed datum: To me "identity" first means the identity function (I don't think this has much to do with functional languages, it seems to come up everywhere for me), and second means identity elements in math such as 0 being the additive identity and 1 the multiplicative identity and so on. I would only start thinking about identification of a person or object in the physical world if it was abbreviated to "id", or if we were talking about philosophy for some reason.

Personally I can't come up with a better name for this function than identity.

@Centril
Copy link
Contributor Author

Centril commented Jan 29, 2018

@phaylon

If I see convert::identity I think about some form of identity conversion.

This is an identity conversion =) Move semantics does not change this.
The only thing required for a function to be the identity function is that f(x) = x. This says nothing about whether x can be reused by the caller of f or not.

@scottmcm
Copy link
Member

is that f(x) = x

error[E0382]: use of moved value: `x`
 --> src/main.rs:6:16
  |
6 | identity(x) == x
  |          -     ^ value used here after move
  |          |
  |          value moved here
  |
  = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait

I rather like bluss's moving (since move is a keyword) here, since match identity(current).next feels just as magical as match {current}.next to me. A different name makes it clearer to me that adding or removing the "identity" function changes the behaviour of the program.

@Centril
Copy link
Contributor Author

Centril commented Jan 29, 2018

@scottmcm

error[E0382]: use of moved value: x

I meant f(x) = x in the context of definition, not application.

If and when Haskell adds linear types, they'd just change the definition of id to be:

id :: forall a. a ->. a  --   ->. is the linear arrow
id x = x

and that is fine, since it would still be the identity function.

A different name makes it clearer to me that adding or removing the "identity" function changes the behaviour of the program.

While I sympathize with that goal, I think moving has the major downside of not being the name functional programmers or others looking for the id(entity) function would be searching for, so findability is much lower.

I believe the identity function is also most useful when passed to higher order functions or when stored among other functions in maps, etc. and not when applied directly as identity(x).stuff(). In the context of being passed to a higher order function, moving does not convey intent as well as identity does.

@Centril
Copy link
Contributor Author

Centril commented Jan 29, 2018

I believe at this stage consensus for inclusion into the prelude does not exist and is unlikely to develop. I also do not have more arguments to present in favor of prelude inclusion. Is this an accurate description of where we're at? If so; I move to strike inclusion into the prelude and propose that we simply have core/std::convert::identity. We can always include it in the prelude at a later point in time if we find that it is motivated then.

@eddyb
Copy link
Member

eddyb commented Jan 29, 2018

I'd rather write |x| x, personally, than import identity. And at least in the flat_map case, .flatten() is so much nicer than .flat_map(/* literally anything */) ("why map?").
(That makes me wonder, can we do type FlatMap<I, F> = Flatten<Map<I, F>>;? cc @bluss)

@bluss
Copy link
Member

bluss commented Jan 29, 2018

I agree that .flatten() is so much nicer. We could use that a type alias. When I had a second chance at making flatten() in itertools, I opted to simplify the struct by not implementing the double ended iterator case, because it is almost never used. I even think that simplification was a "benefit of flatten", too.

@brendanzab
Copy link
Member

I worry that encouraging the use of identity literally, instead of conceptually, will just lead to gotchas. Like people being told to rewrite .map(|x| x) to .map(std::convert::identity), and that breaking their program, since we don't have function coercions and that was actually deref'ing &String -> &str, say.

For that I normally use .map(<_>::as_ref) - perhaps those kinds of idioms could be added to the documentation of identity?

@dtolnay
Copy link
Member

dtolnay commented Aug 8, 2018

The libs team discussed this RFC today and those of us present decided we like identity and are on board with providing it in core::convert and std::convert.

We are not sold on including it in the prelude at this point. @Centril please update that part of the RFC per #2306 (comment). Thanks!

While this bakes in nightly we are open to suggestions of a better module to expose this function in (please follow up in the tracking issue if you have ideas), but convert seems reasonable and it should not block stabilization if nothing better comes to us.

@rfcbot fcp merge

@rfcbot
Copy link
Collaborator

rfcbot commented Aug 8, 2018

Team member @dtolnay has proposed to merge this. The next step is review by the rest of the tagged teams:

No concerns currently listed.

Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Currently awaiting signoff of all team members in order to enter the final comment period. disposition-merge This RFC is in PFCP or FCP with a disposition to merge it. labels Aug 8, 2018
@Centril
Copy link
Contributor Author

Centril commented Aug 8, 2018

@dtolnay Done :)

@rfcbot rfcbot added the final-comment-period Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised. label Aug 9, 2018
@rfcbot
Copy link
Collaborator

rfcbot commented Aug 9, 2018

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot rfcbot removed the proposed-final-comment-period Currently awaiting signoff of all team members in order to enter the final comment period. label Aug 9, 2018
@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this RFC. and removed final-comment-period Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised. labels Aug 19, 2018
@rfcbot
Copy link
Collaborator

rfcbot commented Aug 19, 2018

The final comment period, with a disposition to merge, as per the review above, is now complete.

@Centril Centril merged commit cf20ff9 into rust-lang:master Aug 19, 2018
@Centril
Copy link
Contributor Author

Centril commented Aug 19, 2018

Huzzah! This RFC has been merged!

Tracking issue: rust-lang/rust#53500

@Centril Centril deleted the rfc/convert_id branch August 19, 2018 16:19
bors added a commit to rust-lang/rust that referenced this pull request Aug 20, 2018
Add the identity function as core::convert::identity

## New notes

This implements rust-lang/rfcs#2306 (see #53500).

## Old notes (ignore this in new reviews)

Adds the identity function `fn id<T>(x: T) -> T { x }` to core::convert and the prelude.
Some motivations for why this is useful are explained in the doc tests.
Another is that using the identity function instead of `{ x }` or `|x| x` makes it clear that you intended to use an identity conversion on purpose.

The reasoning:
+ behind adding this to `convert` and not `mem` is that this is an identity *conversion*.
+ for adding this to the prelude is that it should be easy enough to use that the ease of writing your own identity function or using a closure `|x| x` doesn't overtake that.

I've separated this out into two feature gates so that the addition to the prelude can be considered and stabilized separately.

cc @bluss
@Centril Centril added the A-conversions Conversion related proposals & ideas label Nov 23, 2018
@pravic
Copy link

pravic commented Jan 17, 2019

Do we need a clippy lint that will point out to |x| x closures in the appropriate Rust versions?

@scottmcm
Copy link
Member

@pravic It would need to be very carefully written to be helpful, I think. It's not uncommon for .map(|x| x) to not be the same as .map(identity), and if it is the correct fix is to remove the map altogether...

@Manishearth
Copy link
Member

That's easy to avoid (we do this for a bunch of lints already), but a more pressing concern is that unless identity is in the prelude it's more annoying to import it as opposed to typing the short closure

@pravic
Copy link

pravic commented Jan 18, 2019

It's not uncommon for .map(|x| x) to not be the same as .map(identity)

@scottmcm Hmm, any examples?

@dtolnay
Copy link
Member

dtolnay commented Jan 18, 2019

fn f(q: Option<!>) -> Option<u8> {
    q.map(|x| x)
}

@Ixrec
Copy link
Contributor

Ixrec commented Jan 18, 2019

It's not uncommon for .map(|x| x) to not be the same as .map(identity)

@scottmcm Hmm, any examples?

More generally: https://bluss.github.io/rust/fun/2015/10/11/stuff-the-identity-function-does/

spikespaz pushed a commit to spikespaz/dotwalk-rs that referenced this pull request Aug 29, 2024
Add the identity function as core::convert::identity

## New notes

This implements rust-lang/rfcs#2306 (see rust-lang/rust#53500).

## Old notes (ignore this in new reviews)

Adds the identity function `fn id<T>(x: T) -> T { x }` to core::convert and the prelude.
Some motivations for why this is useful are explained in the doc tests.
Another is that using the identity function instead of `{ x }` or `|x| x` makes it clear that you intended to use an identity conversion on purpose.

The reasoning:
+ behind adding this to `convert` and not `mem` is that this is an identity *conversion*.
+ for adding this to the prelude is that it should be easy enough to use that the ease of writing your own identity function or using a closure `|x| x` doesn't overtake that.

I've separated this out into two feature gates so that the addition to the prelude can be considered and stabilized separately.

cc @bluss
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-conversions Conversion related proposals & ideas disposition-merge This RFC is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this RFC. T-libs-api Relevant to the library API team, which will review and decide on the RFC.
Projects
None yet
Development

Successfully merging this pull request may close these issues.