Bottom Type in Swift - swift

I'm wondering if there is bottom type in the Swift language.
To weed out any confusion beforehand, unit type is a different kind than bottom type as we have it as Void or () in swift. Also Any is top type.
What I've found to be the closest, surprisingly, is #noreturn attribute in the form of fatalError() in that we can mostly pass this function to conform to most given arbitrary type.
But, of course, this is incomplete and thus a bad substitute for a true bottom type as, for example, Nothing in Scala, undefined in Haskell or even null in Java.
So, is there a bottom type in Swift language?

Turns out there is no Bottom Type in swift, but we can mock its general behavior through few hacks with #noreturn attribute and generics as explained in this talk.
func undefined<A>(_ message: String = "") -> A {
fatalError("Not Implemented: \(message)")
}
Then we can use it to mark yet-implemented parts of our code to pass compiler errors:
func someComplexFunction<U: User>(u: U) -> U {
return undefined("Do this after creating user")
}
Or to prove some invariances in our code:
let array = ["hello", "world"]
let hello: String = array.first ?? undefined("This is impossible!")

see Never
Basically, you can just do
func foo() -> Never {
// you can't return
}

Related

protocol annotation in var declaration breaks code

I am trying to call the method .enumerate() on an instance of a type which conforms to the protocol Sequence. According to Apple's documentation, this should be correct, since .enumerate is part of the Sequence protocol.
However, I receive this complaint from the compiler:
Member 'enumerated' cannot be used on value of type 'any Sequence<URL>'; consider using a generic constraint instead.
Yet, if I remove the type annotation, then it works.
Here is an example which reproduces the problem:
func example() -> URL? {
let fm : FileManager = FileManager.default
let appDir : FileManager.SearchPathDirectory = FileManager.SearchPathDirectory.applicationDirectory
let domMask : FileManager.SearchPathDomainMask = FileManager.SearchPathDomainMask.allDomainsMask
let appResourceValues : [URLResourceKey] = [URLResourceKey.localizedNameKey]
var appURLs : any Sequence<URL> = fm.urls(for: appDir, in: domMask)
//var appURLs : Sequence<URL> = fm.urls(for: appDir, in: domMask)
//var appURLs = fm.urls(for: appDir, in: domMask)
var appURL : URL? = appURLs.enumerated().first { (offset: Int, element: URL) in
try! element.resourceValues(forKeys: Set(appResourceValues)).localizedName!.contains("App Store")
}?.element
return appURL
}
There are two commented lines in the code above, which are alternate ways to instantiate appURLs. If I use the first commented line, which is the old Swift syntax apparently, then I receive an error telling me that in order to add a type annotation which enforces a protocol, I need to use any protocolName, and not protocolName. (According to a comment on another post, this was a recent change in Swift: Use of protocol 'YourProtocol' as a type must be written 'any YourProtocol' Error, https://github.com/apple/swift-evolution/blob/main/proposals/0335-existential-any.md)
If I use the second commented line, which removes the protocol annotation altogether, then the code works.
Is this a bug in Swift? How can I apply an annotation to indicate that it must conform to Sequence<URL> without breaking the code?
I tried to declare a generic type parameter, but Swift won't let me. None of these work:
associatedtype does exactly what I want: it creates a generic type parameter. But it doesn't work outside a protocol.
If you annotate appURLs with the existential type any Sequence<URL>, then that means that you don't know what concrete type it actually stores. This is problematic for calling enumerated, because enumerated returns EnumeratedSequence<Self>:
func enumerated() -> EnumeratedSequence<Self>
Self means "type on which this is called" - the exact thing that you don't know. Sometimes, having an unknown Self is fine. e.g. if methods with these signatures existed in Sequence:
func f() -> Self
func g() -> (Self, Int)
func h(p: (Self) -> Void)
func i() -> [Self]
func j() -> [Int: Self]
func k() -> Self?
All of these are covariant positions. It remains type safe to substitute Self in these positions with any Sequence<URL>, which is why you can still call these methods. However, it is not safe to do the same with EnumeratedSequence<Self>, because even though SomeConcreteImplementationOfSequence is a any Sequence<URL>, EnumeratedSequence<SomeConcreteImplementationOfSequence> is not a EnumeratedSequence<any Sequence<URL>>. Generics are invariant in Swift - the Self in EnumeratedSequence<Self> is in an invariant position.
You can see they talk about when functions involving Self can be called in this SE proposal:
[...] but references to Self-rooted associated types will for the
same reasons some Self references do today. As alluded to back in
Inconsistent Language Semantics, references to covariant Self
are already getting automatically replaced with the base object type,
permitting usage of Self-returning methods on existential values [...]
This way, a protocol or protocol extension member
(method/property/subscript/initializer) may be used on an existential
value unless:
The type of the invoked member (accessor — for storage declarations),
as viewed in context of the base type, contains references to Self
or Self-rooted associated types in non-covariant position. [...]
They even use enumerated() as an example further down!
extension Sequence {
public func enumerated() -> EnumeratedSequence<Self> {
return EnumeratedSequence(_base: self)
}
}
func printEnumerated(s: Sequence) {
// error: member 'enumerated' cannot be used on value of type protocol type 'Sequence'
// because it references 'Self' in invariant position; use a conformance constraint
// instead. [fix-it: printEnumerated(s: Sequence) -> printEnumerated<S: Sequence>(s: S)]
for (index, element) in s.enumerated() {
print("\(index) : \(element)")
}
}
Besides, EnumeratedSequence<any Sequence<URL>> isn't even a valid type! EnumeratedSequence requires its type parameter to be a Sequence, but any Sequence<URL> isn't one! Because Sequence has static requirements.
Responding to your comments,
It is bad practice to type hint something as [URL] when you only intend to use the qualities encapsulated by Sequence protocol
That is not bad practice. Rather, putting type annotations where they are not needed is considered not Swifty.
Example: I may want to use a method which compiles a enumerable list of URLs, but the way that these URLs are fetched will depend on runtime parameters (e.g., do I have internet access? Is an external drive currently mounted?). Depending on these parameters, it may be more efficient (or only be possible) to acquire the list of URLs as [URL] or as any other type which conforms to Sequence<URL>. In that case, the return type of such a function will be anything which conforms to Sequence<URL>
In that case, your function can return an AnySequence<URL>. Unlike any Sequence<URL>, this is a concrete type. You just need to do the extra step of wrapping other sequence types to it:
func fetchSomeURLs() -> AnySequence<URL> {
if someCondition {
return AnySequence([url1, url2]) // [URL]
} else {
return AnySequence(someOtherImplementationOfSequence)
}
}
I have concluded that the Swift compiler isn't sophisticated enough to check conformity of a variable to a protocol. (There are some limited cases where it will work.)
A work-around in this case is the following:
extension Sequence {
func enumerated_custom() -> any Sequence<(offset:Int, element:Iterator.Element)> {
var index : Int = -1
return self.lazy.map({ (el:Iterator.Element) in
index = index+1 ; return (index+1, el)
})
}
}
Then, we can do appURLs.enumerated_custom() to get a Sequence<(Int, URL)> which mimics the behaviour of appURLs.enumerated(). I can then use the annotation appURLs : Sequence<URL> in order to check for conformity, and the code does not break.
Related informational links:
https://belkadan.com/blog/2021/10/Swift-Regret-Generic-Parameters-are-not-Members/
https://github.com/apple/swift/pull/39492
https://github.com/apple/swift-evolution/blob/main/proposals/0309-unlock-existential-types-for-all-protocols.md
https://github.com/apple/swift/pull/41131

Swift Passing a Generic from a Function

I have the following function :
Amplify.API.query(request: .get(
self.getObjectForOCObject(ocObject: ocObject)!, byId: id)) { event in
The definition of the get function is :
public static func get<M: Model>(_ modelType: M.Type,
byId id: String) -> GraphQLRequest<M?> {
My getObjectForObject is as follows :
func getObjectForOCObject <M: Model>(ocObject:NSObject) -> M.Type?
{
if type (of:ocObject) == type(of: OCAccount.self)
{
return Account.self as? M.Type
}
return nil;
}
But I'm getting a"Generic Parameter 'M' could not be inferred. I get that the compiler cannot determine what type of object this is. However I don't know how to fix this. I need my getObjectForOCObject function to return what it is expecting. Essentially I'm trying to return the type of object based on the type of another object.
Normally this call is done this way and it works...
Amplify.API.query(request: .get(Account.self, byId: id)) { event in
I'm trying to avoid having to create a number of functions to handle each different Model in my code as that is being handled in higher up in the call hierarchy. Which is why I'm trying to do this. Otherwise I'm going to have to write essentially the same code in multiple places. In Objective C one can use the super class to pass objects around but the inheriting class still comes along with it. But with Swift being dynamically typed, I'm running into this issue.
The closest I've gotten is this... Changing the getObjectForOCObject return to Model.Type? as so :
func getObjectForOCObject (ocObject:NSObject) -> Model.Type?
{
if type (of:ocObject) == type(of: OCAccount.self)
{
return Account.self
}
return nil;
}
Then I get a Cannot convert value of type 'Model.Type?' to expected argument type 'M.Type' But aren't these essentially the same thing based on the .get function above?
Hoping for some insight here. Also, FYI, I'm pretty terrible with Swift so I'm certain I'm definitely doing some bad things in Swift here. I'm an expert with ObjC. I'm just trying to create a bridge between the two for this Swift library I'm using.

Workaround for conditional conformance in Swift (was: Adding protocol to a constrained generic types)

The code snippet below demonstrates the problem I am trying to solve.
import Foundation
protocol Printable {
func className() -> String
}
class SomeType: Printable {
func className() -> String {
return "SomeType"
}
}
class List<T> {
}
extension List where T: SomeType {
func className() -> String {
return "List<SomeType>"
}
}
func test(type: Any, message: String) {
guard type is Printable else {
print("\(message): ERROR")
return
}
print("\(message): SUCCESS")
}
let s: Any = SomeType()
test(type: s, message: "#1")
let slist1: Any = List<Any>()
test(type: slist1, message: "#2")
let slist2: Any = List<SomeType>()
test(type: slist2, message: "#3")
How can I get this:
> #1: SUCCESS <--- as expected
> #2: ERROR <--- it's okay
> #3: SUCCESS <--- I am getting ERROR instead
It seems that adding a protocol to this line would do the trick:
extension List: Printable where T: SomeType { // COMPILE ERROR
But unfortunately, this is not allowed.
Another way to do it could be to use:
extension List where T: Printable { // COMPILES OK in Swift 2.3 but doesn't work. COMPILE ERROR in Swift 3.0
But again, no luck passing the test.
What else can I do to add a protocol to a constrained generic type?
An updated answer now that we have Swift 4.2, conditional conformance is now added as a feature.
From their spec on Github, this sort of code is now valid
extension List : Printable where T: SomeType {
func className() -> String {
return "List<SomeType>"
}
}
Okay so in your guard you're asking "if this is Printable then print success else print Error" and with your first example you have s which is SomeType which is printable. That's fine.
After that you have slist1 which is type List<Any> which is definitely not of type printable and you get "Error". That's fine
Next you have List<SomeType>. Now you have a class extension that defines T to be SomeType, correct? But you're only defining T to be SomeType and not the actual List so when you pass the entire List into the test function you're not going to get your test to pass because List<AnyTypeHere> is not Printable because the list itself doesn't implement Printable.
Now the question is, do you want the entire list to be printable? If so, then just make it conform to the SomeType or Printable protocol. That's the only way you'll get that to pass other than you passing individual List<SomeType> elements into the function. Your function logic is correct but it's just a misuse of the concept.
So if you want the List<SomeType> to make that pass then you could do something like
class List<T> : Printable where T:SomeType {
//Add code here that conforms to protocol
}
Doing that will make your second test fail because Any doesn't inherit from SomeType but it'll make your third test pass because now List<T> is Printable and T is also of type SomeType. I mean, that's just a real quick way to get what it looked like you wanted to begin with. You're not going to have the second and third tests pass at the same time unless you add something extra because the second test is List being of type Any while the third is List being of type Printable. So either one of them will throw an error (because List isn't of type Printable) or all tests show success (because List is of type Printable)

How Do I Instantiate AnyGenerator<T> in Swift?

So I'm trying to use AnyGenerator to wrap a generic GeneratorType, however I'm getting the error:
Argument passed to call that takes no argument
This seems to extend from a weird ambiguity as there is both an AnyGenerator struct (the one I expect) and an AnyGenerator class intended as an abstract class for implementations to extend.
However I don't have any idea how to specify one over the other, as all documentation I can find suggests I should just use:
let someGenerator = ["foo"].generate()
let anyGenerator = AnyGenerator(someGenerator)
Is there something else that I can do instead? For extra fun it seems there's also an anyGenerator global function, just to make sure no-one has any idea what's going on ;)
You can use the anyGenerator<G : GeneratorType>(_: G) function to create your AnyGenerator<...> instance
signature:
func anyGenerator<G : GeneratorType>(base: G) -> AnyGenerator<G.Element>
description:
Return a GeneratorType instance that wraps base but whose type depends only on the type of G.Element.
Example:
struct Foo : GeneratorType {
typealias Element = String
mutating func next() -> String? {
return "foo"
}
}
var bar = anyGenerator(Foo())
func foofoo(bar: AnyGenerator<String>) {
print("foobar")
}
foofoo(bar) // "foobar", ok
As I wrote in my comment to your question, you should probably avoid the specific name anyGenerator specifically since there exists a global native function anyGenerator(..).
Also, please see #MartinR:s comment to your question above; the two global anyGenerator functions are soon-to-be deprecated (Swift 2.2), and will be removed in Swift 3.0, in favour of initializers on AnyGenerator.

Can I constrain a generic parameter to *not* be optional?

Let's say I have this code:
func hello<T>(thing: T) -> String {
return "hello \(thing)"
}
Can I write a version of the hello function that won't compile if it's passed an optional?
let foo = "some"
let bar: String? = nil
print(helloNoOptional(foo)) // should compile
print(helloNoOptional(bar)) // should not compile
I'm thinking maybe it's doable with a protocol conformance or where clause on T but I can't think of how exactly that would work.
The reason I want to do this is because I'm dealing with a actual function in legacy codebase that has no sensible behavior if thing is nil. So I'd rather prevent hello from being called on an optional rather than deal with unwrapping thing inside of hello and trying to figure out a sensible error behavior.
Update:
A possible path...I realized that the Optional enum conforms to the NilLiteralConvertible protocol. So if I can find a way to constrain my generic to not conform to a type, I can exclude optionals de facto. But I don't know if it's possible to do something like
<T where !T: NilLiteralConvertible>
Best I can think of is overload and check at runtime:
func hello<T>(thing: T) -> String {
return "hello \(thing)"
}
fun hello<T>(thing: T?) -> String {
fatalError("No optionals allowed!")
}
hello("swift") // fine
hello(2) // fine
hello(Int("2")) // fatal error
But I don't know of a way of generating a compile-time error instead.
Edited
You can create a dummy protocol (NotOfOptionalType below) and extend all types you expect to use in your generic functions by this protocol. Finally use the dummy protocol as a type constraint for the parameter(s) in your generic functions; optionals does not meet this type constraint and you'll be given an error at compile time if they are sent as parameters for these functions.
// dummy protocol
protocol NotOfOptionalType {}
extension String : NotOfOptionalType {}
extension Int : NotOfOptionalType {}
extension Double : NotOfOptionalType {}
// ... extend to the types you will use
func hello<T: NotOfOptionalType > (thing: T) -> String {
return "hello \(thing)"
}
let foo = "some"
var bar: String? = nil
print(hello(foo)) // compiles
print(hello(bar)) // fails at compile time
bar = "something"
print(hello(bar)) // fails at compile time
print(hello(bar!)) // compiles
Building on #Airspeed Velocity's answer, I personally prefer to keep everything in one place, like so...
func hello<T>(_ thing: T) -> String {
if T.self is ExpressibleByNilLiteral.Type {
fatalError("Optional types not supported")
}
return "hello \(thing)"
}