SequenceType / GeneratorType That Can Also Throw? - swift

I'm in the process of learning Swift and as an exercise, I'm writing a wrapper around SQLite. As I was experimenting, I realized that for queries that return rows (like SELECT), I could implement the SequenceType / GeneratorType protocols so that I can return a set of data for each sqlite3_step that I perform.
In practice, sqlite3_step either returns a row or is done, but in theory, it could error out. I'm not doing anything crazy with SQLite. It's just a simple data store for me, so I'm not rewriting schemas on the fly or potentially ripping the database out from under itself, but the fact remains that IN THEORY sqlite3_step could fail.
The question then is, is there a proper way to handle errors in the SequenceType / GeneratorType pattern? GeneratorType's next method doesn't support a throws parameter and returning nil just dictates the end of a sequence. Would there be a good way to handle the error and propagate it up the chain?

You have a few options, depending on what you're looking for.
If you need the Sequence to be lazy, you could use a ResultType kind of thing:
enum SQLiteRow<T> {
case Success(T), FailureTypeOne, FailureTypeTwo
}
Then, your next() method would return a SQLiteRow<T>?, where T is the type of your row.
This fits in nicely with for-loops, as you can use it like this:
for case let .Success(row) in queries {...
so the successful queries are bound to the row variable. This is only if you want to filter out the failed queries. If you wanted to stop everything, you could switch within the for loop, or have a function like this:
func sanitize<
S : SequenceType, T where
S.Generator.Element == SQLiteRow<T>
>(queries: S) -> SQLiteRow<[T]> {
var result: [T] = []
result.reserveCapacity(queries.underestimateCount())
for query in queries {
switch query {
case let .Success(x): result.append(x)
case .FailureTypeOne: return .FailureTypeOne
case .FailureTypeTwo: return .FailureTypeTwo
}
}
return SQLiteRow.Success(result)
}
That will take a sequence of possibly-failed queries, and give back either a sequence of successful queries (if none failed), or a failure type representing the first failure it came across.
However, the second option there isn't lazy. Another eager way to do it would be to use map, which (as of the latest beta) can take a closure which throws:
func makeQuery(x: String) throws -> String {
return x
}
let queries = ["a", "b", "c"]
do {
let successful = try queries.map(makeQuery)
} catch {
// handle
}
Unfortunately the lazy version of map doesn't throw, so you have to evaluate the whole sequence if you want to throw like this.

Related

Forcing an Encoder's UnkeyedEncodingContainer to only contain one type of value

As part of a custom Encoder, I am coding an UnkeyedEncodingContainer. However, the specific format I am making it for asks that all elements of an array be of the same type. Specifically, arrays can contain :
Integers one same size
Floats or Doubles
Other arrays (not necessarily all containing the same kinds of elements)
Objects
Here is the type of answer I need : The basis of an UnkeyedEncodingContainer implementation that conforms to the protocol, and enforces that all elements be of one same type among the above specified ones.
As requested, here are examples of things that should or should not be encodable :
var valid1 = []
var valid2 = [3, 3, 5, 9]
var valid3 = ["string", "array"]
var invalid1 = [3, "test"]
var invalid2 = [5, []]
var invalid3 = [[3, 5], {"hello" : 3}]
// These may not all even be valid Swift arrays, they are only
// intended as examples
As an example, here is the best I have come up with, which does not work :
The UnkeyedEncodingContainer contains a function, checkCanEncode, and an instance variable, ElementType :
var elementType : ElementType {
if self.count == 0 {
return .None
} else {
return self.storage[0].containedType
}
}
func checkCanEncode(_ value : Any?, compatibleElementTypes : [ElementType]) throws {
guard compatibleElementTypes.contains(self.elementType) || self.elementType == .None else {
let context = EncodingError.Context(
codingPath: self.nestedCodingPath,
debugDescription: "Cannot encode value to an array of \(self.elementType)s"
)
throw EncodingError.invalidValue(value as Any, context)
}
}
// I know the .None is weird and could be replaced by an optional,
// but it is useful as its rawValue is 0. The Encoder has to encode
// the rawValue of the ElementType at some point, so using an optional
// would actually be more complicated
Everything is then encoded as a contained singleValueContainer :
func encode<T>(_ value: T) throws where T : Encodable {
let container = self.nestedSingleValueContainer()
try container.encode(value)
try checkCanEncode(value, compatibleElementTypes: [container.containedType])
}
// containedType is an instance variable of SingleValueContainer that is set
// when a value is encoded into it
But this causes an issue when it comes to nestedContainer and nestedUnkeyedContainer : (used for stored dictionaries and arrays respectively)
// This violates the protocol, this function should not be able to throw
func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type) throws -> KeyedEncodingContainer<NestedKey> where NestedKey : CodingKey {
let container = KeyedContainer<NestedKey>(
codingPath: self.nestedCodingPath,
userInfo: self.userInfo
)
try checkCanEncode(container, compatibleElementTypes: [.Dictionary])
self.storage.append(container)
return KeyedEncodingContainer(container)
}
As you can see, since I need checkCanEncode to know whether it is even possible to create a NestedContainer in the first place (because if the array already has stuff inside that aren't dictionaries, then adding dictionaries to it is invalid), I have to make the function throw. But this breaks the UnkeyedEncodingContainer protocol which demands non-throwing versions.
But I can't just handle the error inside the function ! If something tries to put an array inside an array of integers, it must fail. Therefore this is an invalid solution.
Additional remarks :
Checking after having encoded the values already feels sketchy, but checking only when producing the final encoded payload is definitely a violation of the "No Zombies" principle (fail as soon as the program enters an invalid state) which I would rather avoid. However if no better solution is possible I may accept it as a last resort.
One other solution I have thought about is encoding the array as a dictionary with numbered keys, since dictionaries in this format may contain mixed types. However this is likely to pose decoding issues, so once again, it is a last resort.
You will be advised not to edit other people’s questions. If you have edits to suggest please do so in the comments, otherwise mind your own business
Unless anyone has a better idea, here is the best I could come up with :
Do not enforce that all elements be of the same type inside the UnkeyedEncodingContainer
If all elements are the same type, encode it as an array
If elements have varying types, encode it as a dictionary with integers as keys
This is completely fine as far as the encoding format goes, has minimal costs and only slightly complicates decoding (check whether keys contain integers) and greatly widens how many different Swift object will be compatible with the format.
Note : Remember that the "real" encoding step where the data is generated is not actually part of the protocol. That is where I am proposing the shenanigans should take place 😈
I don't know whether this helps you but in Swift you can overload functions. This means that you can declare functions with the same signature but with different parameter types or constraints. The compiler will take always the right choice. It's much more efficient than a type check at runtime.
The first method is called if the array conforms to Encodable
func encode<T: Encodable>(object: [T]) throws -> Data {
return try JSONEncoder().encode(object)
}
Otherwise the second method is called. If the array cannot even be encoded with JSONSerialization you can add custom encoding logic.
func encode<T>(object: [T]) throws -> Data {
do {
return try JSONSerialization.data(withJSONObject: object)
} catch {
// do custom encoding and return Data
return try myCustomEncoding(object)
}
}
This example
let array = [["1":1, "2":2]]
try encode(object: array)
calls the first method.
On the other hand this – even if the actual type is not heterogenous – calls the second method
let array : [[String:Any]] = [["1":1, "2":2]]
try encode(object: array)

Capturing a property of an object for a closure in Swift

I'm rewriting some code to append jobs to an array of closures rather than execute them directly:
var someObject: SomeType?
var jobsArray: [() -> ()] = []
// before rewriting
doExpensiveOperation(someObject!.property)
// 1st attempt at rewriting
jobsArray.append {
doExpensiveOperation(someObject!.property)
}
However, because the value of someObject might change before the closure is executed, I'm now adding a closure list as follows:
// 2nd attempt at rewriting
jobsArray.append { [someObject] in
doExpensiveOperation(someObject!.property)
}
Hopefully then if, say, someObject is subsequently set to nil before the closure executes, the closure will still access the intended instance.
But what's the neatest way to deal with the possibility that the value of .property might change before the closure is executed? Is there a better way than this?
// 3rd attempt at rewriting
let p = someObject!.property
jobsArray.append {
doExpensiveOperation(p)
}
I'm not very keen on this solution because it means changing the original line of code. I'd prefer this but it doesn't work:
// 4th attempt at rewriting
jobsArray.append { [someObject!.property] in
doExpensiveOperation(someObject!.property)
}
Pretty new to Swift, so all guidance gratefully received. Thanks!
A capture list such as [someObject] is actually syntactic sugar for [someObject = someObject], where the right hand side can be an arbitrary expression that gets bound to a new constant upon the closure being formed.
Therefore one option is to write your example as:
jobsArray.append { [property = someObject!.property] in
doExpensiveOperation(property)
}

When to use forEach(_:) instead of for in?

As documented in both Array and Dictionary forEach(_:) Instance methods:
Calls the given closure on each element in the sequence in the same
order as a for-in loop.
Nevertheless, adapted from Sequence Overview:
A sequence is a list of values that you can step through one at a
time. The most common way to iterate over the elements of a sequence
is to use a for-in loop.
Implying that iterating sequence by forEach(_:) or for in:
let closedRange = 1...3
for element in closedRange { print(element) } // 1 2 3
closedRange.forEach { print($0) } // 1 2 3
Or (Array):
let array = [1, 2, 3]
for element in array { print(element) } // 1 2 3
array.forEach { print($0) } // 1 2 3
Would gives the same output.
Why forEach(_:) even exist? i.e what is the benefit of using it instead of the for in loop? would they be the same from performance point view?
As an assumption, it could be a syntactic sugar especially when working with functional programming.
There is no performance benefit offered by forEach. In fact, if you look at the source code, the forEach function actually simply performing for-in. For release builds, the performance overhead of this function over simply using for-in yourself is immaterial, though for debug builds, it results in an observable performance impact.
The main advantage of forEach is realized when you are doing functional programming, you can add it to a chain of functional calls, without having to save the prior result into a separate variable that you'd need if you used for-in syntax. So, instead of:
let objects = array.map { ... }
.filter { ... }
for object in objects {
...
}
You can instead stay within functional programming patterns:
array.map { ... }
.filter { ... }
.forEach { ... }
The result is functional code that is more concise with less syntactic noise.
FWIW, the documentation for Array, Dictionary, and Sequence all remind us of the limitations introduced by forEach, namely:
You cannot use a break or continue statement to exit the current
call of the body closure or skip subsequent calls.
Using the return statement in the body closure will exit only from
the current call to body, not from any outer scope, and won't skip
subsequent calls.
I recently ran across a use case where using forEachwas preferable in a tangible way to for in. Let's say you want to remove all sublayers from a layer. A statement such as the below doesn't work as you need to unwrap the [CALayer]
for layer in self.videoContainerView.layer.sublayers!
If sublayers are nil, you will get a crash. This forces you to check to see if there are sublayers first. However, a forEach makes this much simpler as in the following:
self.videoContainerView.layer.sublayers?.forEach { $0.removeFromSuperlayer() }
They are more or less interchangeable, but there are two important differences.
break/continue only work in a for .. in
return in forEach will exit the closure, but will not halt the iteration.
The reason for this is that for .. in is a special form in the language (which allows break and continue to work as you expect). It is something that you can't implement in an identical way using the language itself.
However, forEach is not a special form and can be re-implemented identically by writing it as a function.
extension Sequence {
func myOwnForEach(_ body: (Self.Element) throws -> Void) rethrows {
let it = Self.makeIterator()
while let item = it.next() {
body(item)
}
}
}
In addition to above answers one more reason that differentiates for loop from forEach is that with for loop we can also chose to implement that logic using where based pattern matching instead, like
for adBanner in adBanners where !adBanner.isLoading {
The above kind of control flow related features are what makes for loops so powerful, but if we don’t need that level of control, using a call to forEach might give us slightly simpler-looking code.
So in short using a for loop gives us a much greater degree of control over an iteration

What does () mean in Swift?

I have the following function in Swift 3
func fetchOrders(_ completionHandler: (_ orders: [Order]) -> Void)
{
ordersStore.fetchOrders { (orders: () throws -> [Order]) -> Void in
do {
let orders = try orders()
completionHandler(orders)
} catch {
completionHandler([])
}
}
}
What does _ completionHandler argument in fetchOrders mean?
What does (orders: () throws -> [Order]) mean?
PS : I am new to iOS and Swift
There's quite a lot in here, so we'll break it down one piece at a time:
func fetchOrders(_ completionHandler: (_ orders: [Order]) -> Void)
This is a function called fetchOrders.
It has one parameter (completionHandler) and returns nothing.
The first _ indicates that there is no "external name" of the first parameter. That is, you do not have to label it (in fact, you cannot). (For subtle reasons that don't really matter here, I believe the author made a mistake using _ there, and I would not have done that.)
The completionHandler is the "internal name," what the parameter is called inside the function.
The type of completionHandler is (_ orders: [Order]) -> Void. We'll break that down now.
This value is a closure that takes an [Order] (array of Order) and returns Void. Informally this means "returns nothing" but literally means it returns the empty tuple ().
The _ orders: syntax is in practice a comment. In principle the _ is an external name (but that's the only legal external name for a closure), and orders is an internal name, but in reality, closures parameters do not have names in any meaningful way, so this is purely informational.
I believe this is a poor use of the closure parameter commenting system. Since orders tells us nothing more than [Order], I would have omitted it, and made the type just ([Order]) -> Void.
Now we'll turn to the next line:
ordersStore.fetchOrders { (orders: () throws -> [Order]) -> Void in
This calls the fetchOrders method on ordersStore. We can tell from this code that fetchOrders takes a closure parameter. This is called "trailing closure" syntax in Swift, and is why I would not have used the _ for our closure. With trailing closure syntax, the external name of the parameter is not needed.
The author has provided type information here that probably wasn't necessary, but we can explore it anyway. This could likely have been written as just { orders in, but then the reader would probably have been surprised by this somewhat unusual code.
We have been passed a closure called orders that takes nothing and returns [Order] or throws an error. Basically this is a way to say that fetchOrders might fail.
The author is working around an awkwardness in Swift's throws system, which does not have a natural way to express an asynchronous action that might fail. This is one way to fix it; you pass a throwing (i.e. a possibly failing) function. I don't favor this approach, I favor using a Result enum for this case because I think it scales better and avoids possible unintended side effects, but that's a debatable point (and the Swift community hasn't really decided how to deal with this common problem).
This all leads us to:
do {
let orders = try orders()
completionHandler(orders)
} catch {
completionHandler([])
}
This is where the orders closure is evaluated. (This is very important; if orders has side effects, this is when they occur, which may be on a different queue than was intended. That's one reason I don't favor this pattern.) If the closure succeeds, we return its result, otherwise we return [] in the catch below.
In this particular case, the throws approach is slightly silly, because it's silently flattened into [] without even a log message. If we don't care about the errors, then failure should have just returned [] to start with and not messed with throws. But it's possible that other callers do check the errors.
In either case, we call the completionHandler closure with our result, chaining this back to our original caller.
This do/catch block could have been more simply written as:
let completedOrders = try? orders() ?? []
completionHandler(completedOrders)
This makes it clearer that we're ignoring errors by turning it into an optional, and avoids code duplication of the call to completionHandler.
(I just add the extra let binding to make the code a little easier to read; it isn't needed.)
The completionHandler argument means that the expected parameter (named completionHandler) must be a function that takes a list of Order objects and does not return any value.
completionHandler is the a variable name. In this specific example, this variable is a callback. You know is a callback function because (orders: [Order]) -> Void is it's data type; in this particular case, said data type is a function that receives an array of Order objects in a variable _orders and doesn't have a return value (the Void part).
TL;DR:
it's the variable name, of type:
function which receives an array of Order as a parameter and acts as a callback.

Can a condition be used to determine the type of a generic?

I will first explain what I'm trying to do and how I got to where I got stuck before getting to the question.
As a learning exercise for myself, I took some problems that I had already solved in Objective-C to see how I can solve them differently with Swift. The specific case that I got stuck on is a small piece that captures a value before and after it changes and interpolates between the two to create keyframes for an animation.
For this I had an object Capture with properties for the object, the key path and two id properties for the values before and after. Later, when interpolating the captured values I made sure that they could be interpolated by wrapping each of them in a Value class that used a class cluster to return an appropriate class depending on the type of value it wrapped, or nil for types that wasn't supported.
This works, and I am able to make it work in Swift as well following the same pattern, but it doesn't feel Swift like.
What worked
Instead of wrapping the captured values as a way of enabling interpolation, I created a Mixable protocol that the types could conform to and used a protocol extension for when the type supported the necessary basic arithmetic:
protocol SimpleArithmeticType {
func +(lhs: Self, right: Self) -> Self
func *(lhs: Self, amount: Double) -> Self
}
protocol Mixable {
func mix(with other: Self, by amount: Double) -> Self
}
extension Mixable where Self: SimpleArithmeticType {
func mix(with other: Self, by amount: Double) -> Self {
return self * (1.0 - amount) + other * amount
}
}
This part worked really well and enforced homogeneous mixing (that a type could only be mixed with its own type), which wasn't enforced in the Objective-C implementation.
Where I got stuck
The next logical step, and this is where I got stuck, seemed to be to make each Capture instance (now a struct) hold two variables of the same mixable type instead of two AnyObject. I also changed the initializer argument from being an object and a key path to being a closure that returns an object ()->T
struct Capture<T: Mixable> {
typealias Evaluation = () -> T
let eval: Evaluation
let before: T
var after: T {
return eval()
}
init(eval: Evaluation) {
self.eval = eval
self.before = eval()
}
}
This works when the type can be inferred, for example:
let captureInt = Capture {
return 3.0
}
// > Capture<Double>
but not with key value coding, which return AnyObject:\
let captureAnyObject = Capture {
return myObject.valueForKeyPath("opacity")!
}
error: cannot invoke initializer for type 'Capture' with an argument list of type '(() -> _)'
AnyObject does not conform to the Mixable protocol, so I can understand why this doesn't work. But I can check what type the object really is, and since I'm only covering a handful of mixable types, I though I could cover all the cases and return the correct type of Capture. Too see if this could even work I made an even simpler example
A simpler example
struct Foo<T> {
let x: T
init(eval: ()->T) {
x = eval()
}
}
which works when type inference is guaranteed:
let fooInt = Foo {
return 3
}
// > Foo<Int>
let fooDouble = Foo {
return 3.0
}
// > Foo<Double>
But not when the closure can return different types
let condition = true
let foo = Foo {
if condition {
return 3
} else {
return 3.0
}
}
error: cannot invoke initializer for type 'Foo' with an argument list of type '(() -> _)'
I'm not even able to define such a closure on its own.
let condition = true // as simple as it could be
let evaluation = {
if condition {
return 3
} else {
return 3.0
}
}
error: unable to infer closure type in the current context
My Question
Is this something that can be done at all? Can a condition be used to determine the type of a generic? Or is there another way to hold two variables of the same type, where the type was decided based on a condition?
Edit
What I really want is to:
capture the values before and after a change and save the pair (old + new) for later (a heterogeneous collection of homogeneous pairs).
go through all the collected values and get rid of the ones that can't be interpolated (unless this step could be integrated with the collection step)
interpolate each homogeneous pair individually (mixing old + new).
But it seems like this direction is a dead end when it comes to solving that problem. I'll have to take a couple of steps back and try a different approach (and probably ask a different question if I get stuck again).
As discussed on Twitter, the type must be known at compile time. Nevertheless, for the simple example at the end of the question you could just explicitly type
let evaluation: Foo<Double> = { ... }
and it would work.
So in the case of Capture and valueForKeyPath: IMHO you should cast (either safely or with a forced cast) the value to the Mixable type you expect the value to be and it should work fine. Afterall, I'm not sure valueForKeyPath: is supposed to return different types depending on a condition.
What is the exact case where you would like to return 2 totally different types (that can't be implicitly casted as in the simple case of Int and Double above) in the same evaluation closure?
in my full example I also have cases for CGPoint, CGSize, CGRect, CATransform3D
The limitations are just as you have stated, because of Swift's strict typing. All types must be definitely known at compile time, and each thing can be of only one type - even a generic (it is resolved by the way it is called at compile time). Thus, the only thing you can do is turn your type into into an umbrella type that is much more like Objective-C itself:
let condition = true
let evaluation = {
() -> NSObject in // *
if condition {
return 3
} else {
return NSValue(CGPoint:CGPointMake(0,1))
}
}