Rules for type check in Swift builds? - swift

I’ve wanted to speed up my build times, so one of the steps was using Other Swift Flags and
-Xfrontend -warn-long-function-bodies=100
-Xfrontend -warn-long-expression-type-checking=100
But I’m not really sure how type checks work. For example, here’s a simple func for creating random CGFloat. Type check for it is over 200ms
static func randomColorValue() -> CGFloat {
return CGFloat(Int.random(in: 0...255))/255.0
}
But on changing to something like this
static func randomColorValue() -> CGFloat {
let rnd = Int.random(in: 0...255)
let frnd = CGFloat(rnd)
let result = frnd/255.0
return result
}
or like this
static func randomColorValue() -> CGFloat {
let rnd : Int = Int.random(in: 0...255)
let frnd : CGFloat = CGFloat(rnd)
let result : CGFloat = frnd/255.0
return result
}
type check is still over 200ms.
What's wrong here? Is there any set of rules and best practices for dealing with build times?
My Mac is a bit older (2012), maybe that's the problem?
EDIT:
After turning off -warn-long-function-bodies problematic line appeared, and that is
CGFloat(rnd)
It appears that casting Int to Float, Double or CGFloat shows slowing down of 150ms.

Note that warn-long-function-bodies is unsupported (it was added as an experimental flag). If you remove it, I find that the expression time is often reported as twice as fast, which makes be believe that using the two measurements together is causing interference. Measurement takes time, too. warn-long-expression is a supported option.

Related

