I've updated the pitch to address many of the issues raised in this thread and moved it to a pull request against the Swift Evolution repository.
I like the color of the shed, thanks!
In Exclusivity and scope, it sounds like we're allowing borrow and inout bindings to the same variable at the same time. Should that be construed as a relaxation of the law of exclusivity? For instance, today, this is illegal:
struct Foo {
var x: Int
mutating func frob(action: () -> Int) -> Int {
return action()
}
}
var foo = Foo(x: 10)
let value = foo.frob { foo.x }
// ^^ Simultaneous accesses to 0x100c38000, but modification requires
// exclusive access.
Will this still be illegal?
In Not implicitly copyable, is copy a new standard library function? If not, how is A being copied: is return a allowed to return a copy?
borrow x = a // Borrow `a`
func copy(_ a: borrow A) -> A { ... }
let z = copy(x) // Legal way to explicitly copy x
In Switch and if-case binding, if you use switch &variable, do you have to use inout bindings for payloads or will it still allow non-inout payloads?
No. There is no intention here of relaxing the law of exclusivity. There is some nuance about when a new binding causes a previous binding to be inaccessible, but there should be no point in the program at which a read/write binding and some other access are both useable.
I'll review that section; it sounds like it may need some additional clarification.
There's a copy function defined on the previous line.
I'm assuming that user-defined function knows how to construct a new A instance with the same information as the borrowed original.
A general-purpose copy function could be an interesting Future Direction, but I'm not proposing such a thing.
First, note that the & sigil here means that the variable might be modified. That means it is required if there are any inout bindings, but does not preclude there being other kinds of bindings. In particular, this leaves open the possibility of mixing different kinds of bindings within a single switch statement.
However, as I explain in "Future Directions", I think mixed bindings could be confusing in practice, so for now I'm proposing that we limit such mixing until we have more experience with this construct.
I saw it, but I didn't feel copy would be trivial enough to be stubbed with no comment! If you get a struct from another module that has no public initializer, today, you can make the assumption that the library author did not want you to make your own values directly but they didn't mind if you copied existing values. As proposed, you need the library author's blessing to copy values that have been passed by borrow. This may well be approximately equivalent to needing the library author's blessing to pass by borrow at all. It feels like requiring explicit copy constructors in C++ to me.
That's a good point. I'll talk to some folks about this and see if there's something we need to adjust here.
Wasnât an explicit copy operator proposed as part of the @noImplicitCopy pitch?
I chatted with a few folks and think I see what got missed...
A copy operator was mentioned in the @noImplicitCopy pitch but not formally proposed there. So I think I'll add it to this proposal.
In essence, the copy operator can be used to explicitly copy a copyable type that is in a non-implicitly-copyable context:
let a = CopyableType()
borrow x = a
let b = x // Illegal. x is not implicitly copyable
let c = copy x // Legal
But this cannot be used to avoid restrictions on non-copyable types:
let u = NoncopyableType()
borrow y = u // Legal to borrow a noncopyable type
let v = y // Illegal; y is not implicitly copyable
let w = copy y // Illegal; y is not copyable at all
The operator form here is consistent with what we're discussing elsewhere for "borrow" and "consume" operators.
It could also be a good idea to clarify the relationship between inout, borrowed and noescape. As I understand it with the copy clarification, an inout/borrowed value can still escape. This is most likely intended.
A borrowed value can escape only by copying it. This is intentional and has two important implications:
- A non-copyable borrowed value cannot escape.
- An escape of a copyable borrowed value requires an explicit 'copy' operation, which makes it obvious in the source.
Please take a look at these changes and let me know if they address your concerns.
Yes, thank you!
When I was relatively new to Swift, coming from some experience in C++ (where I knew about T& but not T&&), I remember writing something like this:
inout aliasToE = a.b.c.d.e
Having read through this thread I donât think thatâs what I would want the syntax to be, but it would be nice if thereâs a fix-it to change that to whatever that should be (whether itâs var x = &y or inout x = &y or whathaveyou).
Out of curiosity: Any progress on this pitch? Canât wait for inout in an enum case.
There's no way to solve the Day 11 Advent of Code 2024 problem in Swift 6 using recursive value typesâa recursive solution hits the call stack depth limit, and an iterative solution seems impossible without this proposed inout declaration keyword. Ironically, the o1 GPT kept reaching for it (falling back to mutating self capture which is also an error) when trying to come up with a linear-time solution using value types.
a recursive solution hits the call stack depth limit, and an iterative solution seems impossible without this proposed
inoutdeclaration keyword.
Okay, so this nerd-sniped me and... no, an iterative solution is not impossible; I was able to accomplish it. (I think I misunderstood this statement; I was able to solve it using an iterative solution, but not with recursive value types.)
(Also sidenote, FYI, it's generally considered poor manners around these parts to revive 2-year old threads. Generally less frowned upon to just make a new thread linking to the old one.)
That being said, I would still say these keywords would be an excellent addition to the language!
Sorry, I failed to mention that I was trying to solve it in-place using recursive value types. Maybe you did! DM'd you for insight into your solution ![]()