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

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)"
}

Related

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.

Constraining one generic with another in Swift

I've run into a problem where I have some protocol:
protocol Baz {
func bar<T>(input:T)
}
The function bar is made generic because I don't want the protocol itself to have a Self(it needs to be useable in a collection). I have an implementation of the protocol defined as:
class Foo<S>: Baz {
var value:S
init(value:S) {
self.value = value
}
func bar<T>(input:T) {
value = input
}
}
This gives an error because the compiler doesn't know that S and T are the same type. Ideally I should be able to write something like:
func bar<T where T==S>(input:T) {
value = input
}
or
func bar<T:S>(input:T) {
value = input
}
The first form gives a "Same-type requirement makes generic parameter 'S' and 'T' equivalent" error (which is exactly what I'm trying to do, so not sure why it's an error). The second form gives me a "Inheritance from non-protocol, non-class type 'S'".
Any ideas of on either how to get this to work, or a better design pattern in Swift?
Update: As #luk2302 pointed out, I forgot to make Foo adhere to the Baz protocol
#luk2302 has hinted at much of this in the comments, but just to make it explicit for future searchers.
protocol Baz {
func bar<T>(input:T)
}
This protocol is almost certainly useless as written. It is effectively identical to the following protocol (which is also almost completely useless):
protocol Baz {
func bar(input:Any)
}
You very likely mean (and hint that you mean):
protocol Baz {
typealias T
func bar(input: T)
}
As you note, this makes the protocol a PAT (protocol with associated type), which means you cannot put it directly into a collection. As you note, the usual solution to that, if you really need a collection of them, is a type eraser. It would be nice if Swift would automatically write the eraser for you, which it likely will be able to do in the future, and would eliminate the problem. That said, though slightly tedious, writing type erasers is very straightforward.
Now while you cannot put a PAT directly into a collection, you can put a generically-constrained PAT into a collection. So as long as you wrap the collection into a type that constrains T, it's still no problem.
If these become complex, the constraint code can become tedious and very repetitive. This can be improved through a number of techniques, however.
Generic structs with static methods can be used to avoid repeatedly providing constraints on free-functions.
The protocol can be converted into a generic struct (this formalizes the type eraser as the primary type rather than "as needed").
Protocols can be replaced with functions in many cases. For example, given this:
protocol Bar {
typealias T
func bar(input: T)
}
struct Foo : Bar {
func bar(input: Int) {}
}
You can't do this:
let bars: [Bar] = [Foo()] // error: protocol 'Bar' can only be used as a generic constraint because it has Self or associated type requirements
But you can easily do this, which is just as good:
let bars = [(Int) -> Void] = [Foo().bar]
This is particularly powerful for single-method protocols.
A mix of protocols, generics, and functions is much more powerful than trying to force everything into the protocol box, at least until protocols add a few more missing features to fulfill their promise.
(It would be easier to give specific advice to a specific problem. There is no one answer that solves all issues.)
EDITED (Workaround for "... an error because the compiler doesn't know that S and T are the same type.")
First of all: This is just an separate note (and perhaps an attempt at redemption for my previous answer that ended up being myself chasing my own tail to compute lots and lots of redundant code) in addition to Robs excellent answer.
The following workaround will possibly let your implementation protocol Foo ... / class Bas : Foo ... mimic the behaviour you initially asked for, in the sense that class method bar(...) will know if generics S and T are actually the same type, while Foo still conforms to the protocol also in the case where S is not of the same type as T.
protocol Baz {
func bar<T>(input:T)
}
class Foo<S>: Baz {
var value:S
init(value:S) {
self.value = value
}
func bar<T>(input:T) {
if input is S {
value = input as! S
}
else {
print("Incompatible types. Throw...")
}
}
}
// ok
var a = Foo(value: 1.0) // Foo<Double>
print(a.value) // 1.0
a.bar(2.0)
print(a.value) // 2.0
let myInt = 1
a.bar(myInt) // Incompatible types. Throw...
print(a.value) // 2.0
// perhaps not a loophole we indended
let myAny : Any = 3.0
a.bar(myAny)
print(a.value) // 3.0
The Any and AnyObject loophole here could be redeemed by creating a dummy type constraint that you extend all types (that you wish for to use the generics) to, however not extending Any and AnyObject.
protocol NotAnyType {}
extension Int : NotAnyType {}
extension Double : NotAnyType {}
extension Optional : NotAnyType {}
// ...
protocol Baz {
func bar<T: NotAnyType>(input:T)
}
class Foo<S: NotAnyType>: Baz {
var value:S
init(value:S) {
self.value = value
}
func bar<T: NotAnyType>(input:T) {
if input is S {
value = input as! S
}
else {
print("Incompatible types. Throw...")
}
}
}
// ok
var a = Foo(value: 1.0) // Foo<Double>
// ...
// no longer a loophole
let myAny : Any = 3.0
a.bar(myAny) // compile time error
let myAnyObject : AnyObject = 3.0
a.bar(myAnyObject) // compile time error
This, however, excludes Any and AnyObject from the generic in full (not only for "loophole casting"), which is perhaps not a sought after behaviour.

