One of the biggest performance killer is the output at the right side of the playground. Now I will show you how to minimize this output.
See at the end for your example code.
Best Performance
The most performant way is to make all the performance critical code in a .swift file inside the Sources folder in the playground.
Note: In order to use the functions, classes, properties and methods from the Sources folder you have to mark them public. If you want to subclass a class it has to be marked open.
Good Performance but ugly code
The following method (I think this is not official/intended) can be used to disable the playground output but also leads to ugly code. However it is good for temporary disabling the output.
There are two main ways (and two tricks) to achieve the minimum amount of output (If you find a better way let us know):
Use parenthesis around Void (or Void?) expressions like assignments (normally leads to no output, see also 3.).
var x = 0 // output: 0
(x = 1) // NO output
(x = 2 * x - 1) // NO output
(x.negate()) // NO output
Note: In Swift an assignment returns Void and in case of optional chaining it is Void?.
var x: (Int, Int)? = nil
if (x?.0 = 0) != nil {
// assignment was successful (x!=0 and now x=(0, x.1))
} else {
// assignment was not successful (x==nil)
}
Initialize and declare variables separately.
var x: Int // NO output
(x = 0) // NO output
If 1. does not work add an additional no-op (no operation) line above or below ().
This happens in single line closures (and probably in some other contexts) for example: (see also the code below)
[1, 4, 5, 6].mmap{
() // without this line the line below would yield to an output
($1 = $0 + 1)
} as [Int]
Instead of wrapping every line in parenthesis you can also use a tuple of all the expressions which is then assigned to a variable:
var a: Any // this may be a useful definition in this context
var x: Int
var y: Int
(a = (x = 0,
y = 1,
x = y + 1,
y = x*x))
However this could lead to a indentation disaster...
Where it does not work (I've found no way how to remove the output; This list is probably not complete):
returns in functions and closures
- Declaration of
Optional variables e.g.: var x: Int?
An example of a new map method on Sequence
Usage: See above at Point 3.
The signature of Sequence.map is
func map<T>(_ transform: (Self.Element) throws -> T) rethrows -> [T]
Since I have not found a way how to remove the output of returns one can use a closure with an inout argument (get the "return" value with an assignment). A possible signature could then be:
func mmap<U>(_ transform: (Element, inout U?) -> ()) -> [U]
so we can pass nil in the inout argument since it is a good default for every possible U without imposing a constraint on U which could require an instance generator (e.g.: init() { ... }).
Unfortunately Swfit has a hard time to infer U so you would need to help the compiler with explicit type annotations. In addition var newElement: U? does return nil in the sidebar.
Now I will use Any instead of U?:
extension Sequence {
// ATTENTION: this is not as performant as the normal `map`!
func mmap<U>(transform: (Element, inout Any) -> ()) -> [U] {
var result: [U]
(result = [U]())
for element in self {
var newElement: Any
(newElement = 0) // some placeholder element
(transform(element, &newElement))
// assume the inout element to be of type `U`
(result.append(newElement as! U))
}
return result // the ONLY output in this method
}
}
Your example code
Using Swift 4
var count = 0
for i in 0..<1_000_000_000 {
(count += 1)
if count % 100_000 == 0 {
// print only every 100_000th loop iteration
print(count)
}
}
Without the parenthesis: about 10.000 loop iterations per second
With parenthesis: about 10.000.000 loop iterations per second !!!
var count = 1000000000.