Protocols, Structs, but no concrete type - swift

Ok I have a protocol called Environment
protocol Environment {
var rootURL: String {get}
}
Then two structs:
struct Production: Environment {
var rootURL = "www.api.mybackend.com/v1"
}
struct Development: Environment {
var rootURL = "www.api.mydevelopmentbackend.com/v1"
}
A settings object with a function that retrieves the environment:
class Settings {
func getEnvironment<T>() -> T where T: Environment {
let environmentRaw = self.retreiveEnvironmentFromLocalStore()
switch environmentRaw {
case 0:
return Development() as! T
case 1:
return Production() as! T
default:
return Development() as! T
}
}
func retreiveEnvironmentFromLocalStore() -> Int {
//Realm, SQLLite, Core Date, I don't really care for this example.
//Let's just say it defaults to returning 1
}
}
I really want to keep moving in a Protocol Oriented Programming direction but now when I call this function on a settings object and try to use the rootURL property the compiler complains it can't figure out the type. So, to better my understanding and to maybe find a solution:
1) Why does it care about the type if I am accessing a property defined by a protocol that at the very least it knows the returning type conforms to?
2) Structs don't have inheritance. Should I define a base class and forget about generics?
3) Can I make my getEnvironment function better? I don't like force casting, it seems like a code smell.
4) Am I even using generics correctly here?
EDIT 1:
To be clear, I want one function that returns a struct that I know will have this property.

Am I even using generics correctly here?
No, I don't think so. You are saying that getEnvironment will return T which can be any type that the client code specifies, as long as it implements Environment. However, the implementation of the method doesn't do this. It will only return two kinds of Environments, and which type it returns is not determined by the client code. The type returned depends on what retreiveEnvironmentFromLocalStore returns. Hence, generics is not suitable in this case.
Since the type of environment it returns is decided by the implementation of the method, instead of the client code, you should make use of polymorphism here - make it return an Environment instead:
func getEnvironment() -> Environment {
let environmentRaw = self.retreiveEnvironmentFromLocalStore()
switch environmentRaw {
case 0:
return Development()
case 1:
return Production()
default:
return Development()
}
}

I really want to keep moving in a Protocol Oriented Programming direction
I suggest instead you try to move in a clear, understandable code direction, regardless of what the trendy orientation is.
Here's your function declaration:
func getEnvironment() -> T where T: Environment
This says that getEnvironment() will return an object of some type T, where T is deduced at compile time based on the code that calls getEnvironment().
What types could T be? It could be either Production or Development. For example, you could write:
let e: Production = Settings().getEnvironment()
This lets the compiler deduce that getEnvironment() returns a Production (which is an Environment) at this call site.
But there's a problem: getEnvironment() might try to return a Development anyway, based on the random number generator inside retreiveEnvironmentFromLocalStore. Then you'll get a crash at run time when it fails to cast Development to Production.
Why do you think getEnvironment() needs to be generic at all? Based on the code in your question, it shouldn't be.
import Foundation
protocol Environment {
var rootURL: String {get}
}
struct Production: Environment {
var rootURL = "www.api.mybackend.com/v1"
}
struct Development: Environment {
var rootURL = "www.api.mydevelopmentbackend.com/v1"
}
class Settings {
func getEnvironment() -> Environment {
let environmentRaw = self.retreiveEnvironmentFromLocalStore()
switch environmentRaw {
case 1: return Production()
default: return Development()
}
}
func retreiveEnvironmentFromLocalStore() -> Int {
return Int(arc4random())
}
}
let settings = Settings()
let e = settings.getEnvironment()
Style note: the Swift API Design Guidelines advise us to
Name functions and methods according to their side-effects
Those without side-effects should read as noun phrases, e.g. x.distance(to: y), i.successor().
Unless the methods in Settings have important side effects, better names would be environment() and rawEnvironmentFromLocalStore().

Related

Can a protocol define subscript(keyPath:) without an explicit implementation in the adopting object?

