Cannot get protocol with typealias to work in Swift - swift

Just trying to build a proof-of-concept lib in Swift with the following code:
import Foundation
protocol Resolver {
typealias ResolvedType
func get() -> ResolvedType
}
class FunctionResolver<T>: Resolver {
typealias ResolvedType = T
private var _resolver: () -> ResolvedType
init(resolver: () -> ResolvedType) {
_resolver = resolver
}
func get() -> ResolvedType {
return _resolver()
}
}
func singleton<T, U: Resolver where U.ResolvedType == T>(instance: T) -> U {
return FunctionResolver({ () -> T in instance }) as U
}
class TestObject {
init() { }
}
let obj = TestObject()
let r = singleton(obj)
However the last line fails with:
playground466.swift:30:9: error: cannot convert the expression's type 'TestObject' to type 'Resolver'
let r = singleton(obj)
^~~~~~~~~
Why is Swift trying to convert obj to a Resolver? I am not quite sure what I am missing there. I think this should work since all the type information is available inside the singleton method.
Am I introducing some kind of loops in the inferrencing system? How can I fix this so the last line works as intended (a resolver that resolves to same instance of obj)?
I am on the latest Xcode available on the dev portal.
EDIT: I tried simplifying it, still does not work:
func singleton<T: Resolver>(instance: T.ResolvedType) -> T {
return FunctionResolver(resolver: { () -> T.ResolvedType in instance }) as T
}

The problem is that in this function:
func singleton<T, U>(instance: T) -> U {
return FunctionResolver({ () -> T in instance }) as U
}
U cannot be inferred as an input parameter - instead it's the type of the variable you assign its return value used to infer the type. If you write:
let r = singleton(obj)
you are not providing enough info to determine what U is. So you should explicitly specify its type:
let r: FunctionResolver<TestObject> = singleton(obj)
I know... the error message doesn't help much :) As a general rule, if it doesn't make sense, the problem is elsewhere.

Looks like you're pushing the type inference system past it's limits.
singleton() function is parametrised with generic type and returns a value of that generic type. There is never any information about what type T actually is.
The easiest fix, since Swift doesn't support explicitly providing values for generics in function, is to determine the return type.
let obj = TestObject()
let r : FunctionResolver = singleton(obj)
Works properly.
But what if you doesn't want to specify the exact type, just that r is Resolver?
Tough luck. Swift doesn't support that. Protocols with associated types can be used only as a generic constrains, as the compiler error states.

Related

In Swift 4, how can you get the string-representation of a data type stored in a variable of type 'Any'?

What is the easiest way to get the string-representation of a value's data type if that value is stored in an 'Any' variable?
For instance, I'm debugging code that has this...
extension SomeClass : Mappable{
static func map(value:Any) -> SomeClass{
return Parse(value)
}
}
I'm trying to figure out what data types are being passed through the function, but if I use type(of:) I keep getting 'Any' and not the value held in it.
extension SomeClass : Mappable{
static func map(value:Any) -> SomeClass{
let nameOfType = ??? <-- This is what I'm trying to figure out
log(nameOfType)
return Parse(value)
}
}
I simply want to print the data type to the debug window, not do testing with is or as, etc. It's strictly for logging/debugging reasons.
Ok, I figured it out. It's a two-step process.
You have to:
Use type(of:) to get the type of the variable (as others have described)
Use String(describing:) to get the name of that type (that was the missing piece)
Here's an example...
let typeName = String(describing: type(of:value))
That's what I was after. Thanks for the other answers. Hope this helps!
static func map(value:AnyObject) -> AnyClass{
return value.classForCoder
}
Or
static func map(value:Any) -> AnyClass{
return (value as AnyObject).classForCoder
}
In Swift 4 you can achieve that like this:
static func map(value: Any) -> Any.Type {
return type(of: value)
}

Is there an Kotlin equivalent `with` function in Swift?

