idea: immutable setters for structs and tuples?


(Zsolt Szatmári) #1

Dear All,

  The only thing I am really missing right now from Swift is described as
following. This works in some other languages, e.g. F#, Kotlin, and Haskell.

  F# example (taken from https://fsharpforfunandprofit.com/posts/correctness-
immutability/)

let john = {firstName="John"; lastName="Doe"}

let alice = {john with FirstName="Alice"}

  Current way to do this in Swift is:

let john = (firstName:"John", lastName:"Doe")
var alice = john
alice.firstName = "Alice"

  This might seem to be a nuance, but it's more cumbersome (especially if one
wants to do this frequently), and we are left with a var at the end.

  Also, this idea rhymes with the current direction of removing var arguments
from functions.

  What do You think? Thank You.

Zsolt


(Brent Royal-Gordon) #2

let john = {firstName="John"; lastName="Doe"}
let alice = {john with FirstName="Alice"}

  Current way to do this in Swift is:
  
let john = (firstName:"John", lastName:"Doe")
var alice = john
alice.firstName = "Alice"

I think this is better modeled in Swift as something like:

  let john = (firstName:"John", lastName:"Doe")
  let alice = with(john) {
    $0.firstName = "Alice"
  }

`with` would be something like:

  func with<Value>(value: Value, function: Value throws -> Void) rethrows -> Value {
    var mutableValue = value
    return try function(&mutableValue)
  }

This would serve many different purposes:

* If the value is a value type, allows you to return a modified copy
* Allows you to customize a value's properties immediately after initializing it, which many people have asked for
* Acts as a `tap` function when the block doesn't change the value (see <http://ruby-doc.org/core-2.3.0/Object.html#method-i-tap>)

···

--
Brent Royal-Gordon
Architechies


#3

I cannot remember any use of such a feature but instead of a language feature there is also a reasonable library solution:

// inspired by the lens idea (of Joe Groff I think)
// there is probably a better name
func lens<T>(value: T, lensClosure: inout T -> ()) -> T {
        var value = value
        lensClosure(&value)
        return value
}

// usage
let john = (firstName:"John", lastName:"Doe")
let alice = lens(john) { $0.firstName = "Alice" }

Kind regards
- Maximilian

···

Am 23.03.2016 um 09:06 schrieb Zsolt Szatmári via swift-evolution <swift-evolution@swift.org>:

Dear All,

  The only thing I am really missing right now from Swift is described as following. This works in some other languages, e.g. F#, Kotlin, and Haskell.

  F# example (taken from https://fsharpforfunandprofit.com/posts/correctness-immutability/)
  
let john = {firstName="John"; lastName="Doe"}
let alice = {john with FirstName="Alice"}

  Current way to do this in Swift is:
  
let john = (firstName:"John", lastName:"Doe")
var alice = john
alice.firstName = "Alice"

  This might seem to be a nuance, but it's more cumbersome (especially if one wants to do this frequently), and we are left with a var at the end.
  Also, this idea rhymes with the current direction of removing var arguments from functions.
  What do You think? Thank You.

Zsolt

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(William Dillon) #4

I like this. I’m always annoyed when I need var just because I can’t get all my initialization done with let.

- Will

···

On Mar 23, 2016, at 2:32 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

let john = {firstName="John"; lastName="Doe"}
let alice = {john with FirstName="Alice"}

Current way to do this in Swift is:

let john = (firstName:"John", lastName:"Doe")
var alice = john
alice.firstName = "Alice"

I think this is better modeled in Swift as something like:

  let john = (firstName:"John", lastName:"Doe")
  let alice = with(john) {
    $0.firstName = "Alice"
  }

`with` would be something like:

  func with<Value>(value: Value, function: Value throws -> Void) rethrows -> Value {
    var mutableValue = value
    return try function(&mutableValue)
  }

This would serve many different purposes:

* If the value is a value type, allows you to return a modified copy
* Allows you to customize a value's properties immediately after initializing it, which many people have asked for
* Acts as a `tap` function when the block doesn't change the value (see <http://ruby-doc.org/core-2.3.0/Object.html#method-i-tap>)

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Erica Sadun) #5

