Is there a placeholder for doubles in Swift? - swift

I want to be able to call various doubles from a collection but I'm having trouble setting it up.
" " can be used on the right side of a value/constant declaration as a placeholder for string values, is there a way to do the same for doubles? I Googled but wasn't able to find anything.

For original question
A "nan" "not a number" has a specific meaning of an undefined or unrepresentable number. There are quiet and signaling versions. You can get a nan by multiplying Double.infinity by something.
let alarmTriggeringNotANumber: Double = .signalingNan
let quietNotANumber: Double = .nan
let hero: Double = .zero
let loveLife: Double = -.infinity
Technically, "" isn't a placeholder, but an empty collection. Nil would be a way to indicate the absence of a value.
For the separate question in the comment
I want to get a bunch of latitude and longitude coordinates
and call them from a collection using one name. For example var latitude = x, where x would represent whichever object I call to it.
You can create a Dictionary/Set where the element is of type Coordinates.
struct Coordinates {
let lat: Double
let long: Double
}
let batCavesByCountryID: [UUID : [Coordinates]]
You can create a type alias that allows you to reference a tuple with a specific signature.
You can also create a typealias for Lat/Long.
Typealiases are useful to reduce code maintenance. For example, you might change IDs from UUIDs to Strings. Using a typealias can be more expressive and let you change a whole app with one line of code. However, going overboard will just make this obscure. You can add extensions to type aliases, but tuples are currently not extendable.
typealias Coordinates = (lat: Latitude, long: Longitude)
typealias Latitude = Double
typealias Longitude = Double

Related

While using Measurement, I am unable to return a Double even though it is supposed to return a Double?