In Kotlin, we could change the below
// Original code
var commonObj = ClassCommonObj()
commonObj.data1 = dataA
commonObj.data2 = dataB
commonObj.data3 = dataC
// Improved code
var commonObj = ClassCommonObj()
with(commonObj) {
data1 = dataA
data2 = dataB
data3 = dataC
}
However in Swift as below, do I have equivalent with function to use?
// Original code
var commonObj = ClassCommonObj()
commonObj.data1 = dataA
commonObj.data2 = dataB
commonObj.data3 = dataC
Unfortunately, no such functionality so far in Swift. However, similar functionality can be reached with the power of extensions:
protocol ScopeFunc {}
extension ScopeFunc {
#inline(__always) func apply(block: (Self) -> ()) -> Self {
block(self)
return self
}
#inline(__always) func with<R>(block: (Self) -> R) -> R {
return block(self)
}
}
This protocol and extension provides two inline functions, where one can be served to return processed object, and the other is strictly similar to with in Kotlin and other languages (Visual Basic supported in 90s).
Usage
Specify types which these functions should apply to:
extension NSObject: ScopeFunc {}
apply:
let imageView = UIImageView().apply {
$0.contentMode = .scaleAspectFit
$0.isOpaque = true
}
Here we create an object and once the closure is executed, modified object is returned.
with:
imageView.with {
$0.isHidden = true
}
Works equal to with in Kotlin.
Originaly based on this source code.
NOTE:
Swift compiler is generally regarded as smart enough to decide whether or not a function should be inlined. Quite likely, these two would be inlined due to their relative compactness even without strictly specifying #inline (__always). Either way, you should know that this keyword does not affect the logic and the result of these, because inlining is about optimizing the program.
Like #Hexfire said, so far, no built-in Swift equivalent to Kotlin's with(). As he points out, you can more or less write one yourself.
I use a version slightly different than the Kotlin with() that automatically returns the modified element (more akin to Kotlin's apply). I find this clearer, pithier, and more generally useful.
This is the version I use:
#discardableResult
public func with<T>(_ item: T, _ closure: (inout T) -> Void) -> T {
var mutableItem = item
closure(&mutableItem)
return mutableItem
}
It's declared globally (so no dependency on NSObject or extension declarations). It also handles mutability like I expect. In use, it looks like:
let myWellDescribedLabel = with(UILabel()) {
$0.attributedText = attributedStringTitle
$0.isAccessibilityElement = true
$0.numberOfLines = 1
}
Unfortunately (or is it? see comments), Swift does not have self syntax in closures, so you must reference the passed object as $0 (or create a named parameter to the closure).
While we're here, a withLet() that handles optionals is also very useful:
#discardableResult
public func withLet<T>(_ item: Optional<T>, _ closure: (inout T) -> Void) -> Optional<T> {
guard let item = item else { return nil }
return with(item, closure)
}
These are in a gist here.

Swift: Protocol Based Type Construction

I'm trying to create a protocol in Swift I can use for object construction. The problem I'm running into is that I need to store the type information so the type can be constructed later and returned in a callback. I can't seem to find a way to store it without either crashing the compiler or creating build errors. Here's the basics (a contrived, but working example):
protocol Model {
init(values: [String])
func printValues()
}
struct Request<T:Model> {
let returnType:T.Type
let callback:T -> ()
}
We have a simple protocol that declares a init (for construction) and another func printValues() (for testing). We also define a struct we can use to store the type information and a callback to return the new type when its constructed.
Next we create a constructor:
class Constructor {
var callbacks: [Request<Model>] = []
func construct<T:Model>(type:T.Type, callback: T -> ()) {
callback(type(values: ["value1", "value2"]))
}
func queueRequest<T:Model>(request: Request<T>) {
callbacks.append(request)
}
func next() {
if let request = callbacks.first {
let model = request.returnType(values: ["value1", "value2"])
request.callback(model)
}
}
}
A couple things to note: This causes a compiler crash. It can't figure this out for some reason. The problem appears to be var callbacks: [Request<Model>] = []. If I comment out everything else, the compiler still crashes. Commenting out the var callbacks and the compiler stops crashing.
Also, the func construct works fine. But it doesn't store the type information so it's not so useful to me. I put in there for demonstration.
I found I could prevent the compiler from crashing if I remove the protocol requirement from the Request struct: struct Request<T>. In this case everything works and compiles but I still need to comment out let model = request.returnType(values: ["value1", "value2"]) in func next(). That is also causing a compiler crash.
Here's a usage example:
func construct() {
let constructor = Constructor()
let request = Request(returnType: TypeA.self) { req in req.printValues() }
//This works fine
constructor.construct(TypeA.self) { a in
a.printValues()
}
//This is what I want
constructor.queueRequest(request)
constructor.next() //The callback in the request object should be called and the values should print
}
Does anyone know how I can store type information restricted to a specific protocol to the type can later be constructed dynamically and returned in a callback?
If you want the exact same behavior of next I would suggest to do this:
class Constructor {
// store closures
var callbacks: [[String] -> ()] = []
func construct<T:Model>(type:T.Type, callback: T -> ()) {
callback(type(values: ["value1", "value2"]))
}
func queueRequest<T:Model>(request: Request<T>) {
// some code from the next function so you don't need to store the generic type itself
// **EDIT** changed closure to type [String] -> () in order to call it with different values
callbacks.append({ values in
let model = request.returnType(values: values)
request.callback(model)
})
}
func next(values: [String]) {
callbacks.first?(values)
}
}
Now you can call next with your values. Hopefully this works for you.
EDIT: Made some changes to the closure type and the next function
Unfortunately there is no way to save specific generic types in an array and dynamically call their methods because Swift is a static typed language (and Array has to have unambiguous types).
But hopefully we can express something like this in the future like so:
var callbacks: [Request<T: Model>] = []
Where T could be anything but has to conform to Model for example.
Your queueRequest method shouldn't have to know the generic type the Request it's being passed. Since callbacks is an array of Request<Model> types, the method just needs to know that the request being queued is of the type Request<Model>. It doesn't matter what the generic type is.
This code builds for me in a Playground:
class Constructor {
var callbacks: [Request<Model>] = []
func construct<T:Model>(type:T.Type, callback: T -> ()) {
callback(type(values: ["value1", "value2"]))
}
func queueRequest(request: Request<Model>) {
callbacks.append(request)
}
func next() {
if let request = callbacks.first {
let model = request.returnType(values: ["value1", "value2"])
request.callback(model)
}
}
}
So I found an answer that seems to do exactly what I want. I haven't confirmed this works yet in live code, but it does compile without any errors. Turns out, I needed to add one more level of redirection:
I create another protocol explicitly for object construction:
protocol ModelConstructor {
func constructWith(values:[String])
}
In my Request struct, I conform to this protocol:
struct Request<T:Model> : ModelConstructor {
let returnType:T.Type
let callback:T -> ()
func constructWith(values:[String]) {
let model = returnType(values: values)
callback(model)
}
}
Notice the actual construction is moved into the Request struct. Technically, the Constructor is no longer constructing, but for now I leave its name alone. I can now store the Request struct as ModelConstructor and correctly queue Requests:
class Constructor {
var callbacks: [ModelConstructor] = []
func queueRequest(request: Request<Model>) {
queueRequest(request)
}
func queueRequest(request: ModelConstructor) {
callbacks.append(request)
}
func next() {
if let request = callbacks.first {
request.constructWith(["value1", "value2"])
callbacks.removeAtIndex(0)
}
}
}
Note something special here: I can now successfully "queue" (or store in an array) Request<Model>, but I must do so indirectly by calling queueRequest(request: ModelConstructor). In this case, I'm overloading but that's not necessary. What matters here is that if I try to call callbacks.append(request) in the queueRequest(request: Request<Model>) function, the Swift compiler crashes. Apparently we need to hold the compiler's hand here a little so it can understand what exactly we want.
What I've found is that you cannot separate Type information from Type Construction. It needs to be all in the same place (in this case it's the Request struct). But so long as you keep construction coupled with the Type information, you're free to delay/store the construction until you have the information you need to actually construct the object.