Bottom Type in 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
}

Swift 2: understanding AnyObject and Self

I couldn't find any good explanation to my questions so I'd like to ask you directly. First of all I'd like to refine my code in this post.
My problem is the protocol AnyObject and the Self type. I didn't implement AnyObject into my code because it is marked with #objc and I don't want any Objective-C stuff involved in my code (don't judge me for that). I also couldn't find any explanation about the Self type. It just worked as expected, but Xcode does not replace Self with the type the static function is called at.
Here is some example:
extension Int : Instance {}
Int.singleton { (customInstanceName) -> Self in 0 } // Self shall be replaced with Int
As you can see Xcode produces a Self instead an Int. Is there any chance I could fix this? Am I right that Self does return the dynamicType and my implementation is fine as it is in my post above? I would really appreciate any good explanation about the Self type.
As you have seen in my code. I am using a custom protocol to check whether my instance is a class or not. Is there any other shiny implementation to check my instances if they are classes or structure types, or am I forced to use AnyObject if I want to get rid of my ClassInstance protocol?
Thank you for your time.
UPDATE:
protocol Test {}
class A : Test {}
struct B : Test {}
let aClass : Test = A()
let aStruct : Test = B()
if let someClass = aClass as? AnyObject {
print(someClass) // only this will print
}
if let someStruct = aStruct as? AnyObject {
print(someStruct)
}
This will work, but AnyObject is still marked as an #objc protocol.
The Self type can be only used in protocols where it is a implicit typealias of the type which conforms to it:
protocol Testable {
func test() -> Self
}
If you want to conform to this protocol you than have to replace Self with the name of the type. For instance:
struct Product: Testable {
func test() -> Product {
return Product()
}
}
Important Edit:
As DevAndArtist pointed out in the comments there is a working class check in Swift 1.2 (without automatic bridging to Objective C) but not Swift 2 (Xcode 7 beta 3; probably a bug):
if instance.dynamicType is AnyClass {
// instance is a class
} else {
// instance is not a class
}
You can see workaround (mainly) for Swift 2 below.
End Edit
With respect to classes you should use AnyObject if you want to keep it simple but you can also use reflection which would be much more effort.
Below you can see some reflection results of string interpolations (only the first few characters):
"\(reflect(classType))" // Swift._ClassMirror
"\(reflect(0))" // Swift._LeafMirror
"\(reflect(enumType))" // Swift._EnumMirror
"\(reflect(structure))" // Swift._StructMirror
"\(reflect([0, 4]))" // Swift._ArrayTypeMirror
"\(reflect(NSDate()))" // Foundation._NSDateMirror
"\(reflect(NSURLRelationship.Contains))" // Swift._EnumMirror
"\(reflect(Int?(2)))" // Swift._OptionalMirror
As you can see enums are consistent if they are not defined in the Swift standard library (unfortunately also Optional...). So you can distinguish also structs and enums:
public enum Type {
case Enum, Class, Struct
}
public func getType<T>(anything: T) -> Type {
if anything is AnyObject {
return .Class
}
if "\(reflect(anything))".hasPrefix("Swift._EnumMirror") {
return .Enum
}
return .Struct
}
So for a better result you have to put some effort into it to differentiate between all the different cases.
But the easiest way to distinguish only between reference types and value types (aka classes and structs/enums) is still (unfortunately only works for own declared structs and not built in types because they can be bridged to Objective C; I'm working on it...):
if instance is AnyObject {}
// or: if instance is of type Any
if let classInstance = instance as? AnyObject {}