rust-lang / libs-team

The home of the library team
Apache License 2.0
115 stars 18 forks source link

ACP: Impl From<&T> for &[T] #305

Closed Bwallker closed 8 months ago

Bwallker commented 9 months ago

Proposal

Add the following trait implementations to librust:

impl From<&T> for &[T] impl From<&mut T> for &mut [T] impl From<&T> for &[T; 1] impl From<&mut T> for &mut [T; 1]

Problem statement

Sometimes when you are working with arrays and slices, it's useful to be able to convert a reference to a T to a slice of T. Currently in stable rust you would have to unsafely construct the slice by calling std::slice::from_raw_parts.

Motivating examples or use cases

Here's one use case I ran into while coding today.

Condider the following program:

fn main() {
  let a = Some(42);
  let b = None;
  let arr = [a, b].map(|v| v.unwrap_or(0));

  let slice: &[i32] = match (a, b) {
    (Some(_), Some(_)) => &arr,
    // Convert &a into &[i32].
    (Some(_), None) => (&a).into(),
    (None, Some(_)) => (&b).into(),
    (None, None) => &[],
  };
  // Do something useful with slice.
  // In my use case it was sending it to a database.
  println!("{slice});
}

Code attapted from: https://github.com/Bwallker/voice-channel-manager/blob/ef8e8528c3a2a4335fa9e964f8d8e7b2d1edcded/src/events.rs#L226-L231

Solution sketch

Add the aforementioned trait implementations.

Alternatives

The above code could be rewritten to call std::slice::from_raw_parts or to collect into a vector. In the specific use case I came up with you could also just slice the array, but they are likely other use cases where this isn't directly possible.

Links and related work

What happens now?

This issue contains an API change proposal (or ACP) and is part of the libs-api team feature lifecycle. Once this issue is filed, the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.

Possible responses

The libs team may respond in various different ways. First, the team will consider the problem (this doesn't require any concrete solution or alternatives to have been proposed):

Second, if there's a concrete solution:

pitaj commented 9 months ago

Why should these be From impls rather than associated functions or free standing functions?

thomcc commented 9 months ago

Currently in stable rust you would have to unsafely construct the slice by calling std::slice::from_raw_parts.

This isn't true, we have core::slice::from_ref and core::array::from_ref (and from_mut for both).

jdahlstrom commented 9 months ago

This isn't true, we have core::slice::from_ref and core::array::from_ref (and from_mut for both).

One might, of course, be inclined to ask if it was really thought that these conversions are so special that they deserve their own names, rather than From impls.

thomcc commented 9 months ago

I suppose, but having separate methods is considerably less dubious from a coherence point of view. Adding blanket From impls for all &T seems very likely to cause issues to me.

joshtriplett commented 8 months ago

The motivation given here is a motivation for the existence of core::slice::from_ref and core::array::from_ref (and the corresponding from_mut functions). However, those functions already exist. There doesn't seem to be a clear motivation that specifically requires From/Into. And when we discussed this in today's @rust-lang/libs-api meeting, we were hesitant to add these, for multiple reasons including potential lack of clarity and potential inference issues.

We're going to close this for now. If you have a use case / motivation that specifically requires From/Into, please feel free to file a new ACP.

scottmcm commented 8 months ago

if it was really thought that these conversions are so special that they deserve their own names

I'd say, rather, that it's the From ones that are special. By not having a name and often just happening without much thought in foo(x.into()), it's often the case that things shouldn't be Froms -- like str::as_bytes isn't a From.

To use the term from https://doc.rust-lang.org/nightly/std/convert/trait.From.html#when-to-implement-from, scalar-to-slice isn't clearly "value-preserving" since 1 and [1] have different conceptual kinds.