Why would Error always be NSError? - swift

I have the following class defined on a Playground with Swift 3:
class MyError: Error {
}
Then, I create an instance of such class and check if it is a NSError
let firstError = MyError()
firstError is NSError // Output: false
The output is as expected, and I also get a warning which indicates Cast from 'MyError' to unrelated type 'NSError' always fails. This makes total sense for me, but if I change the code a little bit and declare the variable as an Error, I get a strange result:
var secondError: Error
secondError = MyError()
secondError is NSError // Output: true
And in this case I get a warning in the last line that says 'is' test is always true. I don't get why an Error would always be an NSError, when the model is defined the other way round (NSError: Error). Any idea what is going on here?

This is intentional behavior to allow Swift Error types to interop with Objective-C.
The compiler will only do the coercion when bridging Swift errors to Objective-C, or in your case where all you have is the Error existential that could contain anything... remember it could just as well have come from a throws function written in Objective-C. This also gives you an out to get the coercion if you need to pass an NSError directly to some Objective-C method as a parameter (for whatever reason).

Related

Implementing Maybe type using enum

My definition of Maybe enum:
enum Maybe<A> {
case Nothing
case Just(A)
}
Printing a Just value works perfectly:
print(Maybe.Just(10))
Output:
 swiftc -o main main.swift
 ./main
Just(10)
However, fails in case of a Nothing value:
print(Maybe.Nothing)
Output:
error: argument type 'Maybe<_>' does not conform to expected type 'Any'
What's happening, here ?
Could someone give me some background information about this issue and how can I solve it ?
There's no such thing as Maybe.Nothing. There's no such type as Maybe, only Maybe<A>.
Whenever declaring a variable of type Maybe, you need to specify its generic type parameter, even in case of Nothing.
let noInt = Maybe<Int>.Nothing
Unrelated to your question, but enum cases should be lowerCamelCase. You should also give meaningful names to generic type parameters instead of using single letters.
enum Maybe<Value> {
case nothing
case just(Value)
}
It seems you are trying to reimplement the existing Optional type. If you're doing this as a learning exercise, it might be worth actually looking at the implementation of Optional for best-practices.

Difference between wrapping a value and explicitly declaring value as a type in Swift

I came across a heterogeneous dictionary definition like this on a tutorial online:
var mixedMap4 = [AnyHashable(0): "Zero" as Any,
AnyHashable(1): 1.0 as Any,
AnyHashable("pi"): 3.14 as Any]
I was wondering why the author chose to write
AnyHashable(0) instead of 0 as AnyHashable. When I tried this on Swift playground, it also worked. However when I turned "Zero" as Any into Any(0) it gives the following
error: error: The Dictionary.xcplaygroundpage:41:34: error: protocol
type 'Any' cannot be instantiated var mixedMap4 = [AnyHashable(0):
Any("Zero") ,
Thank you for the answer
The clue is in the error message.
AnyHashable is a struct that type-erases the underlying hashable type, and so can be directly instantiated as an object
Any is a protocol and therefore can't be directly instantiated, although all other types can be complied with it, thus a String such as "Zero" can be cast as Any but Any(String) is meaningless.
To me it all just feels like a bucket load of trouble waiting to happen!

Realm lazy results type-erasure

I'm working on an iOS app with Realm as the database and I'm confronted to a problem I can't fix without your help.
I have a function that queries objects from my Realm instance like so:
static func trainings(containing exercise: Exercise) -> Results<Training>? {
return Realm.workoutDatabase?.objects(TrainingEntry.self)
.filter({ $0.exercise == exercise })
.compactMap({ $0.training })
}
This code produces the following error:
Cannot convert return expression of type 'LazyMapCollection<LazyFilterCollection<LazyMapCollection<LazyFilterCollection<Results<TrainingEntry>>, Training?>>, Training>?' to return type 'Results?'`
There error is obviously that the return type should not be Results<Training>? but LazyMapCollection<LazyFilterCollection<LazyMapCollection<LazyFilterCollection<Results<TrainingEntry>>, Training?>>, Training>?.
Outch! That type is soooooo long.
I tried to set [Training]? as the return type for the function and it worked.
But by doing so, I'm afraid that this will implicitly cast the returned result of the expression into an array, thus loosing the laziness of the collection?
As far I as know, I need a type-eraser to get a much shorter type, but I'm definitely not an expert on that particular subject.
I know that the Swift Standard Library provides a few type-erasure structs, such as AnyGenerator, AnySequence but I'm afraid I don't know enough about type-erasure to use them in my case.
So my question is, how to use type-erasure to get a cleaner return type for my function?
Edit:
I tried to cast the expression to AnyRandomAccessCollection but I get the following error:
Type 'LazyFilterCollection<LazyMapCollection<LazyFilterCollection<Results<TrainingEntry>>, Training?>>' does not conform to protocol 'RandomAccessCollection'
I also tried to cast to AnyCollection and AnyBidirectionalCollection, both of them work, but then I'm loosing the ability to subscript with an Int, which is something I want to keep.

'String' is not convertible to 'String?'

Using ReactiveSwift, I've used the following code:
let alertMessageProperty = MutableProperty<String?>(nil)
...
.on(failed: { self.alertMessageProperty.value = $0.localizedDescription })
...
which means:
self.alertMessageProperty.value is of type String?
in .on(failed:), failed is of type ((Error) -> Void)? so $0 is of type Error and $0.localizedDescription is of type String.
in a simple Playground, assigning a String to a String? variable works fine, as expected.
It does not compile and I get this error:
'String' is not convertible to 'String?'
I think String is SO convertible to String?. What's going on here?
Versions: Swift 3.2 - ReactiveSwift 2.0.1
There is a lot missing in your example so I can not reproduce the exact problem.
Your code that you left out in ... is probably a lot more complicated, maybe a chain of multiple reactive operations, and my guess is that the actual error is something completely different somewhere in that code. The error message you're getting is just misleading due to some bug i the Swift compiler.
You can try to break up your code into smaller pieces and see if the compiler now fails at a different place and try to narrow it down that way.

`?` causing segmentation fault in Xcode 8.3.2's Swift compiler

I have this line of Swift which use to compile without issue
let layoutSettings = try LayoutSettings.deserialize(params: layoutSettingsParams as Dictionary<String, AnyObject?>)
As of Xcode 8.3.2 I get the error
Swift Compiler Error
Command failed due to signal:
Segmentation fault: 11
If I remove the ? at the end of the line of code it compiles without issue.
How do I use the nullable type without crashing the compiler?
AnyObject and AnyObject? are not the same thing. AnyObject? is actually syntactic sugar for Optional< AnyObject >. The fact that it compiles with Dictionary< String, AnyObject > but not Dictionary< String, AnyObject? > means that Dictionary< String, AnyObject > or [String: AnyObject] is the correct type, or convertible to the correct type. In general the swift compiler occasionally has problems with type inference which either causes it to crash or to compile very slowly. I notice this most frequently with dictionaries and with returns from .map(). In both cases if you explicitly state the type (even if according to the rules of the language it should be inferred) it usually helps the compiler go faster and/or not crash. In these instances I think it also helps the reader, because if the compiler can't infer the type easily its often the case that a human can't do it without some thinking as well.