'withUnsafeMutableBytes' is deprecated: use `withUnsafeMutableBytes<R>

I am very green with Xcode (apologize in advance). Trying to bring some old code to life. Getting the following with trying to move to Swift 5.
withUnsafeMutableBytes' is deprecated: use withUnsafeMutableBytes<R>(_: (UnsafeMutableRawBufferPointer) throws -> R) rethrows -> R instead
Goal: All I need to do is modify the code appropriately and be done.
I have looked at other Stack Overflow messages, searched various articles, experimented with different things, but can't quickly determine what needs to change. I am sure the solution is super simple for someone that knows more.
var responseData = Data(count: Int(responseDataLength))
_ = responseData.withUnsafeMutableBytes
{
mfError = MFMediaIDResponse_GetAsString(mfMediaIdResponsePtr.pointee, MFString($0), responseDataLength)
}
Here is my example, when refreshing old code of withUnsafeMutableBytes
hope it helps
The old one:
_ = data.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) in
memcpy((ioData.pointee.mBuffers.mData?.assumingMemoryBound(to: UInt8.self))!, bytes, dataCount)
}
The new one:
_ = data.withUnsafeMutableBytes { (rawMutableBufferPointer) in
let bufferPointer = rawMutableBufferPointer.bindMemory(to: UInt8.self)
if let address = bufferPointer.baseAddress{
memcpy((ioData.pointee.mBuffers.mData?.assumingMemoryBound(to: UInt8.self))!, address, dataCount)
}
}
Explains:
use UnsafeMutablePointer<ContentType>, you get an unsafeMutablePointer in its closure.
To access to its memory, so need to typed it with bindMemory,
more details on Apple Pointer Doc

Swift compiler struggles with this expression

EDIT
The source of the issue seems to be the use of .lowercased() to return a lower case string. Adding this to any line seems to result in a 40-60ms compile time.
In an effort to speed up my compile times I've added the "-Xfrontend -debug-time-function-bodies" flag detailed here as well as following the optimisation tips here
The compiler seems to struggle with filter functions for example this:
// Filter by search term
if self.searchController.isActive {
filteredManualTasksArray = self.filteredManualTasksArray.filter() {
let taskName:String = $0.bmTaskName!.lowercased()
let searchText:String = searchController.searchBar.text!.lowercased()
return taskName.contains(searchText)
}
}
Result in this warning:
Expression took 51ms to type-check (limit: 50ms)
The variable filteredManualTasksArray is declared elsewhere as:
var filteredManualTasksArray:[BMTask]!
So all variables are explicitly typed as far as I can tell. Is there anything I can do to speed this up?
Edit: I've tried a couple of approaches that seem to make no difference
1) combining the three lines into one:
return $0.bmTaskName!.lowercased().contains(searchController.searchBar.text!.lowercased())
2) Specifying the filter type:
filteredManualTasksArray = self.filteredManualTasksArray.filter { (task: BMTask) -> Bool in
Edit 2
This line:
let searchText:String = searchController.searchBar.text!.lowercased()
Seems to be the cause of the issue - it take 38ms to type check. Any ideas how I can improve this?
You could move the let searchText line out of the filter function:
if self.searchController.isActive {
let searchText:String = searchController.searchBar.text!.lowercased()
filteredManualTasksArray = self.filteredManualTasksArray.filter() {
let taskName:String = $0.bmTaskName!.lowercased()
return taskName.contains(searchText)
}
}

Does the Swift compiler get rid of superfluous type casts when using a typealias?

In my application I can't decide what floating point format will be the best for performance. Its not so much the matter of bits that I am worried about rather how it interfaces with various functions I am using since I am using math libraries and graphics libraries.
As a result I have built everything using typealias EngineDecimal = CGFloat so that at the end I can experiment with changing that to other formats such as GLFloat, Float32 etc.
My question is what does the compiler do if I write a function like this:
func foo(in: EngineDecimal)-> EngineDecimal
{
return Decimal(mathFunction(CGFloat(in)));
}
//foo2 is a library defined function that I have no control over but I'm typing a sample one for this example
func foo2(in: CGFloat) -> CGFloat
{
return sin(in) + cos(in)
}
Will the compiler notice if Decimal is the same type as CGFloat and thus get rid of the casting statements? So in essence would this code run faster if typealias EngineDecimal = CGFloat vs if typealias EngineDecimal = GLFloat ?
A typealias doesn't create a new type, it just allows a new name to be used in place of an existing type. So there is no casting being done and no optimisation needs to occur.

Subclassing Swift Double / Operator Overloading typealias

I'd like to be able to subclass Double with some custom types in my swift code so I can do some introspection and operator overloading later on.
This is semantically what I want to be able to write:
class Frequency: Double {}
class Period: Double {
init(_ frequency: Frequency) {
let period: Double = 1 / frequency
self.init(period)
}
}
let a = Double(1)
print(type(of: a)) // Double
let b = Frequency(2)
print(type(of: b)) // Frequency
let c = Period(a)
print(type(of: c)) // Period == 1
let d = Period(b)
print(type(of: d)) // Period == 0.5
Feel like what I'm trying to do should be posible as Swift is a strictly typed language.
I've looked at typealiases as well, but you can't operator overload with those. Also looked at the FloatingPoint protocol but doesn't seem to help me.
while this is not possible, I created a class a while ago, which addressed a similar issue. I was in need of a polyvalent variable class, for ease of synthax in currency strings, and ended up with something like bellow. So far it's working great, and I've been using it as mortar for many advanced subclasses i've built since then. It does what you wish, which if you can see in the Frequency subclass, becomes a matter of tweaking the init override for each use case.
While the class is large, and the methods bulky, feel free to tweak and modify however you see fit, or if you find simpler approaches. I uploaded it to a gist file here so it can be read easily.
Link to the class.
When used with your use case, it allows for the following, which seems to be what you want:
class Frequency : MultiVar {
override init(_ value: Any?) {
super.init(value)
let current = double
guard current != 0.0 else {
print("Frequency Error: Something went wrong while subclassing \(self), established variable 'double' is equal to 0!")
return
}
double = 1 / current
}
}
let freq = Frequency(10)
print(freq.string) //prints 0.1
print(freq.double) //prints 0.1

CGFloat <-> Double

Writing graphics code in UIKit is a PITA. The "nominal" floating point type for Swift is Double. But most of the UIKit graphics code uses CGFloat which seems to be either Double or Float based on the chip in my phone. I find myself having to constantly use CGFloat() and Double() transformers.
I have considered killing the problem by simply providing the operators it continually complains are lacking (I like to add lots of numeric type extensions anyway):
func * (lhs:CGFloat, rhs:Double) -> Double {
return Double(lhs) * rhs
}
func * (lhs:CGFloat, rhs:Double) -> CGFloat {
return lhs * CGFloat(rhs)
}
func * (lhs:Double, rhs:CGFloat) -> Double {
return lhs * Double(rhs)
}
func * (lhs:Double, rhs:CGFloat) -> CGFloat {
return CGFloat(lhs) * rhs
}
With this in place, I don't have to care anymore. I realize there will be lots of opinions as to whether this is a good thing or not. I get the cases where there can be subtle differences between a CGFloat that is a Float on a 32 bit platform and a Double, but I'm not sure that I'm likely to see them anyway. In other words, I can do this once and only once and get stung by those edge cases where fp math breaks down at the boundaries, or I can constantly convert things a million times over and still get stung by the same edge case. So my question is, is there ANY OTHER reason than those edge cases of fp math, not to do this?