Difference between Swift shell and Swift compiled - swift

I'm new to swift and today I wrote a small script to test it for scientific application.
Regarding the small application I wrote, it appears that it is slower than C++ but faster than python. However, I noticed that, if I run my application using the interpreter (like from terminal swift main.swift) or I compile it, there is no difference in the execution time.
Am I missing something or is it normal. I would have expected a considerable speed-up in the compiled version. Here the sample code:
import Foundation
func isPrime(num:Int) -> Int {
var IsPrime = 0
var count = 1
for index in 1...num-1 {
if (num % index != 0) {
++count
}
}
if (count == num-1) {
IsPrime = 1
}
return IsPrime
}
var isReallyPrime = 0
var maxNum = 10000
print(isPrime(21))
let methodStart = NSDate()
var primeArray = [Int]()
for index in 2...maxNum-1 {
if (index%1000 == 0) {
print("Iterarion \(index)")
}
if (isPrime(index) == 1) {
primeArray.append(index)
}
}
let methodFinish = NSDate()
let executionTime = methodFinish.timeIntervalSinceDate(methodStart)
var last = primeArray.last
print("Last prime number: \(last)")
print("Execution time [s]: \(executionTime)")

swift main.swift
compiles the Swift code and then runs it. So the only overhead compared to a compiled binary is that the code is compiled on every invocation.
You can even pass compiler options such as the optimization level:
swift -Onone main.swift
swift -O main.swift
swift -Ounchecked main.swift

Related

The test runner exited with code 9 before finishing running tests

What does code 9 signify ( and how to fix the issue ) when Xcode crashes during the execution of WatchOS tests?
Scenario:
I have an XCTestCase that reads around 100 CSV test resource files. These files are comma-delimited, have approximately 6,000 lines, and have an average size of 64K. During my test case, I read these files into memory, and one my one, I verify that the input file ( after some processing ) matches the output file. Here is some code to demonstrate the flow:
import XCTest
#testable import MyWatch_Extension
class MyTest: XCTestCase {
func testMyAlgo() throws {
let testingData = discoverAvailableTestFiles(filter: "dataset_1");
XCTAssertGreaterThan(testingData.count, 0, "have data to process")
for (_, testingEntry) in testingData.enumerated() {
var input : [Double] = [];
var expectations : [Double] = [];
readInputOutputTestData(entries: &input, fileName: testingEntry + "_input");
readInputOutputTestData(entries: &expectations, fileName: testingEntry + "_expected_output");
// do something with the input, and store it into results
let results = MyAglo().doSomething();
compareResultsAndExpectations(testingEntry: testingEntry, results: results, expectations: expectations);
}
}
func discoverAvailableTestFiles(filter: String) -> Set<String> {
let bundle = Bundle(for: type(of: self))
let paths = bundle.paths(forResourcesOfType: "csv", inDirectory: nil);
var results = Set<String>()
for path in paths {
if (path.contains(filter)) {
let fileNameSubstring = path[path.index(path.lastIndex(of: "/")!, offsetBy: 1)...]
let qaFileName = fileNameSubstring[...fileNameSubstring.index(fileNameSubstring.lastIndex(of: "_")!, offsetBy: -1)]
results.insert(String(qaFileName))
}
}
return results;
}
func readInputOutputTestData(entries : inout [Double], fileName : String) {
let bundle = Bundle(for: type(of: self))
let path = bundle.path(forResource: fileName, ofType: "csv")!
do {
let data = try String(contentsOfFile: path, encoding: .utf8)
let myStrings = data.components(separatedBy: .newlines);
for idx in 0..<myStrings.count {
let parts = myStrings[idx].split(separator: ",");
if (parts.count > 0) {
for part in parts {
entries.append((part as NSString).doubleValue);
}
}
}
} catch {
print(error)
}
}
func compareResultsAndExpectations(testingEntry: String, results: [Double], expectations: [Double]) {
print("## testing \(testingEntry)");
XCTAssertEqual(results.count, expectations.count / 3, "mismatch in data count \(testingEntry)")
var counter = 0;
for idx in stride(from: 0, to: expectations.count, by: 3) {
XCTAssertEqual(results[counter], expectations[idx], accuracy: 0.5, "\(idx + 1) value mismatch")
counter += 1;
}
}
}
When I execute the testMyAlgo testcase, I might read the first 20 files, and I get the error message :
The test runner exited with code 9 before finishing running tests.
If I run each file individually or in smaller batches ( maybe only 20 of them, as opposed to the entire loop of 100 ), everything is fine. This leads me to believe that I am exhausting the memory space of the watch or should be executing the test case differently. Any idea what the problem is, or perhaps, how I should re-structure the test case to get away from this error? ( Maybe free resources or something similar before each test case )
You can create a dumb Xcode project that runs on an iPhone and copy/paste only this test to it. If it runs OK, that means you're exceeding the limits on the watch. If that's the case, you can create a framework with your algorithm and run the tests on the framework, and import the framework on your watch extension

Swift 4.2 computed variable [String:Bool] does not assign value correctly

