Accessing a stored property of a consuming parameter

this is certainly an extremely basic question, but google doesn’t have the answer as of yet.

why is copy needed here? the path property is a stored property.

    init?(get metadata:consuming Metadata)
    {
        guard
        let uri:URI = .init((copy metadata).path)
        else
        {
            return nil
        }

        ...

i also took a look at the draft documentation in the swift book, but that didn’t explain it either.

I thiiink consume would also work here, in which case the logic is “if you want to consume the stored property of the parameter, you have to consume the whole parameter, because Swift doesn’t do destructuring at this time”. (And if you weren’t expecting to be consuming the stored property, remember that inits consume their parameters by default.)

1 Like

i consume the metadata structure as a whole later; it gets passed to a memberwise init.

ah, i forgot the URI.init(_:) was missing a __shared. that initializer was @inlinable and i used to follow a convention where i didn’t bother adding __shared to @inlinable inits because i figured it was unnecessary. that strategy seems to have aged poorly.

EDIT: spoke too soon.

extension URI:LosslessStringConvertible
{
    @inlinable public
    init?(_ description:borrowing String)
    {
        self.init(description[...])
//  copy of noncopyable typed value. This is a compiler bug. 
//  Please file a bug with a small example of the bug
//  sourcekitd
    }
}

since when did String become noncopyable?

it still doesn’t work when i do, and recompile the URI module

    @inlinable public
    init?(_ description:borrowing String)
    {
        //  ???
        self.init((copy description)[...])
    }

could this be another manifestation of Move only loadable to address reabstraction by jckarter · Pull Request #69263 · apple/swift · GitHub ?

1 Like

Does that actually make sense to borrow here? You take description by borrowing, but than you have to produce Substring, which can't be borrowing operation w/o copy.
I mean in theory one could imagine code like

init(_ substring: borrowing Substring) {
  // parse and copy only needed info from substring
}

init(_ description: borrowing String) {
  withoutActuallyConsuming(description) { consumableDescription in
    let substring = consumableDescription[...]
    // consumableDescription consumed to substring
    self.init(substring)
    // substring lifetime ended w/o damaging consumableDescription
  }
}

But this wouldn't work for a bunch of reasons.
IRL depending on how URI.init(_: Substring) actually works it's either should be consuming or take init(_ s: borrowing String, range: Range<String.Index>) or init(_ s: borrowing some StringProtocol).

And about "noncopyable String" - I guess it's just a misleading diagnostic message, seems like there's an issue about this.
And I think __shared doesn't have this issue.

Also, I didn't get what's about your second snippet:

Seems like it compiles fine, although it's just strange.