You can kind of do this now:

struct Person {
    var firstName, lastName: String
}

func modify<T>(item: T, update: (inout T) -> Void) -> T {
    var this = item
    update(&this)
    return this
}

let carol: Person = modify(john) {
    $0.firstName = "Carol"
}

print(carol)

-- E

···

On Mar 23, 2016, at 3:32 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

let john = {firstName="John"; lastName="Doe"}
let alice = {john with FirstName="Alice"}

Current way to do this in Swift is:

let john = (firstName:"John", lastName:"Doe")
var alice = john
alice.firstName = "Alice"

I think this is better modeled in Swift as something like:

  let john = (firstName:"John", lastName:"Doe")
  let alice = with(john) {
    $0.firstName = "Alice"
  }


(James Campbell) #6

Yeah a way to have a function that mutates a struct return a new copy with
that mutation would be awesome ! Rather than mutating in place.

···

*___________________________________*

*James⎥Head Of CEO*

*james@supmenow.com <james@supmenow.com>⎥supmenow.com <http://supmenow.com>*

*Sup*

*Runway East *

*10 Finsbury Square*

*London*

* EC2A 1AF *

On Wed, Mar 23, 2016 at 2:28 PM, William Dillon via swift-evolution < swift-evolution@swift.org> wrote:

I like this. I’m always annoyed when I need var just because I can’t get
all my initialization done with let.

- Will

> On Mar 23, 2016, at 2:32 AM, Brent Royal-Gordon via swift-evolution < > swift-evolution@swift.org> wrote:
>
>> let john = {firstName="John"; lastName="Doe"}
>> let alice = {john with FirstName="Alice"}
>>
>> Current way to do this in Swift is:
>>
>> let john = (firstName:"John", lastName:"Doe")
>> var alice = john
>> alice.firstName = "Alice"
>
> I think this is better modeled in Swift as something like:
>
> let john = (firstName:"John", lastName:"Doe")
> let alice = with(john) {
> $0.firstName = "Alice"
> }
>
> `with` would be something like:
>
> func with<Value>(value: Value, function: Value throws -> Void)
rethrows -> Value {
> var mutableValue = value
> return try function(&mutableValue)
> }
>
> This would serve many different purposes:
>
> * If the value is a value type, allows you to return a modified copy
> * Allows you to customize a value's properties immediately after
initializing it, which many people have asked for
> * Acts as a `tap` function when the block doesn't change the value (see <
http://ruby-doc.org/core-2.3.0/Object.html#method-i-tap>)
>
> --
> Brent Royal-Gordon
> Architechies
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Brent Royal-Gordon) #7

I think this is better modeled in Swift as something like:

  let john = (firstName:"John", lastName:"Doe")
  let alice = with(john) {
    $0.firstName = "Alice"
  }

You can kind of do this now:

struct Person {
    var firstName, lastName: String
}

func modify<T>(item: T, update: (inout T) -> Void) -> T {
    var this = item
    update(&this)
    return this
}

let carol: Person = modify(john) {
    $0.firstName = "Carol"
}

print(carol)

You *can* do this now. I'm suggesting it be added to Stdlib.

···

--
Brent Royal-Gordon
Architechies


(Tyler Cloutier) #8

I would very much like a standardized way of doing this. I am currently writing a game implementation in a functional style and the syntax for updating fields in pretty clunky. I’d like to avoid having to explicitly use var’s at all to accomplish it.

···

On Mar 23, 2016, at 7:29 AM, James Campbell via swift-evolution <swift-evolution@swift.org> wrote:

Yeah a way to have a function that mutates a struct return a new copy with that mutation would be awesome ! Rather than mutating in place.

___________________________________

James⎥Head Of CEO

james@supmenow.com <mailto:james@supmenow.com>⎥supmenow.com <http://supmenow.com/>
Sup

Runway East >

10 Finsbury Square

London

> EC2A 1AF

On Wed, Mar 23, 2016 at 2:28 PM, William Dillon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I like this. I’m always annoyed when I need var just because I can’t get all my initialization done with let.

