I had an idea just now that I thought was pretty cool, so I'm curious to see if anyone agrees. The idea is to allow a function which returns an array of values to define those values one by one, using expressions which evaluate to unused values. Here's an example:
func rectTransforms () -> [RectTransform] {
RectTransform { rect in
rect.width = rect.width * 2
}
RectTransform { rect in
let previousWidth = rect.width
rect.width = rect.height
rect.height = previousWidth
}
RectTransform { rect in
rect.x += rect.width
}
}
In case it's unclear for anyone - in this scenario there is a type called RectTransform
which has an initializer: init (transformFunction: @escaping (inout Rect)->())
such that you can create new instances in the manner seen above. The unsugared version of this might be something like:
func rectTransforms () -> [RectTransform] {
var returnValues: [RectTransform] = []
let value1 = RectTransform { rect in
rect.width = rect.width * 2
}
returnValues.append(value1)
let value2 = RectTransform { rect in
let previousWidth = rect.width
rect.width = rect.height
rect.height = previousWidth
}
returnValues.append(value2)
let value3 = RectTransform { rect in
rect.x += rect.width
}
returnValues.append(value3)
return returnValues
}
Clearly, the former is vastly preferable from a syntax perspective. If the whole use case were totally contrived that wouldn't matter, but I hope you can see from a combination of the example and your imagination that there could be many ways to apply this create beautifully elegant descriptions of rather complex values. An extension of this example might be to describe complex animations in a similar manner. The difference between the sugared and unsugared versions is especially dramatic because the return values each use trailing closure syntax - this is on purpose, because the use case I have for this does the same thing which is why I want this.
Swift has already set the precedent of floating values being treated as return values in single line closures. This seems to me like a debatable but fairly natural extension of that. I personally have a use case for this in a library I'm developing.
@discardableResult
functions complicate things slightly, but not really. If you want to use one for its side effects within a function like this without returning the value, just do this let _ = mySideEffectFunction()
. If you use normal return myArray
syntax then you can of course use mySideEffectFunction()
without the trivial assignment to _
without any unintended return values.
I get that there are all kinds of questions to answer, like "what if the user puts at the bottom of the function if someBool { return [] }
?" and many others. Will love to hear what ideas you guys have about this.