Reputation: 60081
In Kotlin, we could change the below
// Original code
var commonObj = ClassCommonObj()
commonObj.data1 = dataA
commonObj.data2 = dataB
commonObj.data3 = dataC
// Improved code
var commonObj = ClassCommonObj()
with(commonObj) {
data1 = dataA
data2 = dataB
data3 = dataC
}
However in Swift as below, do I have equivalent with
function to use?
// Original code
var commonObj = ClassCommonObj()
commonObj.data1 = dataA
commonObj.data2 = dataB
commonObj.data3 = dataC
Upvotes: 13
Views: 2843
Reputation: 11880
Like @Hexfire said, so far, no built-in Swift equivalent to Kotlin's with()
. As he points out, you can more or less write one yourself.
I use a version slightly different than the Kotlin with()
that automatically returns the modified element (more akin to Kotlin's apply
). I find this clearer, pithier, and more generally useful.
This is the version I use:
@discardableResult
public func with<T>(_ item: T, _ closure: (inout T) -> Void) -> T {
var mutableItem = item
closure(&mutableItem)
return mutableItem
}
It's declared globally (so no dependency on NSObject
or extension declarations). It also handles mutability like I expect. In use, it looks like:
let myWellDescribedLabel = with(UILabel()) {
$0.attributedText = attributedStringTitle
$0.isAccessibilityElement = true
$0.numberOfLines = 1
}
Unfortunately (or is it? see comments), Swift does not have self syntax in closures, so you must reference the passed object as $0
(or create a named parameter to the closure).
While we're here, a withLet()
that handles optionals is also very useful:
@discardableResult
public func withLet<T>(_ item: Optional<T>, _ closure: (inout T) -> Void) -> Optional<T> {
guard let item = item else { return nil }
return with(item, closure)
}
These are in a gist here.
Upvotes: 1
Reputation: 6058
Unfortunately, no such functionality so far in Swift. However, similar functionality can be reached with the power of extensions:
protocol ScopeFunc {}
extension ScopeFunc {
@inline(__always) func apply(block: (Self) -> ()) -> Self {
block(self)
return self
}
@inline(__always) func with<R>(block: (Self) -> R) -> R {
return block(self)
}
}
This protocol and extension provides two inline
functions, where one can be served to return processed object, and the other is strictly similar to with
in Kotlin and other languages (Visual Basic supported in 90s).
Usage
Specify types which these functions should apply to:
extension NSObject: ScopeFunc {}
apply
:
let imageView = UIImageView().apply {
$0.contentMode = .scaleAspectFit
$0.isOpaque = true
}
Here we create an object and once the closure is executed, modified object is returned.
with
:
imageView.with {
$0.isHidden = true
}
Works equal to with
in Kotlin.
Originaly based on this source code.
NOTE:
Swift compiler is generally regarded as smart enough to decide whether or not a function should be inlined. Quite likely, these two would be inlined due to their relative compactness even without strictly specifying @inline (__always)
. Either way, you should know that this keyword does not affect the logic and the result of these, because inlining is about optimizing the program.
Upvotes: 15