- Will

> On Mar 23, 2016, at 2:32 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
>> let john = {firstName="John"; lastName="Doe"}
>> let alice = {john with FirstName="Alice"}
>>
>> Current way to do this in Swift is:
>>
>> let john = (firstName:"John", lastName:"Doe")
>> var alice = john
>> alice.firstName = "Alice"
>
> I think this is better modeled in Swift as something like:
>
> let john = (firstName:"John", lastName:"Doe")
> let alice = with(john) {
> $0.firstName = "Alice"
> }
>
> `with` would be something like:
>
> func with<Value>(value: Value, function: Value throws -> Void) rethrows -> Value {
> var mutableValue = value
> return try function(&mutableValue)
> }
>
> This would serve many different purposes:
>
> * If the value is a value type, allows you to return a modified copy
> * Allows you to customize a value's properties immediately after initializing it, which many people have asked for
> * Acts as a `tap` function when the block doesn't change the value (see <http://ruby-doc.org/core-2.3.0/Object.html#method-i-tap>)
>
> --
> Brent Royal-Gordon
> Architechies
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Andrey Tarantsov) #9

I would very much like a standardized way of doing this.

+1 for a function like with/lens in stdlib.

A.


(Erica Sadun) #10

Ah, then that's a "pass it by Dmitri" kind of thing, isn't it?

-- E

···

On Mar 24, 2016, at 3:39 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

I think this is better modeled in Swift as something like:

  let john = (firstName:"John", lastName:"Doe")
  let alice = with(john) {
    $0.firstName = "Alice"
  }

You can kind of do this now:

struct Person {
   var firstName, lastName: String
}

func modify<T>(item: T, update: (inout T) -> Void) -> T {
   var this = item
   update(&this)
   return this
}

let carol: Person = modify(john) {
   $0.firstName = "Carol"
}

print(carol)

You *can* do this now. I'm suggesting it be added to Stdlib.


(Rudolf Adamkovič) #11

+1 for a standardized way of doing this!

R+

···

Sent from my iPhone

On 23 Mar 2016, at 21:51, Andrey Tarantsov via swift-evolution <swift-evolution@swift.org> wrote:

I would very much like a standardized way of doing this.

+1 for a function like with/lens in stdlib.

A.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(James Campbell) #12

Could we draft up a proposal :slight_smile:

···

*___________________________________*

*James⎥Head Of CEO*

*james@supmenow.com <james@supmenow.com>⎥supmenow.com <http://supmenow.com>*

*Sup*

*Runway East *

*10 Finsbury Square*

*London*

* EC2A 1AF *

On Wed, Mar 23, 2016 at 10:49 PM, Rudolf Adamkovic via swift-evolution < swift-evolution@swift.org> wrote:

+1 for a standardized way of doing this!

R+

Sent from my iPhone

On 23 Mar 2016, at 21:51, Andrey Tarantsov via swift-evolution < > swift-evolution@swift.org> wrote:

>> I would very much like a standardized way of doing this.
>
> +1 for a function like with/lens in stdlib.
>
> A.
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


#13

I think this is better modeled in Swift as something like:

   let john = (firstName:"John", lastName:"Doe")
   let alice = with(john) {
       $0.firstName = "Alice"
   }

You can kind of do this now:

struct Person {
  var firstName, lastName: String
}

func modify<T>(item: T, update: (inout T) -> Void) -> T {
  var this = item
  update(&this)
  return this
}

let carol: Person = modify(john) {
  $0.firstName = "Carol"
}

print(carol)

You *can* do this now. I'm suggesting it be added to Stdlib.

Ah, then that's a "pass it by Dmitri" kind of thing, isn't it?

-- E

I think so. Although there should be a formal proposal.
Regarding the new naming conventions shouldn't it be "modified"?

Kind regards
- Maximilian

···

Am 24.03.2016 um 22:40 schrieb Erica Sadun via swift-evolution <swift-evolution@swift.org>:

On Mar 24, 2016, at 3:39 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution