- Objective-C is not dead, it’s awesome, it’s a lovely language but you just won’t find a job if stick to it.
- Daniel misses the Objective-C’s
*in Swift. Because that way he knows that something is (or isn’t) a reference type. He also misses header files because those are nice overviews of what he can call in a certain class. Otherwise, he loves Swift. - Context is important in code. If you would want to get
timeIntervalUntilNowyou need the inverse oftimeIntervalSinceNowbecause the latter would return a negative number. Just putting a-in front of it somewhere is bad, because there’s no context. Wrapping it in a method,-is okay to put there. That provides context. SotimeIntervalUntilNowwould just return-timeIntervalSinceNow. - Translating things from Objective-C to Swift is not thinking in Swift. Thinking in Swift doesn’t mean monads, map, flatmap, reduce and all the haskell stuff.
- If you use protocols, like
SequenceTypeyou get a lot for free on certain models. If you would have a model with your app sales and you make yourAppSalesstruct conform toSequenceTypeyou could easily iterate through your numbers, you could use amapfunction to calculate revenue and more. - A revenue calculation could be
Double(dailySales) * 0.99 * 0.70but that looks pretty abstract. Cleaner code would be:Double(dailySales) * unitPrice * sellersPercentage. And pulling that out from a map function and putting the calc into a function you could write something like:appSales.map(appRevenueForCopies). Filtering out anything < 0 like thisappSales.map{$0 > 0 ? $0 : 0}.map(appRevenueForCopies). But that’s not very readable. Better code:appSales.map(negativeToZero).map(appRevenueForCopies). - The
appRevenueForCopiesfunction returns aDouble. But it’s not obvious what that double is. You createtypealias USDollars = Double. Rounding the revenue in a function could result in something like:toTheNearestPenny(appRevenueForCopies(copiesSold)). But that’s backwards, you read it inside out. - Doing
infix >> {associativity left}helps. Function body is like this.
func >> <T, U>(input:T, transform: T->U) -> U {
return transform(input)
}
toTheNearestPenny(appRevenueForCopies(copiesSold)) can now be written as numberOfCopies >> revenueForCopies >> toTheNearestPenny.
appSales.map{$0 > 0 ? $0 : 0}.map(appRevenueForCopies)isn’t very pretty. Pulling that apart to two functions is better.func replaceNegativeWithZero(),func arrayOfSales()andfunc calcRevenueFromSales(). With the new infix:appSales >> arrayOfSales >> replaceNegativeWithZero >> calcRevenueFromSales. This is very readable. Maybe not super transparent but you abstract away all the cruft. If you want to know more you can zoom in on each component of this.- But.. custom operators. Can we do it without? Yes. If we extend
Intwe can put a private method on anIntextension that returns a double. We can do the same with rounding to the nearest penny on Double. And then extendingIntagain we canreturn revenueForCopiesSold().roundedToTheNearestPenny(). Resulting in code like7.revenueForCopiesSold(). - Reduce is map, flatmap and filter. All at once. Try to implement map, flatmap and filter using a reduce call and generics. It’s not efficient or a good idea per se but it looks very interesting. Performance for this implementation is not good.
- Transducers can help with this. There’s no formal implementation in Swift but there’s examples if you look for them. A transducer takes a function from S to T (
f: S -> T).[Copies]->[USDollars] = T.[Int]->[USDollars] = Ssof: S -> Tis actuallyf: Int -> USDollars. I really didn’t understand this last part.. it was so complex and amazing.