[MacOS 10.14.1, Xcode 10.1, Swift 4.2]
I'm working on creating a getopt style CLI argument processor whilst practising Swift. In my design, I decided to create a computed variable, represented as a [String:Bool] dictionary, that can be checked to see if an option (key) is just a switch (value = true) or whether it may include parameters (value = false). So I've written the code below, all of which is, at the moment, in my small (300 lines) main.swift file.
The code works correctly in a playground, but in my Swift Xcode project, whilst the dictionary's keys are correct, values are always false and inconsistent with the printed messages.
let options = "cwt:i:o:"
//lazy var optionIsSwitch : [String:Bool] = { (This will be moved to a class)
var optionIsSwitch : [String:Bool] = {
var tmpOptionIsSwitch : [String:Bool] = [:]
let optionsStrAsArray = Array(options)
let flags = Array(options.filter { !":".contains($0) } )
tmpOptionIsSwitch.reserveCapacity(flags.count)
for thisOption in 0...flags.count-1 {
var posInOptionsStr = 0
while posInOptionsStr < optionsStrAsArray.count-1 && flags[thisOption] != optionsStrAsArray[posInOptionsStr] {
posInOptionsStr += 1
}
if posInOptionsStr < optionsStrAsArray.count-1 && optionsStrAsArray[posInOptionsStr+1] == ":" {
tmpOptionIsSwitch[String(flags[thisOption])] = false
print("\(flags[thisOption]) is FALSE")
} else {
tmpOptionIsSwitch[String(flags[thisOption])] = true
print("\(flags[thisOption]) is TRUE")
}
}
return tmpOptionIsSwitch
}()
I've stepped through the code in my project to observe the execution sequence, and found it to be correct. As per the first image, tmpOptionIsSwitch returns a dictionary containing the right keys but all the values are set to false, which is inconsistent with the print statements.
As part of my debugging activities, I copied the above code into a Swift Playground where I found it gave the correct results, as per the image below.
Has anyone has such an issue? Is there something I've done wrong?

Is there a way to override the Copy on Write behavior for Swift arrays?

I'm working on a project where I need to work with large arrays, and by using UnsafeMutablePointers, I get a threefold speed increase over using the regular array methods. However, I believe the copy on write behavior is causing me to change instances that I do not want to be affected. For example, in the following code, I want to update the values in copyArray, but leave the original values in anArray.
import Foundation
func increaseWithPointers(_ arr: inout [Int]) {
let count = arr.count
let ptr = UnsafeMutablePointer(mutating: &arr)
for i in 0..<count {
ptr[i] = ptr[i] + 1
}
}
var anArray = [1,2,3,4,5]
var copyArray = anArray
increaseWithPointers(&copyArray)
print(anArray)
Executing this code prints [2,3,4,5,6].
I can get around this by declaring copyArray as follows:
var copyArray = [Int](repeating: 0, count: 5)
for i in 0..<5 {
copyArray[i] = anArray[i]
}
However, this requires writing each value twice: to zero, then to the intended value. Is there a way to efficiently guarantee a copy of an array?
I can reproduce your problem using Xcode 9 beta 3, but not using Xcode 8.3.3. I suggest you file a Swift bug report.
This fixes the problem:
import Foundation
func increaseWithPointers(_ arr: inout [Int]) {
arr.withUnsafeMutableBufferPointer { (buffer) in
for i in buffer.indices {
buffer[i] += 1
}
}
}
var anArray = [1,2,3,4,5]
var copyArray = anArray
increaseWithPointers(&copyArray)
print(anArray)

Swift: command line tool exit callback

I need to know when a command line program is stopped by the user to release some active bluetooth connections from a command-line program (running on the terminal), written in swift.
Say the user calls the program then exits by pressing ctrl+Z.
How would I know ?
You can install a signal handler with Swift. For example:
import Foundation
let startTime = Date()
var signalReceived: sig_atomic_t = 0
signal(SIGINT) { signal in signalReceived = 1 }
var i = 0
while true {
if signalReceived == 1 { break }
usleep(500_000)
if signalReceived == 1 { break }
i += 1
print(i)
}
let endTime = Date()
print("Program has run for \(endTime.timeIntervalSince(startTime)) seconds")
Modified from this gist.

Creating random Bool in Swift

I'm needing to create a random bool value in my game, in Swift.
It's basically, if Yes (or 1), spawn one object, if No (or 0), spawn the other.
So far, looking at this question and a similar one on here, I found this:
let randomSequenceNumber = Int(arc4random_uniform(2))
Now it works, but it seems bias to 0 to me... like ridiculously bias...
This is how I'm then using the value:
if(randomSequenceNumber == 0)
//spawn object A
else
//spawn object B
Is there a better way to implement this using a random bool value? That isn't bias to a certain value?
Update
Bit of an experiment to see how many 1's vs 0's were were generated in 10,000 calls:
func experiment() {
var numbers: [Int] = []
var tester: Int = 0
var sum = 0
for i in 0...10000 {
tester = Int(arc4random_uniform(2))
numbers.append(tester)
print(i)
}
for number in numbers {
sum += number
}
print("Total 1's: ", sum)
}
Test 1: Console Output: Total 1's: 4936
Test 2: Console Output: Total 1's: 4994
Test 3: Console Output: Total 1's: 4995
Xcode 10 with Swift 4.2
Looks like Apple  engineers are listening
let randomBool = Bool.random()
import Foundation
func randomBool() -> Bool {
return arc4random_uniform(2) == 0
}
for i in 0...10 {
print(randomBool())
}
for more advanced generator the theory is available here
for basic understanding of Bernoulli (or binomial) distribution check here
extension Bool {
static func random() -> Bool {
return arc4random_uniform(2) == 0
}
}
// usage:
Bool.random()