In an attempt to create a function using Swift's Measurements which returns a Double. I apparently am smol brained and can't figure out why, even though my function is calling to return a double, it is giving me an error of the following :
Cannot convert return expression of type 'Measurement<UnitLength>' to return type 'Double'
func convertImperialHeightToCM() -> Double {
// User input of Feet, forcing unwrap will likely fuck this up...
let convertFeetToCm = Measurement(value: userData!.userHeightFeet, unit: UnitLength.feet)
let feetToCentimeters = convertFeetToCm.converted(to: UnitLength.centimeters)
// User input of Inches, forcing upwrap will likely fuck this up...
let convertInchesToCm = Measurement(value: userData!.userHeightInches, unit: UnitLength.inches)
let inchesToCentimeters = convertInchesToCm.converted(to: UnitLength.centimeters)
// Compute this shit and whip the numbers into one...
let addUpCentimeters = feetToCentimeters + inchesToCentimeters
return addUpCentimeters
}
I am then calling this function later on in other functions as well (will likely make a single nested function but breaking them up to help with testability, plus I'm a noob.
The issue is that addUpCentimeters is a measurement unit, not a double. You therefore have two options, either you return that unit, or you call addUpCentimeters.value to get the actual double value.

Converting NSPoint to CGPoint using NSPointToCGPoint

How difficult can it be to access x and y coordinates from NSPoint...Can't believe it.
I get an NSPoint from following call:
var mouseLoc = [NSEvent .mouseLocation]
I need to access x and y coordinates. NSPoint does not offer a getter like CGPoint. I learned: I have to cast into CGPoint but nothing that I found seems to work in latest Swift anymore:
var p = (CGPoint)mouseLoc // error: Cannot convert value of type '[NSPoint]' (aka 'Array<CGPoint>') to expected argument type 'NSPoint' (aka 'CGPoint')
var p = NSPointToCGPoint(mouseLoc) // error: Cannot convert value of type '[NSPoint]' (aka 'Array<CGPoint>') to expected argument type 'NSPoint' (aka 'CGPoint')
I am sure it's a complete beginner thing but I just don't get it.
Swift uses a different syntax for calling instance or class methods than Objective-C.
// Objective-C
NSPoint mouseLoc = [NSEvent mouseLocation]
translates to
// Swift
let mouseLoc = NSEvent.mouseLocation
whereas your Swift code creates an array containing a single NSPoint.
Also NSPoint is a type alias for CGPoint:
typealias NSPoint = CGPoint
so you can simply use the same accessors:
// Swift
let mouseLoc = NSEvent.mouseLocation
let xCoord = mouseLoc.x
let yCoord = mouseLoc.y
Here seems what mouseLoc is an array of NSEvent. Iterate through it and convert each point individually or use only one (first or last element).
Iterate like this:
let allPoints = mouseLoc.forEach { NSPointToCGPoint($0) }
But in this case you also will get an array, but now of CGPoint. You probably want to use only one of it, first or last.
But also maybe you have an array with only one element - use .first.

I'm confused about value type () in Swift. What is it, and how am I meant to use it?

I'm trying to convert height in feet with a decimal to height in feet and inches.
I'm trying to use the .round(.down) method to get the feet, and multiply the decimal by 12 for the inches. I'm getting all kinds of errors, like so:
var heightInFeet: Float = 5.45
let feetRounded = heightInFeet.round(.down) // feetRounded is "type ()." What is that?
percentToNextFoot = heightInFeet - feetRounded // Error: Binary operator '-' cannot be applied to operands of type 'Float' and '()'
I tried the following and got another error:
percentToNextFoot = heightInFeet - Float(feetRounded) // Cannot invoke initializer for type 'Float' with an argument list of type '(())'
I finally got it working by avoiding the .round() method, but I'm still really confused by the value type (). Can anyone explain what's going on here?:
var heightInFeet: Float = 5.45
var feet = Int(heightInFeet) // 5
var percentToNextFoot = heightInFeet - Float(feet) // 0.45
let heightInFeetAndInches = "\(feet)ft \(Int(percentToNextFoot * 12))in" // 5ft 5in
() is shorthand for void. It means "no value is possible here".
In this example, it means that the .round() method does not return anything - it is a mutating function called on its receiver. So assigning its void return to a var causes that var's type to be inferred to be void. Void vars can be useful, sometimes, rarely*, but not in this case.
Methods on value types often come in pairs: a verb like round, and a passive verb e.g. rounded. The first operates directly on, and modifies, its target; the second returns a modified version of its target. For another example, see sort() and sorted() on collections, or append(_) and appending(_) on strings, etc.
(* note: filter is an annoying exception; it means "filtered", and there is no handy "filter in place".)
To get the effect you were going for in the first example, rounded() is what you want.
--
(* To answer the tangential question in your title: how would one actually use a void variable? Well, here's a way I use them sometimes:
In an object with some setup that I would like to happen sometime after init, but guaranteed at most once per instance, I used to use Objective-C's dispatch_once. That's not available in Swift, so now I'll make a lazy void member like so:
class Foo {
lazy var setup: () = {
// do some complicated stuff I couldn't do in `init` for some reason
// this will only run once
}()
func doSomethingUseful() {
_ = setup // runs the setup initializer just the first time we get here
// do useful things that depend on setup having happened
}
}
I'll leave it to the comments to judge whether we're "meant to" use such a technique. :)
Welcome to stack overflow!
Double has two rounding methods:
Double.round(), which rounds a Double value by mutating it in-place. This is one you called. It doesn't return anything, which strictly speaking means it returns Void, a.k.a. (), the empty tuple.
Double.rounded(), which rounds a Double value by returning a new Double. This is the one you probably intended to call.
By calling the first, and trying to assign the value to a variable, you end up with a variable of type Void, whose value is ().
This is a common Swift convention: "object.foo" edits it in place. "object.fooed" returns a mutated copy.
That said, in your case, I would recommend doing this using the existing Measurement API:
import Foundation
extension Measurement where UnitType == UnitLength {
func toFeetAndInches() -> (feet: Measurement<UnitLength>, inches: Measurement<UnitLength>) {
let numberOfWholeFeet = self.converted(to: .feet).value.rounded(.towardZero)
return (
feet: Measurement(value: numberOfWholeFeet, unit: UnitLength.feet),
inches: Measurement(value: self.value - numberOfWholeFeet, unit: UnitLength.feet).converted(to: .inches)
)
}
}
let heightInFeet = Measurement(value: 5.5, unit: UnitLength.feet)
let (feet, inches) = heightInFeet.toFeetAndInches()
let mf = MeasurementFormatter()
mf.unitOptions = .providedUnit // force the use of feet/inches, rather than the unit appropriate for the user's locale.
mf.unitStyle = .medium
print(mf.string(for: feet)!, mf.string(for: inches)!) // => "5 ft. 6 in."
If you look at the reference for the round function of Float type, you will see that it returns nothing. It just mutate the float you called this method on.
You can do
var feetRounded = heightInFeet
feetRounded.round(.down)
Please take a look at the documentation. The method
mutating func round(_ rule: FloatingPointRoundingRule)
has no return value (aka Void aka ())
If you need a result you have to use rounded(_:) which has a return value
func rounded(_ rule: FloatingPointRoundingRule) -> Float
round changes the value in place; you use it like this:
var heightInFeet: Float = 5.45
heightInFeet.round(.down)
You notice that no value is returned; there is no = in the second line. We do not need to set anything to the result of the round call, because it has no result.
If, as in your code, you accidentally do capture the "result", it is expressed as type (). So () is the "result" type of a method call that has no result.
When we accidentally write this:
var heightInFeet: Float = 5.45
let x = heightInFeet.round(.down)
we get this error: "Constant 'x' inferred to have type '()', which may be unexpected." That is just a fancy way of saying, "You've taken a method call that has no result and captured its 'result'. You probably didn't mean to do that!" And indeed, you didn't.

swift function to iterate possibly reversed array

I'd like to create a function that will iterate over an array (or collection or sequence). Then I will call that function with an array, and the reversed version of the array (but efficiently: without creating a new array to hold the reverse).
If I do this:
func doIteration(points: [CGPoint]) {
for p in points {
doSomethingWithPoint(p)
}
// I also need random access to points
doSomethingElseWithPoint(points[points.count-2]) // ignore obvious index error
}
And if I have this:
let points : [CGPoint] = whatever
I can do this just fine:
doIteration(points)
But then if I do this:
doIteration(points.reverse())
I get 'Cannot convert value of type 'ReverseRandomAccessCollection<[CGPoint]> to expected argument type [_]'
Now, I DON'T want to do this:
let reversedPoints : [CGPoint] = points.reverse()
doIteration(reversedPoints)
even though it will work, because that will (correct me if I'm wrong) create a new array, initializing it from the ReverseRandomAccessCollection returned by reverse().
So I guess I'd like to write my doIteration function to take some sort of sequence type, so I can pass in the result of reverse() directly, but ReverseRandomAccessCollection doesn't conform to anything at all. I think I'm missing something - what's the accepted pattern here?
If you change your parameter's type to a generic, you should get the functionality you need:
func doIteration
<C: CollectionType where C.Index: RandomAccessIndexType, C.Generator.Element == CGPoint>
(points: C) {
for p in points {
doSomethingWithPoint(p)
}
doSomethingElseWithPoint(points[points.endIndex - 2])
}
More importantly, this won't cause a copy of the array to be made. If you look at the type generated by the reverse() method:
let points: [CGPoint] = []
let reversed = points.reverse() // ReverseRandomAccessCollection<Array<__C.CGPoint>>
doIteration(reversed)
You'll see that it just creates a struct that references the original array, in reverse. (although it does have value-type semantics) And the original function can accept this new collection, because of the correct generic constraints.
You can do this
let reversedPoints : [CGPoint] = points.reverse()
doIteration(reversedPoints)
or this
doIteration(points.reverse() as [CGPoint])
but I don't think there is any real difference by the point of view of a the footprint.
Scenario 1
let reversedPoints : [CGPoint] = points.reverse()
doIteration(reversedPoints)
Infact in this case a new Array containing references to the CGPoint(s) present in the original array is created. This thanks to the Copy-on-write mechanism that Swift used to manage structures.
So the memory allocated is the following:
points.count * sizeOf(pointer)
Scenario 2
On the other hand you can write something like this
doIteration(points.reverse() as [CGPoint])
But are you really saving memory? Let's see.
A temporary variable is created, that variable is available inside the scope of the function doIteration and requires exactly a pointer for each element contained in points so again we have:
points.count * sizeOf(pointer)
So I think you can safely choose one of the 2 solutions.
Considerations
We should remember that Swift manages structures in a very smart way.
When I write
var word = "Hello"
var anotherWord = word
On the first line Swift create a Struct and fill it with the value "Hello".
On the second line Swift detect that there is no real reason to create a copy of the original String so writes inside the anotherWord a reference to the original value.
Only when word or anotherWord is modified Swift really create a copy of the original value.

Swift Cannot invoke '+' with an argument list of type '($T10, CGFloat)'

I am a beginner in Swift.
I have this error
Cannot invoke '+' with an argument list of type '($T10, CGFloat)'
func loadBackground(key: NSString, width:CGFloat, height:CGFloat) -> UIImage!{
var imageName = key + "_" + width + "_" + height
return UIImage(named: imageName)!
}
The error states that you're trying to concat a string and a float (or different types anyway, that cannot be concatenated via +). You could just interpolate & construct the string like this instead:
func loadBackground(key: NSString, width:CGFloat, height:CGFloat) -> UIImage!{
var imageName = "\(key)_\(width)_\(height)"
return UIImage(named: imageName)!
}
You can read more about this here
OK a few more words after #Grimxn's comment...
First of all, specifying width and height as CGFloats might be handy when calling the method and grabbing values from frame/bounds, but it will most probably bite you in the future (think for example a frame with an almost 'perfect' width like 120.001 - or any crazy number that came out from a division for example). So, I believe that Ints would serve better in this case in order to maintain a (relatively safer) mapping between sizes/filenames.
PS. Also a let might be preferable over a var in your case since imageName is just constructed and returned without further modification and finally a UIImage? as a return type would force you to handle (or at least check first for) any cases that the image could not be found and hence make your code safer.