[swift-evolution] "with" operator a la O'Caml?

Xiaodi Wu xiaodi.wu at gmail.com
Mon Dec 19 16:13:07 CST 2016


More advanced mirroring is one of those things that is on the agenda
somewhere. It would stand to reason that a generalizable solution which
doesn't need to be created for each struct would become possible when that
arrives, no?

On Mon, Dec 19, 2016 at 16:08 Andy Chou via swift-evolution <
swift-evolution at swift.org> wrote:

> Value semantics help reduce the issues around mutability, but they don't
> go away completely. I would like to create structs that are completely
> immutable after construction. Turning the properties into vars
> unfortunately loses this idea.
>
> The proposed 'with' function doesn't construct new instances, which means
> the let constants are already set. Nick's solution works, as it's basically
> a copy constructor that allows for changes while the new object is
> constructed. But it needs to be created for each struct. Which I'm fine
> with :)
>
> Andy
>
> On Dec 19, 2016, at 1:47 PM, Derrick Ho <wh1pch81n at gmail.com> wrote:
>
> That is correct Andy. Let-constant can not be assigned a new value after
> it gets its initial value.
>
> It is unclear why you are against turning your properties into var's.
> Because you are using structs, all properties are copied by value.
>
> struct Person {
>   var name: String
> }
>
> let andy = Person(name: "Andy")
> var brandon = andy; brandon.name = "Brandon"
>
> andy.name // "Andy"
> brandon.name // "Brandon"
>
> I believe this accomplishes the same thing you wanted in with(name:)
>
> On Mon, Dec 19, 2016 at 1:26 PM Andy Chou via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> Thanks Erica, I wasn't aware of that Swift evolution proposal. If I'm
> reading it right, this wouldn't work with structs with let-variables...?
> Here's what I get with this example:
>
> struct Person {
>     let name: String
>     let address: String
> }
>
> @discardableResult
> public func with<T>(_ item: T, update:
> (inout T) throws -> Void) rethrows -> T {
>     var this = item
>     try update(&this)
>     return this
> }
>
> let john = Person(name: "John", address: "1 battery st")
> let jane: Person = with(john) { $0.name = "Jane" }     //
> Test.swift:24:41: Cannot assign to property: 'name' is a 'let' constant
>
> Andy
>
>
> On Dec 19, 2016, at 11:44 AM, Erica Sadun <erica at ericasadun.com> wrote:
>
> https://github.com/apple/swift-evolution/pull/346
>
> Be aware that there's a bug that's being worked on:
>
> https://bugs.swift.org/browse/SR-2773
>
> -- E
>
>
> On Dec 19, 2016, at 12:40 PM, Andy Chou via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> Of course. Thanks for pointing out the obvious solution. This preserves
> the immutability of the struct and doesn't require O(n^2) code for structs
> with large numbers of fields.
>
> I was thinking of a generic solution - perhaps something like a synthetic
> initializer that does what your solution does. But that may be overkill
> given how relatively easy it is to do this per struct...
>
> On the other hand a generic solution would encourage using immutable
> structs. I wasted too much time trying to solve this, I suspect others
> would just give up and use var, or even classes.
>
> Andy
>
> On Dec 19, 2016, at 10:43 AM, Nick Keets <nick.keets at gmail.com> wrote:
>
>
>
>
>
>
>
>
>
>
>
> You are probably asking for a generic solution, but for a specific struct
> you can implement it like this:
>
>
>
>
> extension Person {
>     func with(name: String? = nil, address: String? = nil, phone: String?
> = nil) -> Person {
>         let name = name ?? self.name
>         let address = address ?? self.address
>         let phone = phone ?? self.phone
>         return Person(name: name, address: address, phone: phone)
>     }
> }
>
>
>
>
>
>
>
>
>
>
>
>
> On 19 Dec 2016, 20:28 +0200, Andy Chou via swift-evolution <
> swift-evolution at swift.org>, wrote:
>
>
> I like that structs are value types in Swift, this encourages the use of
> immutable data. O'Caml has an operator "with" that allows for copying an
> existing struct with a change to one field. I looked at Lenses for this
> functionality and it seems like a lot to digest for something so simple. I
> also tried to implement this using a constructor, or a function, and it was
> not obvious how to do so without a lot of code duplication.
>
>
>
>
>
> What's I'm looking for is something like this (not necessarily with this
> syntax):
>
>
>
>
>
> struct Person {
>
>
> let name: String
>
>
> let address: String
>
>
> let phone: String
>
>
> }
>
>
>
>
>
> func f() {
>
>
> let andy = Person(name: "Andy", address: "1 Battery St., San Francisco,
> CA", phone: "1234567")
>
>
> let chris = andy.with(name: "Chris")
>
>
> let dave = andy.with(address: "50 Townsend St., San Francisco, CA")
>
>
> }
>
>
>
>
>
> I tried to implement a "with" function like this but default arguments
> cannot reference properties of self. Same problem trying to do this in a
> constructor.
>
>
>
>
>
> Obviously it's possible to create an entirely new Person specifying the
> values from an existing Person, but this is very tedious with structures
> with many properties.
>
>
>
>
>
> Anyone taken a look at this before? Any suggestions?
>
>
>
>
>
> Andy
>
>
>
>
>
> _______________________________________________
>
>
> swift-evolution mailing list
>
>
> swift-evolution at swift.org
>
>
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
>
>
>
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> _______________________________________________
>
>
> swift-evolution mailing list
>
>
> swift-evolution at swift.org
>
>
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161219/5ca2835f/attachment.html>


More information about the swift-evolution mailing list