Since Swift 4, objects have gained subscript(keyPath:) which can be used to retrieve values using AnyKeyPath and its subclasses. According to the Swift book, the subscript is available on all types. For example, an instance of a class TestClass may be subscripted with an AnyKeyPath like so:
class TestClass {
let property = true
}
let anyKeyPath = \TestClass.property as AnyKeyPath
_ = TestClass()[keyPath: anyKeyPath]
This compiles correctly as expected. Use of any other valid subclass would also compile including PartialKeyPath<TestClass>, KeyPath<TestClass, Bool>, etc. This functionality is unavailable in a protocol extension. For example, the following is invalid:
class TestClass {
let property = true
}
protocol KeyPathSubscriptable {
}
extension KeyPathSubscriptable {
func test() {
let anyKeyPath = \TestClass.property as AnyKeyPath
_ = self[keyPath: anyKeyPath] // Value of type 'Self' has no subscripts
}
}
If we want to use that keyPath subscript in the protocol, we can include it in the protocol definition. However, the compiler will not resolve it automatically:
protocol KeyPathSubscriptable {
subscript(keyPath: AnyKeyPath) -> Any? { get }
}
extension KeyPathSubscriptable {
func test() {
let anyKeyPath = \TestClass.property as AnyKeyPath // This can be any valid KeyPath
_ = self[keyPath: anyKeyPath]
}
}
class TestClass: KeyPathSubscriptable { // Type 'TestObject' does not conform to protocol 'KeyPathSubscriptable'
let property = true
}
With this, we get a compile error: Type 'TestObject' does not conform to protocol 'KeyPathSubscriptable'. In order to resolve this, we must include a redundant implementation of that subscript in TestClass:
class TestClass: KeyPathSubscriptable {
let property = true
subscript(keyPath: AnyKeyPath) -> Any? {
fatalError() // This is never executed
}
}
This resolves the conformance issue and produces the goal result although it is seemingly unnecessary and illogical. I'm not sure how, but the subscript implementation is never even used. It's finding the expected implementation of subscript(keyPath:) and using that instead, but how? Where is that and is there any way to use it in a protocol? Why is this required by the compiler even though it's never used?
The context of this use case is in a logging module. The goal is that an object should be able to adopt a particular protocol which, with no additional setup on the object, would provide a human readable description of the object, instead of the default for many objects which is a memory address. The protocol would use Mirror to fetch KeyPaths of an object, read the values, and print them to the console. It is intended for debugging purposes and would not run in any production environment.
Please let me know if I can make any clarifications. I may post this to the Swift team if others think that this could potentially be a bug of sorts. All help is appreciated. Thanks in advance.
Full gist located here.

Swift: casting un-constrained generic type to generic type that confirms to Decodable

