Hi,
I really like the proposal as it's in the last draft. And the examples are 
really good, specially the one that is similar to the Ruby tap.
I've been using the Then extension for a while and makes the initialization 
much nicer. I also use a set of extensions that allow me to print intermediate 
objects in a chain of methods. Initially I was using it for FRP style but I 
ended up using it while developing on chain of functional methods on arrays. Is 
basically a specific implementation of what this proposal will generalize, 
which is cool.

My only concern is with the method cascading proposal. If that gets implement 
in the future how useful will this proposal be? I'm not that familiar with 
method cascading to have a strong opinion on this, but I would like to see 
other members to speak about it.

Btw, thanks for adding the proposals directly in the email. Makes keeping up to 
date withthe list   much easier 👏🏻

Sent from my iPad

> On 27 May 2016, at 20:42, Erica Sadun via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
>> On May 25, 2016, at 5:34 PM, Dany St-Amant <dsa....@icloud.com> wrote:
>>> Le 25 mai 2016 à 14:28, Erica Sadun via swift-evolution 
>>> <swift-evolution@swift.org> a écrit :
>>> 
>>> Over the past couple of days, the Twitters have discovered some work I'd 
>>> done on closure-based setup. 
>>> It's clear that a demand is out there and strong for this kind of behavior, 
>>> even without implicit `self` as 
>>> part of the mix or cascading. In that light, I've put together the 
>>> following:
>>> 
>>> https://gist.github.com/erica/96d9c5bb4eaa3ed3b2ff82dc35aa8dae
>>> 
>>> If the community demand is this high, I think we should re-consider pushing 
>>> it before 3. 
>>> Feedback as always welcome, including criticism.
>> 
>> Recently there was another possible 'with' variant:
>> - instead of being a: with 'instance' create new 'instance' using 'closure'
>> - it was a: with(/on) 'instance/s' perform 'closure' (same idea as the 
>> closure-based initialization, described in the motivation)
>> 
>> The thread "What about a VBA style with Statement?": 
>> http://thread.gmane.org/gmane.comp.lang.swift.evolution/14384
>> 
>> In either case the 'with' can be misleading/confusing; with, on its own 
>> doesn't suggest creation of a new entity, nor does it strongly suggest 
>> possible mutation.
>> 
>> Just mentioning it as to end up... with the proper name for this new 
>> function.
>> 
>> Dany
> 
> Naming can always be bikeshedded. 
> Brent's submitted a pull request: 
> https://github.com/apple/swift-evolution/pull/346
> Here's a gist: 
> https://gist.github.com/brentdax/ce3272e3d35f5ccac56483666f86b8fb
> The current state of the proposal follows 
> -- E
> 
> Introducing with to the Standard Library
> Proposal: TBD
> Author: Erica Sadun, Brent Royal-Gordon
> Status: TBD
> Review manager: TBD
> Introduction
> 
> This proposal introduces a with function to the standard library. This 
> function simplifies the initialization of objects and modification of value 
> types.
> 
> Swift-evolution thread: What about a VBA style with Statement?
> 
> Motivation
> 
> When setting up or modifying an instance, developers sometimes use an 
> immediately-called closure to introduce a short alias for the instance and 
> group the modification code together. For example, they may initialize and 
> customize a Cocoa object:
> 
> let questionLabel: UILabel = {
>     $0.textAlignment = .Center
>     $0.font = UIFont(name: "DnealianManuscript", size: 72)
>     $0.text = questionText
>     $0.numberOfLines = 0
>     mainView.addSubview($0)
>     return $0
> }(UILabel())
> Or they may duplicate and modify a constant value-typed instance:
> 
> let john = Person(name: "John", favoriteColor: .blueColor())
> let jane: Person = { (var copy) in
>     copy.name = "Jane"
>     return copy
> }(john)
> This technique has many drawbacks:
> 
> The compiler cannot infer the return type.
> You must explicitly return the modified instance.
> The instance being used comes after, not before, the code using it.
> Nevertheless, developers have created many variations on this theme, because 
> they are drawn to its benefits:
> 
> The short, temporary name reduces noise compared to repeating a variable name 
> like questionLabel.
> The block groups together the initialization code.
> The scope of mutability is limited.
> SE-0003, which removes var parameters, will make this situation even worse by 
> requiring a second line of boilerplate for value types. And yet developers 
> will probably keep using these sorts of tricks.
> 
> Fundamentally, this is a very simple and common pattern: creating a temporary 
> mutable variable confined to a short scope, whose value will later be used 
> immutably in a wider scope. Moreover, this pattern shortens the scopes of 
> mutable variables, so it is something we should encourage. We believe it's 
> worth codifying in the standard library.
> 
> Proposed Solution
> 
> We propose introducing a function with the following simplified signature:
> 
> func with<T>(_: T, update: (inout T -> Void)) -> T
> with assigns the value to a new variable, passes that variable as a parameter 
> to the closure, and then returns the potentially modified variable. That 
> means:
> 
> When used with value types, the closure can modify a copy of the original 
> value.
> When used with reference types, the closure can substitute a different 
> instance for the original, perhaps by calling copy() or some non-Cocoa 
> equivalent.
> The closure does not actually have to modify the parameter; it can merely use 
> it, or (for a reference type) modify the object without changing the 
> reference.
> 
> Examples
> 
> Initializing a Cocoa Object
> 
> Before:
> 
> let questionLabel: UILabel = {
>     $0.textAlignment = .Center
>     $0.font = UIFont(name: "DnealianManuscript", size: 72)
>     $0.text = questionText
>     $0.numberOfLines = 0
>     mainView.addSubview($0)
>     return $0
> }(UILabel())
> After:
> 
> let questionLabel = with(UILabel()) {
>     $0.textAlignment = .Center
>     $0.font = UIFont(name: "DnealianManuscript", size: 72)
>     $0.text = questionText
>     $0.numberOfLines = 0
>     mainView.addSubview($0)
> }
> Using with here moves the UILabel() initialization to the top, allows the 
> type of questionLabel to be inferred, and removes the return statement.
> 
> Copying and Modifying a Constant
> 
> Before (without var parameter):
> 
> let john = Person(name: "John", favoriteColor: .blueColor())
> let jane: Person = {
>     var copy = $0
>     copy.name = "Jane"
>     return copy
> }(john)
> After:
> 
> let john = Person(name: "John", favoriteColor: .blueColor())
> let jane = with(john) {
>     $0.name = "Jane"
> }
> In addition to the aforementioned benefits, with removes the var copy line.
> 
> Treating a Mutable Method As a Copy-and-Return Method
> 
> You would like to write this:
> 
> let fewerFoos = foos.removing(at: i)
> But there is only a remove(at:) mutating method. Using with, you can write:
> 
> let fewerFoos = with(foos) { $0.remove(at: i) }
> Avoiding Mutable Shadowing
> 
> The standard library includes an operator for concatenating two 
> RangeReplaceableCollections with this implementation:
> 
> var lhs = lhs
> // FIXME: what if lhs is a reference type?  This will mutate it.
> lhs.reserveCapacity(lhs.count + numericCast(rhs.count))
> lhs.append(contentsOf: rhs)
> return lhs
> Using with, you can eliminate the shadowing of lhs:
> 
> // FIXME: what if lhs is a reference type?  This will mutate it.
> return with(lhs) {
>   $0.reserveCapacity($0.count + numericCast(rhs.count))
>   $0.append(contentsOf: rhs)
> }
> It's important to note that with does not resolve the "FIXME" comment. Like 
> the var lhs = lhs in the original code, with only copies value types, not 
> reference types. If RangeReplaceableCollection included a Foundation-like 
> copy()method that was guaranteed to return a copy even if it was a reference 
> type, with would work nicely with that solution:
> 
> return with(lhs.copy()) {
>   $0.reserveCapacity($0.count + numericCast(rhs.count))
>   $0.append(contentsOf: rhs)
> }
> Inspecting an Intermediate Value
> 
> Suppose you want to inspect a value in the middle of a long method chain. For 
> instance, you're not sure this is retrieving the type of cell you expect:
> 
> let view = tableView.cellForRow(at: indexPath)?.contentView.withTag(42)
> Currently, you would need to either split the statement in two so you could 
> capture the return value of cellForRow(at:) in a constant, or insert a very 
> clunky immediate-closure call in the middle of the statement. Using with, you 
> can stay close to the original expression:
> 
> let view = with(tableView.cellForRow(at: indexPath)) { print($0) 
> }?.contentView.withTag(42)
> Because the closure doesn't alter $0, the cell passes through the with call 
> unaltered, so it can be used by the rest of the method chain.
> 
> Detailed Design
> 
> We propose adding the following free function to the standard library:
> 
> /// Returns `item` after calling `update` to inspect and possibly 
> /// modify it.
> /// 
> /// If `T` is a value type, `update` uses an independent copy 
> /// of `item`. If `T` is a reference type, `update` uses the 
> /// same instance passed in, but it can substitute a different 
> /// instance by setting its parameter to a new value.
> @discardableResult
> public func with<T>(_ item: T, update: @noescape (inout T) throws -> Void) 
> rethrows -> T {
>   var this = item
>   try update(&this)
>   return this
> }
> @discardableResult permits the use of with(_:update:) to create a scoped 
> temporary copy of the value with a shorter name.
> 
> Impact on Existing Code
> 
> This proposal is purely additive and has no impact on existing code.
> 
> Alternatives Considered
> 
> Doing nothing: with is a mere convenience; any code using it could be written 
> another way. If rejected, users could continue to write code using the 
> longhand form, the various closure-based techniques, or homegrown versions of 
> with.
> 
> Using method syntax: Some list members preferred a syntax that looked more 
> like a method call with a trailing closure:
> 
> let questionLabel = UILabel().with {
>     $0.textAlignment = .Center
>     $0.font = UIFont(name: "DnealianManuscript", size: 72)
>     $0.numberOfLines = 0
>     addSubview($0)
> }
> This would require a more drastic solution as it's not possible to add 
> methods to all Swift types. Nor does it match the existing design of 
> functions like withExtendedLifetime(_:_:), withUnsafePointer(_:_:), and 
> reflect(_:).
> 
> Adding self rebinding: Some list members wanted a way to bind self to the 
> passed argument, so that they can use implicit self to eliminate $0.:
> 
> let supView = self
> let questionLabel = with(UILabel()) { 
>     self in
>     textAlignment = .Center
>     font = UIFont(name: "DnealianManuscript", size: 72)
>     numberOfLines = 0
>     supView.addSubview(self)
> }
> We do not believe this is practical to propose in the Swift 3 timeframe, and 
> we believe with would work well with this feature if it were added later.
> 
> Adding method cascades: A competing proposal was to introduce a way to use 
> several methods or properties on the same instance; Dart and Smalltalk have 
> features of this kind.
> 
> let questionLabel = UILabel()
>     ..textAlignment = .Center
>     ..font = UIFont(name: "DnealianManuscript", size: 72)
>     ..numberOfLines = 0
> addSubview(questionLabel)
> Like rebinding self, we do not believe method cascades are practical for the 
> Swift 3 timeframe. We also believe that many of with's use cases would not be 
> subsumed by method cascades even if they were added.
> 
> 
> _______________________________________________
> 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

Reply via email to