How do I declare a function that takes *any* block/closure as parameter?

I want to pass any block around as a parameter, without wanting to know the precise block parameter/return type.
func myFunc(block:(xxx) -> yyy) -> AnyObject {
...
}
So xxx in my code should match any number of parameters (including none) of any type. And yyy could be anything from void to AnyObject to an NSObject.
You can make a generic function:
func myFunc<A,B>(block:A -> B) -> AnyObject {
...
}
Unfortunately, you can't do that in Swift. Function Types are defined by their parameters and return types and there is no general function type. Functions also don't conform to Any or AnyObject, so you also can't use those either.
In Swift it's still possible to use the Selector. Maybe you can achieve what you want using that. See sample below:
func myFunc(selector:Selector) -> AnyObject {
self.performSelector(selector)
}
func someSelector() -> String {
return "test"
}
var result: AnyObject = myFunc(Selector("someSelector"))

Assigning to a var defined in Protocol says that it can't assign to it

Here is a simple use case:
protocol Debuggable {
var _d: String -> () {
get set
}
}
class Debugger {
class func attach(instance: Debuggable) {
let d = Debugger()
instance._d = d.d // This doesn't work
}
func d(message: String) {
println(message)
}
}
Error message at compile time: Cannot assign to _d in instance, although my protocol defines the var with a getter and setter.
This is a good case of the compiler catching an error for you :)
instance may be a value type and therefore be copied in to this method. In that case, you will modify the copy and just throw it out. The quickest fix is to define it as an inout parameter:
class func attach(inout instance: Debuggable) {
let d = Debugger()
instance._d = d.d
}
I think it would be better to return the instance though:
class func attach(instance: Debuggable) -> Debuggable {
let d = Debugger()
var ret = instance
ret._d = d.d
return ret
}
I feel that inout is mostly in the language for backwards compatibility to Objective-C and C. Let the type determine if it should be copied instead of forcing it to be passed by reference. If something is defined as a value type, there is a good reason for it.