Situation
I have a two generic classes which will fetch data either from api and database, lets say APIDataSource<I, O> and DBDataSource<I, O> respectively
I will inject any of two class in view-model when creating it and view-model will use that class to fetch data it needed. I want view-model to work exactly same with both class. So I don't want different generic constraints for the classes
// sudo code
ViewModel(APIDataSource <InputModel, ResponseModel>(...))
// I want to change the datasource in future like
ViewModel(DBDataSource <InputModel, ResponseModel>(...))
To fetch data from api ResponseModel need to confirms to "Decodable" because I want to create that object from JSON. To fetch data from realm database it need to inherit from Object
Inside ViewModel I want to get response like
// sudo code
self.dataSource.request("param1", "param2")
If developer tries to fetch api data from database or vice-versa it will check for correct type and throws proper error.
Stripped out version of code for playground
Following is stripped out version of code which shows what I want to achieve or where I am stuck (casting un-constrained generic type to generic type that confirms to Decodable)
import Foundation
// Just to test functions below
class DummyModel: Decodable {
}
// Stripped out version of function which will convert json to object of type T
func decode<T:Decodable>(_ type: T.Type){
print(type)
}
// This doesn't give compilation error
// Ignore the inp
func testDecode<T:Decodable> (_ inp: T) {
decode(T.self)
}
// This gives compilation error
// Ignore the inp
func testDecode2<T>(_ inp: T){
if(T.self is Decodable){
// ??????????
// How can we cast T at runtime after checking T confirms to Decodable??
decode(T.self as! Decodable.Type)
}
}
testDecode(DummyModel())
Any help or explanation that this could not work would be appreciated. Thanks in advance :)
As #matt suggests, moving my various comments over to an answer in the form "your problem has no good solution and you need to redesign your problem."
What you're trying to do is at best fragile, and at worst impossible. Matt's approach is a good solution when you're trying to improve performance, but it breaks in surprising ways if it impacts behavior. For example:
protocol P {}
func doSomething<T>(x: T) -> String {
if x is P {
return "\(x) simple, but it's really P"
}
return "\(x) simple"
}
func doSomething<T: P>(x: T) -> String {
return "\(x) is P"
}
struct S: P {}
doSomething(x: S()) // S() is P
So that works just like we expect. But we can lose the type information this way:
func wrapper<T>(x: T) -> String {
return doSomething(x: x)
}
wrapper(x: S()) // S() simple, but it's really P!
So you can't solve this with generics.
Going back to your approach, which at least has the possibility of being robust, it's still not going to work. Swift's type system just doesn't have a way to express what you're trying to say. But I don't think you should be trying to say this anyway.
In the method that fetch data I will check type of generic type and if it confirms to "Decodable" protocol I will use it to fetch data from api else from database.
If fetching from the API vs the database represents different semantics (rather than just a performance improvement), this is very dangerous even if you could get it to work. Any part of the program can attach Decodable to any type. It can even be done in a separate module. Adding protocol conformance should never change the semantics (outwardly visible behaviors) of the program, only the performance or capabilities.
I have a generic class which will fetch data either from api or database
Perfect. If you already have a class, class inheritance makes a lot of sense here. I might build it like:
class Model {
required init(identifier: String) {}
}
class DatabaseModel {
required init(fromDatabaseWithIdentifier: String) {}
convenience init(identifier: String) { self.init(fromDatabaseWithIdentifier: identifier )}
}
class APIModel {
required init(fromAPIWithIdentifier: String) {}
convenience init(identifier: String) { self.init(fromAPIWithIdentifier: identifier )}
}
class SomeModel: DatabaseModel {
required init(fromDatabaseWithIdentifier identifier: String) {
super.init(fromDatabaseWithIdentifier: identifier)
}
}
Depending on your exact needs, you might rearrange this (and a protocol might also be workable here). But the key point is that the model knows how to fetch itself. That makes it easy to use Decodable inside the class (since it can easily use type(of: self) as the parameter).
Your needs may be different, and if you'll describe them a bit better maybe we'll come to a better solution. But it should not be based on whether something merely conforms to a protocol. In most cases that will be impossible, and if you get it working it will be fragile.
What you'd really like to do here is have two versions of testDecode, one for when T conforms to Decodable, the other for when it doesn't. You would thus overload the function testDecode so that the right one is called depending on the type of T.
Unfortunately, you can't do that, because you can't do a function overload that depends on the resolution of a generic type. But you can work around this by boxing the function inside a generic type, because you can extend the type conditionally.
Thus, just to show the architecture:
protocol P{}
struct Box<T> {
func f() {
print("it doesn't conform to P")
}
}
extension Box where T : P {
func f() {
print("it conforms to P")
}
}
struct S1:P {}
struct S2 {}
let b1 = Box<S1>()
b1.f() // "it conforms to P"
let b2 = Box<S2>()
b2.f() // "it doesn't conform to P"
This proves that the right version of f is being called, depending on whether the type that resolves the generic conforms to the protocol or not.

what is the difference between these two in swift 3 [duplicate]

