Howdy,
        It seems the main question in discussing this proposal is “If $0, $1, 
$2, $3 are automatic closure parameters, then what is “$”?”.  Another thing 
that has also recently come to my attention that Swift does not have a “result 
of previous expression” magic identifier as some functional languages do.  
Combine this with my difficulty in creating closures which automatically bind 
weakly to the variable, and I’m looking at a potential meaning for “$” 
consistent with all of these goals.

First off, I don’t like the “$0, $1, $2, …” feature, but I can respect it.  I 
mainly don’t like it because in English “$” is defined as “dollar”, not “magic 
variable number _”.  However, it appears that in Swift, “$” really does mean 
“magic variable number _”, and some developers find it very useful.

I’m not looking to routinely violate the law of Demeter, but occasionally in 
data conversion, it’s really unavoidable.  Sometimes, I need to convert to a 
type with a non-optional argument, but my argument is Optional.  Here, for 
instance:

struct XMLNode {
        var attributes:[String:String]
}

struct Note {
        /// half-steps from middle-C, nil means the note is a rest
        var pitch:Int?
        //more properties
        init?(xmlNode: XMLNode) {
                if let pitchString:String = xmlNode.attributes[“pitch”], let 
pitchInt:Int = Int(pitchString) {
                        pitch = pitchInt
                }
                //more code
        }
}

I could go write an extension on String to provide a computed integer property, 
but I’m not just talking about one case, I’m talking about all cases where we 
convert to types in this way.

If “$” meant “identifier of result of previous expression”, I could write:

init?(xmlNode: XMLNode) {
        pitch = xmlNode.attributes[“pitch”]?Int($)
        //more code
}

instead.  Much cleaner.

Now, in my mind the first question is: “don’t I need another operator after the 
“?” ? “  And that got me thinking about unowned/weak capture in closures and 
UndoManager blocks.  If the reference is captured separately from the actions 
on the reference, then strong/weak/unowned really isn’t an argument for those 
cases.  It’s like I want an autoclosure that takes 1 instead of 0 arguments, 
the 1 generic value from the previous expression, which, incidentally would be 
represented by “$”—if it were explicitly referenced.  The optional chaining 
operator right now, as I understand it, is compiler magic.  But what if there 
were a language construct for such features as there is for optimized 
evaluation with ??, &&, and || ?  It would allow me to create my own “?”-like 
behaviors.  

Which operator it is, I don’t much care; I am looking closely at “\”.  Finally, 
there is a difference between a 1-argument auto closure that acts as if it 
continued an expression, i.e. _?._ and one which places the previous result as 
an argument into a self-contained expression.  But if the leading-dot, i.e. 
“.intValue”, syntax is itself just syntactic sugar for writing “$.intValue”, 
then there really isn’t a difference.

So the chaining optional operator becomes defined in the language as:

nocapture operator ? : WhateverPrecedenceGroup

infix func ?<LReturnType, RReturnType>(lhs:@autoclosure()->(LReturnType?), 
rhs:@autoclosure (LReturnType)->(RReturnType))-> RReturnType? {
        guard let lhs = lhs() else { return nil }
        return rhs(lhs)
}

and I can extract a closure which does not capture “self” at all:

class Controller {
        func provideClosure()->(Controller)->Result {
                return self\.doSomething        //doesn’t capture self
        }
        func doSomething()->Result {
                //write me
        }
}

So “\” becomes:

nocapture operator \ : WhateverPrecedenceGroup

and the compiler inserts the magic of creating the “nocapture” operators, which 
parses nearly identically to how it works today.

Calls to UndoManager become cleaner:

class Controller {
        var color:Color {
                didSet {
                        undoManager.register(withTarget:self, handler:{ 
(controller:Controller)->Void in
                                controller.color = oldValue
                        })
                }
        }
}

becomes:

class Controller {
        var color:Color {
                didSet {
                        undoManager.register(withTarget:self, 
handler:self\.color = oldColor)
                }
        }
}


So, doing all this would:

- Give $, $0, $1, $2 consistent meanings, “the argument”.
- Solve the problem of quickly obtaining a weak / unowned closure references by 
creating generic 1-parameter autoclosures.
- Allow inits in optional chains.

Alternatively:

Perhaps use $0 instead inside my 1-argument auto closures, but to me it implies 
there could be more, and could interfere with these from an enclosing closure.

Perhaps “?” is the operator to use for creating the 1-argument closures, but to 
me it implies optional-related behavior

Perhaps this really is just too many “dots”, and we want to move away from the 
functional style, but developers are loving it.

Perhaps the UndoManager’s generic syntax is sufficient.

Perhaps I’ve missed something critical in the grammar.

Thanks your reading and consideration.  Swift on!

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to