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

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.

Related

How do I ensure a double input in a TextField? (Swift)

New to Swift here. I'm making an application that will take a price from the user through a TextField, and calculate the tip. In order for it to not crash, I want it to only take a valid double but I'm unsure on how to do so.
Button function handling this process:
#IBAction func calculate_eighteen_perc(_ sender: Any) {
let bill:Double = round(Double(user_bill_input.text!)! * 100) / 100.0
let tip:Double = round(bill * 0.18 * 100) / 100.0
let total:Double = bill + tip
result_display.text = "Tip Amount: $\(tip); Total: $\(total)"
}
The cases that will crash the program, to my knowledge, are:
Whitespace before number.
Any non-number character in input.
Multiple decimal points.
Empty input (nil).
Is there a way to handle this gracefully, without writing a condition to check each case?
Thanks in advance for any assistance.
You generally want to avoid forced unwrapping for the reason you identified -- invalid entries will crash your app. Double(user_bill_input_text) won't crash your app by itself if the user's input isn't a Double. The return type of casting to Double from a String is an optional Double, and its value will simply be nil if one of the invalid entry conditions you identified occurs.
Then, you can use a guard statement, in which the rest of the function will execute if the value is non-nil. If it is, you can set an error condition and exit the function safely.
#IBAction func calculate_eighteen_perc(_ sender: Any) {
let input = Double(user_bill_input_text)
guard let input = input else {
print("Invalid entry. Try again.")
return
}
// put the rest of the code that you only want to execute if the input
// is a valid Double here
}

Is there a placeholder for doubles in 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

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.

Why converting Double to Int doesn't return optional Int in Swift?

Converting a String to Int returns an optional value but converting a Double to Int does not return an optional value. Why is that? I wanted to check if a double value is bigger than maximum Int value, but because converting function does not return an optional value, I am not be able to check by using optional binding.
var stringNumber: String = "555"
var intValue = Int(stringNumber) // returns optional(555)
var doubleNumber: Double = 555
var fromDoubleToInt = Int(doubleNumber) // returns 555
So if I try to convert a double number bigger than maximum Integer, it crashes instead of returning nil.
var doubleNumber: Double = 55555555555555555555
var fromDoubleToInt = Int(doubleNumber) // Crashes here
I know that there's another way to check if a double number is bigger than maximum Integer value, but I'm curious as why it's happening this way.
If we consider that for most doubles, a conversion to Int simply means dropping the decimal part:
let pieInt = Int(3.14159) // 3
Then the only case in which the Int(Double) constructor returns nil is in the case of an overflow.
With strings, converting to Int returns an optional, because generally, strings, such as "Hello world!" cannot be represented as an Int in a way that universally makes sense. So we return nil in the case that the string cannot be represented as an integer. This includes, by the way, values that can be perfectly represented as doubles or floats:
Consider:
let iPi = Int("3.14159")
let dPi = Double("3.14159")
In this case, iPi is nil while dPi is 3.14159. Why? Because "3.14159" doesn't have a valid Int representation.
But meanwhile, when we use the Int constructor which takes a Double and returns non-optional, we get a value.
So, if that constructor is changed to return an optional, why would it return 3 for 3.14159 instead of nil? 3.14159 can't be represented as an integer.
But if you want a method that returns an optional Int, returning nil when the Double would overflow, you can just write that method.
extension Double {
func toInt() -> Int? {
let minInt = Double(Int.min)
let maxInt = Double(Int.max)
guard case minInt ... maxInt = self else {
return nil
}
return Int(self)
}
}
let a = 3.14159.toInt() // returns 3
let b = 555555555555555555555.5.toInt() // returns nil
Failable initializers and methods with Optional return types are designed for scenarios where you, the programmer, can't know whether a parameter value will cause failure, or where verifying that an operation will succeed is equivalent to performing the operation:
let intFromString = Int(someString)
let valueFromDict = dict[someKey]
Parsing an integer from a string requires checking the string for numeric/non-numeric characters, so the check is the same as the work. Likewise, checking a dictionary for the existence of a key is the same as looking up the value for the key.
By contrast, certain operations are things where you, the programmer, need to verify upfront that your parameters or preconditions meet expectations:
let foo = someArray[index]
let bar = UInt32(someUInt64)
let baz: UInt = someUInt - anotherUInt
You can — and in most cases should — test at runtime whether index < someArray.count and someUInt64 < UInt32.max and someUInt > anotherUInt. These assumptions are fundamental to working with those kinds of types. On the one hand, you really want to design around them from the start. On the other, you don't want every bit of math you do to be peppered with Optional unwrapping — that's why we have types whose axioms are stated upfront.

constant 'result' inferred to have type (), which may be unexpected

#IBAction func operate(sender: UIButton) {
if let operation = sender.currentTitle {
if let result = brain.performOperation(operation) {
displayValue = result
}
else {
displayValue = 0.0
}
}
}
I am new to coding so pardon my coding format and other inconsistencies. I have been trying out the iOS 8 intro to swift programming taught by Stanford university and I have ran into a problem with the modified calculator.
I get three errors. The first one is a swift compiler warning - at
if let result = brain.performOperation(operation)
It says
constant 'result' inferred to have type () which may be unexpected.
It gives me the suggestion to do this ----
if let result: () = brain.performOperation(operation)
The other two errors are
Bound value in a conditional binding must be of Optional type at if let result line
Cannot assign a value of type () to a value of Double at "displayValue = result"
Here is the github link if anyone needs more information on the code.
Thanks in advance.
Guessing from the errors, I expect that performOperation() is supposed to return Double? (optional double) while if fact it returns nothing.
I.e. it's signature is probably:
func performOperation(operation: String) {
// ...
}
.. while in fact it should be:
func performOperation(operation: String) -> Double? {
// ...
}
Reason why I think so is that this line: if let result = brain.performOperation(operation) is call "unwrapping the optional" and it expects that the assigned value is an optional type. Later you assign the value that you unwrap to the variable that seems to be of Double type.
By the way, the shorter (and more readable) way to write the same is:
displayValue = brain.performOperation(operation) ?? 0.0
It looks like brain.performOperation() does not return a result at all,
so there is no optional value, too.