In the Introduction to Swift WWDC session, a read-only property description is demonstrated:
class Vehicle {
var numberOfWheels = 0
var description: String {
return "\(numberOfWheels) wheels"
}
}
let vehicle = Vehicle()
println(vehicle.description)
Are there any implications to choosing the above approach over using a method instead:
class Vehicle {
var numberOfWheels = 0
func description() -> String {
return "\(numberOfWheels) wheels"
}
}
let vehicle = Vehicle()
println(vehicle.description())
It seems to me that the most obvious reasons for choosing a read-only computed property are:
Semantics - in this example it makes sense for description to be a property of the class, rather than an action it performs.
Brevity/Clarity - prevents the need to use empty parentheses when getting the value.
Clearly the above example is overly simple, but are there other good reasons to choose one over the other? For example, are there some features of functions or properties that would guide your decision of which to use?
N.B. At first glance this seems like quite a common OOP question, but I'm keen to know of any Swift-specific features that would guide best practice when using this language.
It seems to me that it's mostly a matter of style: I strongly prefer using properties for just that: properties; meaning simple values that you can get and/or set. I use functions (or methods) when actual work is being done. Maybe something has to be computed or read from disk or from a database: In this case I use a function, even when only a simple value is returned. That way I can easily see whether a call is cheap (properties) or possibly expensive (functions).
We will probably get more clarity when Apple publishes some Swift coding conventions.
Well, you can apply Kotlin 's advices https://kotlinlang.org/docs/reference/coding-conventions.html#functions-vs-properties.
In some cases functions with no arguments might be interchangeable
with read-only properties. Although the semantics are similar, there
are some stylistic conventions on when to prefer one to another.
Prefer a property over a function when the underlying algorithm:
does not throw
complexity is cheap to calculate (or caсhed
on the first run)
returns the same result over invocations
While a question of computed properties vs methods in general is hard and subjective, currently there is one important argument in the Swift's case for preferring methods over properties. You can use methods in Swift as pure functions which is not true for properties (as of Swift 2.0 beta). This makes methods much more powerful and useful since they can participate in functional composition.
func fflat<A, R>(f: (A) -> () -> (R)) -> (A) -> (R) {
return { f($0)() }
}
func fnot<A>(f: (A) -> Bool) -> (A) -> (Bool) {
return { !f($0) }
}
extension String {
func isEmptyAsFunc() -> Bool {
return isEmpty
}
}
let strings = ["Hello", "", "world"]
strings.filter(fnot(fflat(String.isEmptyAsFunc)))
There is a difference:
If you use a property you can then eventually override it and make it read/write in a subclass.
Since the runtime is the same, this question applies to Objective-C as well. I'd say, with properties you get
a possibility of adding a setter in a subclass, making the property readwrite
an ability to use KVO/didSet for change notifications
more generally, you can pass property to methods that expect key paths, e.g. fetch request sorting
As for something specific to Swift, the only example I have is that you can use #lazy for a property.
In the read-only case, a computed property should not be considered semantically equivalent to a method, even when they behave identically, because dropping the func declaration blurs the distinction between quantities that comprise the state of an instance and quantities that are merely functions of the state. You save typing () at the call site, but risk losing clarity in your code.
As a trivial example, consider the following vector type:
struct Vector {
let x, y: Double
func length() -> Double {
return sqrt(x*x + y*y)
}
}
By declaring the length as a method, it’s clear that it’s a function of the state, which depends only on x and y.
On the other hand, if you were to express length as a computed property
struct VectorWithLengthAsProperty {
let x, y: Double
var length: Double {
return sqrt(x*x + y*y)
}
}
then when you dot-tab-complete in your IDE on an instance of VectorWithLengthAsProperty, it would look as if x, y, length were properties on an equal footing, which is conceptually incorrect.
From the performance perspective, there seems no difference. As you can see in the benchmark result.
gist
main.swift code snippet:
import Foundation
class MyClass {
var prop: Int {
return 88
}
func foo() -> Int {
return 88
}
}
func test(times: u_long) {
func testProp(times: u_long) -> TimeInterval {
let myClass = MyClass()
let starting = Date()
for _ in 0...times {
_ = myClass.prop
}
let ending = Date()
return ending.timeIntervalSince(starting)
}
func testFunc(times: u_long) -> TimeInterval {
let myClass = MyClass()
let starting = Date()
for _ in 0...times {
_ = myClass.prop
}
let ending = Date()
return ending.timeIntervalSince(starting)
}
print("prop: \(testProp(times: times))")
print("func: \(testFunc(times: times))")
}
test(times: 100000)
test(times: 1000000)
test(times: 10000000)
test(times: 100000000)
Output:
prop: 0.0380070209503174
func: 0.0350250005722046
prop: 0.371925950050354
func: 0.363085985183716
prop: 3.4023300409317
func: 3.38373708724976
prop: 33.5842199325562
func: 34.8433820009232
Program ended with exit code: 0
In Chart:
There are situations where you would prefer computed property over normal functions. Such as: returning the full name of an person. You already know the first name and the last name. So really the fullName property is a property not a function. In this case, it is computed property (because you can't set the full name, you can just extract it using the firstname and the lastname)
class Person{
let firstName: String
let lastName: String
init(firstName: String, lastName: String){
self.firstName = firstName
self.lastName = lastName
}
var fullName :String{
return firstName+" "+lastName
}
}
let william = Person(firstName: "William", lastName: "Kinaan")
william.fullName //William Kinaan
Semantically speaking, computed properties should be tightly coupled with the intrinsic state of the object - if other properties don't change, then querying the computed property at different times should give the same output (comparable via == or ===) - similar to calling a pure function on that object.
Methods on the other hand come out of the box with the assumption that we might not always get the same results, because Swift doesn't have a way to mark functions as pure. Also, methods in OOP are considered actions, which means that executing them might result in side effects. If the method has no side effects, then it can safely be converted to a computed property.
Note that both of the above statements are purely from a semantic perspective, as it might well happen for computed properties to have side effects that we don't expect, and methods to be pure.
Historically description is a property on NSObject and many would expect that it continues the same in Swift. Adding parens after it will only add confusion.
EDIT:
After furious downvoting I have to clarify something - if it is accessed via dot syntax, it can be considered a property. It doesn't matter what's under the hood. You can't access usual methods with dot syntax.
Besides, calling this property did not require extra parens, like in the case of Swift, which may lead to confusion.
An updated/fixed version of Benjamin Wen's answer incorporating Cristik's suggestion.
class MyClass {
var prop: Int {
return 88
}
func foo() -> Int {
return 88
}
}
func test(times: u_long) {
func testProp(times: u_long) -> TimeInterval {
let myClass = MyClass()
let starting = CACurrentMediaTime()
for _ in 0...times {
_ = myClass.prop
}
let ending = CACurrentMediaTime()
return ending - starting
}
func testFunc(times: u_long) -> TimeInterval {
let myClass = MyClass()
let starting = CACurrentMediaTime()
for _ in 0...times {
_ = myClass.foo()
}
let ending = CACurrentMediaTime()
return ending - starting
}
print("prop: \(testProp(times: times))")
print("func: \(testFunc(times: times))")
}
test(times: 100000)
test(times: 1000000)
test(times: 10000000)
test(times: 100000000)

How do I combine the safety of type requirements with the safety of enums?

So I'm working on an sql database abstraction layer in swift and I want to write it as safe as possible. By that I mean I would prefer to make it impossible for anybody to do anything illegal in the database using my library.
One thing I'm not fully able to solve yet is how to make the conversion from Swift types to SQL data types 100% safe. So I'll explain my current implementation and its flaws:
So in SQL, many data types have parameters. For example, when you want to define a column as a VARCHAR, you need to give it a parameter that represents the max length of the VARCHAR, like VARCHAR(255). You could say that VARCHAR is one of SQL's primitive data-types and VARCHAR(255) is a more specified data-type. To represent that in a type-safe way in swift I created two protocols:
public protocol PrimitiveDataType {
associatedtype Options = Void
}
public protocol SpecifiedDataType {
associatedtype Primitive: PrimitiveDataType
static var options: Primitive.Options { get }
static func from(primitive: Primitive) -> Self
var primitive: Primitive { get }
}
So here's an example of a PrimitiveDataType:
extension String: PrimitiveDataType {
public enum DatabaseStringType {
case char(length: Int), varchar(limit: Int), text
}
public typealias Options = DatabaseStringType
}
And here's an example of a SpecifiedDataType:
struct Name {
let value: String
init?(_ value: String) {
guard case 0...50 = value.characters.count else {
return nil
}
self.value = value
}
}
extension Name: SpecifiedDataType {
static let options = String.DatabaseStringType.varchar(limit: 50)
static func from(primitive: String) -> Name {
return Name(primitive)!
}
var primitive: String {
return value
}
}
Now I can use the information elsewhere in the library to know what kind of database-column is expected whenever a Name type is requested. This gives my library the power to make sure the database columns are always of the correct type.
I haven't written all that code yet, but it might look something like this:
func createColumn<SDT: SpecifiedDataType>(ofType type: SDT) -> String {
switch SDT.options {
case let options as String.DatabaseStringType:
switch options {
case .text:
return "TEXT"
case .char(let length):
return "CHAR(\(length))"
case .varchar(let limit):
return "VARCHAR(\(limit))"
}
case let length as UInt32.Options:
// return something like UNSIGNED INTEGER(\(length)) or whatever
// case etcetera
}
}
There is just one small problem with this. The set of valid primitive data-types is limited, but the set of possible implementations of the PrimitiveDataType protocol is unlimited, because I can't stop anybody from creating their own implementation of this protocol.
So for this reason it would be better to use some kind of enum instead of a number of implementations of a protocol. Because nobody can extend an enum that I create, so I can keep the options limited to whatever I define as valid types. However, an enum would create another problem that doesn't exist in my current implementation.
You see in my current implementation, whenever someone implements SpecifiedDataType with their options defined like so:
static let options = String.DatabaseStringType.varchar(limit: 50)
I can trust that the compiler will force them to make their type compatible with string by implementing the from(primitive: String) method and the primitive: String (computed) variable. AFAIK, if I switch the protocol for an enum I lose this compiler-enforced type-safety.
So in summary, I want to have all of the following:
A way for a developer to declare what sql data-type they want their type to correspond with.
A way to then force that developer to actually make their type compatible with that sql data-type.
To guarantee that the developer using my library can't somehow extend the list of sql-data types, but can only use the ones that I have defined for him / her.
So far I only know how to do either the first two, but not the last one, or the last one, but not the first two. How do I get all three?

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.