Implementing Maybe type using enum - swift

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.

Related

How to declare and init nested enum with reserved keyword as type name in Swift?

I'm having a hard time to figure out how to declare a certain nested enum and calling one of it's automatic constructors. This enum i'm trying to declare is supposed to have a reserved keyword as type name.
Here is a simplified example of what i'm trying to do:
import Foundation
public class Foo {}
public extension Foo {
enum `Type`: Int {
case bar
}
}
var type: Foo.`Type`
type = Foo.`Type`(rawValue: 0)
This doesn't compile in Swift 5.2 with error
error: type 'Foo.Type' has no member 'init'
I'm pretty sure it is just a matter of getting the syntax right but i just can't figure it out. Anyone can please explain how to do it or is it just impossible all together?
There is no way to do this specific thing you want to do. That's why nobody uses nested types named Type, even though we all want to—the language already provides this type, and you don't get to override it with your own. We all use the Objective-C style naming of just smashing the word Type right up there without a proper delimiter.
FooType is what you've got to work with.

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.

How to get the underlying Value from a Swift KeyPath when its type is KeyPath<Root, Value!>?

Take a look at the following code:
struct Something {
var s: String! // Implicitly Unwrapped Optional
}
func bind<T, V>(keyPath: WritableKeyPath<T, V?>) {
}
bind(\Something.s)
The code above does not compile. If we change the signature of bind to bind<T, V>(keyPath: WritableKeyPath<T, V>) then it does compile, but the problem is that the type of V is String! and I need to get the underlying type, in this case String.
We can solve the problem as follows:
func bind<T, V>(keypath: WritableKeyPath<T, ImplicitlyUnwrappedOptional<V>>) {
}
Unfortunately the documentation says that ImplicitlyUnwrappedOptional is deprecated. However, it is not marked as deprecated with the #available attribute.
I'm hesitant to use a type that the docs say are deprecated, but I can find no other way to accomplish what I need.
Is there another way to get the implicitly wrapped generic Value type from a WritableKeyPath when its type is WritableKeyPath<T, V!>?
Will ImplicitlyUnwrappedOptional be removed at some point?
Is there another way to get the implicitly wrapped generic Value type from a WritableKeyPath when its type is WritableKeyPath<T, V!>?
Not that I'm aware of. Really the problem here is that \Something.s shouldn't be a WritableKeyPath<T, V!>. That should be illegal under the rules set out by SE-0054 (IUOs are attributes on declarations; they're not actual types that can satisfy generic placeholders).
Instead, \Something.s should be a WritableKeyPath<T, V?>, so really your original code ought to compile. This issue has been filed as a bug here.
Will ImplicitlyUnwrappedOptional be removed at some point?
Yes, this is set out by SE-0054:
Because IUOs are an attribute on declarations rather than on types, the ImplicitlyUnwrappedOptional type, as well as the long form ImplicitlyUnwrappedOptional<T> syntax, is removed. Types with nested IUOs are no longer allowed. This includes types such as [Int!] and (Int!, Int!).
However the type-checker implementation for this wasn't fully implemented for Swift 4, which is why you're still able to use ImplicitlyUnwrappedOptional as a type in order to work around your problem. It has been implemented for Swift 5 though, so your workaround will no longer compile on its release.
Although hopefully the IUO key path bug will have been fixed by then.

Cast to a Metatype Type in Swift?

Can you cast to a Metatype Type in Swift? It really seems like you should be able to (after all you can instantiate objects from Metatypes).
The following doesn't work:
class Super {}
class A : Super {}
let superA:Super = A()
let subType = superA.dynamicType
let afterCast = superA as subType
//Compiler error: "use of undeclared type 'subType'"
Does anyone know the right way to do this?
Edit:
As newacct pointed out, the result of .dynamicType is obviously not known until runtime, so a compile-time cast to the result of .dynamicType would not make sense.
So the answer is: "You can't" (and there is no good reason to try).
First of all, as takes a type, not an expression, on the right-hand side. So what you have is a syntax error.
What you seem to be trying to do is "cast" to a type that is computed at runtime. What would that even mean? Let's first consider what is a "cast".
Usually, when we have a cast expression x as T, it has two components:
At compile-time: The entire cast expression x as T has compile-time type T?, which allows you to do stuff with the resulting expression that you maybe cannot do on x directly. In other words, it allows you to change the compile-time type.
At runtime: It checks whether the runtime type of x is a subtype of T, and if it is, it evaluates to the optional containing that value, otherwise, it evaluates to nil.
If the type T is not known at compile-time, then obviously you cannot do the compile-time part of it. (The compile-time type of the resulting expression cannot, obviously, depend on something which is not known at compile-time.)
The other part, the runtime component, could that be done with a type computed at runtime? Sure. For example,
import Foundation
let afterCast : Super? =
(superA as AnyObject).isKindOfClass(subType) ? superA : nil
It's not clear if that is what you want.