swift: Assign function type to variable - swift

struct System {
var method: (() -> ())?
var curMethod: Int
init() {
method = nil
curMethod = 0
}
mutating func method1() {
curMethod = 1
}
mutating func method2() {
curMethod = 2
}
}
var sys = System()
sys.method = System.method1
sys.method!()
I get an error cannot assign value of type (inout System) -> () -> ()' to type '(() -> ())?. What am I doing wrong?

First of all, your line sys.method = System.method1 is wrong, as it would require method1 to be a static function (like a class function) rather than an instance function, so it should be changed to sys.method = sys.method1. But this isn't allowed - the error is "error: partial application of 'mutating' method is not allowed".
If you make System a class (rather than a struct), it will work if you replace the System.method1 with sys.method1.
The reason for this is that a mutating func is actually quite a lot more than a simple function under the hood - it is a curried function (curried with a compiler generated function) that effectively creates a new copy of the struct with the "new" value - hence, you A) can't access it it directly ("partial application is not allowed") and B) you can't assign it to a ()->() variable.

So, there're 3 variants suggested by participants. Everything is working, and using class instead of struct seems to me less complicated.
struct System1 {
var method: (() -> ())?
var curMethod: Int
init() {
method = nil
curMethod = 0
}
mutating func method1() { curMethod = 1 }
mutating func method2() { curMethod = 2 }
}
struct System2 {
var method: ((inout System2) -> ())?
var curMethod: Int
init() {
method = nil
curMethod = 0
}
mutating func callCurrentMethod() { method?(&self) }
mutating func method1() { curMethod = 1 }
mutating func method2() { curMethod = 2 }
}
class System3 {
var method: (() -> ())?
var curMethod: Int
init() {
method = nil
curMethod = 0
}
func method1() { curMethod = 1 }
func method2() { curMethod = 2 }
}
var struct1 = System1()
var struct2 = System2()
var class1 = System3()
print(struct1.curMethod)
let curried = System1.method1
let unsafe = curried(&struct1)
unsafe()
print(struct1.curMethod)
print(struct2.curMethod)
struct2.method = { $0.method1() }
struct2.callCurrentMethod()
print(struct2.curMethod)
print(class1.curMethod)
class1.method = class1.method1
class1.method!()
print(class1.curMethod)

Related

How can I get a specific struct type returned?

I want to initialize the struct by receiving the "struct type"(?) by a specific logic as below.
As I abstracted the return value of the struct into MyProtocol had a declaration of init(), which seems a little awkward.
I'm not sure I can do this.
I'd like to get an undecided struct type returned, what should I do?
Is this for the best?
For your information, Opaque Type is not available because it needs to support iOS 13 or earlier.
protocol MyProtocol {
init() // Is this for the best?
}
struct AAA: MyProtocol {
var numberAAA: Int // Sample variable.
init() {
print("init AAA")
numberAAA = 100
}
}
struct BBB: MyProtocol {
var numberBBB: Int // Sample variable.
init() {
print("init BBB")
numberBBB = 200
}
}
class MyClass {
func mainLogic() {
let myStruct = randomStruct()
myStruct.init() // This is the reason init () declared in the MyProtocol.
}
func randomStruct() -> MyProtocol.Type {
if Bool.random() {
return AAA.self
} else {
return BBB.self
}
}
}
init() as a protocol requirement seems odd. No one is stopping you to do this and compiler should allow this, however I would consider making protocol based on some other requirement rather than just init().
Here's an attempt to do so -
protocol NumberOperation {
var number: Int { get set }
mutating func perform()
}
struct Incrementer: NumberOperation {
var number: Int
mutating func perform() {
number += 1
}
}
struct Decrementer: NumberOperation {
var number: Int
mutating func perform() {
number -= 1
}
}
struct Record<O: NumberOperation> {
public var operation: O
mutating func perform() {
operation.perform()
}
}
class MyClass {
func mainLogic() {
var record = getRecord(type: Incrementer.self)
record.perform()
}
func getRecord<O: NumberOperation>(type: O.Type) -> Record<O> {
if type == Incrementer.self {
return Record(operation: Incrementer(number: 1) as! O)
}
return Record(operation: Decrementer(number: 10) as! O)
}
}
This introduces a container type Record that holds/wraps our type based on the same protocol conformation. This does the same what you were doing, probably is easier to read/understand.

Generic class with generic delegate. How can I distinguish which object's delegate is executing the callback?

MyClass is a generic class which has a generic delegate.
AClass contains two iVar instances of MyClass and also implements MyClassDelegate.
Where AClass implements MyClassDelegate, how can I distinguish which object is calling into the interface? With non-generic classes, == is acceptable.
Please see the comments and error messages at the bottom of this code snippet.
protocol MyClassDelegate: class {
func myClass<T>(_ myClass: MyClass<T>, valueDidChange value: T)
}
class MyClass<T: Comparable> {
private var _value: T
var value: T {
set {
delegate?.myClass(self, valueDidChange: newValue)
}
get {
return _value
}
}
var delegate: MyClassDelegate?
init(value: T) {
_value = value
}
}
class AClass {
private var thing1 = MyClass(value: Int(10))
private var thing2 = MyClass(value: Int(100))
private var thing3 = MyClass(value: TimeInterval(10))
private var thing4 = MyClass(value: TimeInterval(100))
init() {
thing1.delegate = self
thing2.delegate = self
thing3.delegate = self
thing4.delegate = self
}
}
extension AClass: MyClassDelegate {
func myClass<T>(_ myClass: MyClass<T>, valueDidChange value: T) {
// This fails to complile
// Binary operator '==' cannot be applied to operands of type 'MyClass<T>' and 'MyClass<Int>'
if myClass == thing1 {
}
// Binary operator '==' cannot be applied to operands of type 'MyClass<T>' and 'MyClass<TimeInterval>' (aka 'MyClass<Double>')
else if myClass == thing3 {
}
}
}
Restrict the T type in your protocol method signature func myClass<T>(...) to be Comparable. Since you restricted it only in one particular extension of that protocol, the method in AClass can take any kind of T, not just Comparable ones.
I tried and tried but couldn't configure the generic delegate in a manner where I could compare callers.
I read the answer from NRitH, but couldn't get the compiler to accept the syntax. Perhaps there is a way to do this, but I went a different route with success.
I gave up on the protocol/delegate technique and ended up using a callback closure. Instead of defining a delegate in MyClass and implementing that delegate in AClass, I defined a callback closure in MyClass in implemented that in AClass like so:
class MyClass<T: Comparable>: Equatable {
var valueChanged: ((_ clazz: MyClass) -> Void)?
private var _value: T
var value: T {
set {
_value = newValue
valueChanged?(self)
}
get {
return _value
}
}
init(value: T) {
_value = value
}
static public func ==(lhs: MyClass<T>, rhs: MyClass<T>) -> Bool {
return lhs.value == rhs.value
}
}
class AClass {
fileprivate var thing1: MyClass<Int> = MyClass(value: 10)
fileprivate var thing2: MyClass<Int> = MyClass(value: 100)
fileprivate var thing3: MyClass<TimeInterval> = MyClass(value: 10)
fileprivate var thing4: MyClass<TimeInterval> = MyClass(value: 100)
init() {
thing1.valueChanged = { (thing) in
// You can compare here, but you already know which object is callling back
if thing == self.thing1 {
}
}
thing2.valueChanged = { (thing) in
print("Thing2 changed: \(thing.value)")
}
}
}

swift 3 downcast to dynamic class

I am trying to create a couple of objects which are dependent one to each other and they mush have a method to downcast directly the concrete class of the other object. Something like this:
protocol aProt
{
var bVar:bProt! { get set }
}
protocol bProt
{
var aVar:aProt! { get set }
}
class a: aProt
{
var bVar: bProt!
func bConcrete() -> b {
return bVar as! b
}
}
class b: bProt
{
var aVar: aProt!
func aConcrete() -> a {
return aVar as! a
}
Now, the problem is that I want this behavior (func aConcrete(),func bConcrete()) to be inherited by the subclasses of a and b. Then I thought the perfect way of doing this was using generics, but... There's no way of doing this.
class a: aProt
{
var bVar: bProt!
func bConcrete() -> T {
return bVar as! T
}
}
class b: bProt
{
var aVar: aProt!
func aConcrete<T>() -> T {
return aVar as! T
}
You can do it but when you have to use it you must downcast the variable anyway, so there is no way of doing it in a clean manner:
let aObject = a()
let bSubclassObject = a.bConcrete() // The compiler complains it cannot infer the class of T
let bSubclassObject = a.bConcrete() as! bSubclass // this works, but this is exactly which I wanted to avoid... :(
Define the generic function and add where to T:
protocol aProt {
var bVar: bProt! { get set }
}
protocol bProt {
var aVar:aProt! { get set }
}
class a: aProt {
var bVar: bProt!
func bConcrete<T: b>(_ type: T.Type) -> T? {
return bVar as? T
}
}
class b: bProt {
var aVar: aProt!
func aConcrete<T: a>(_ type: T.Type) -> T? {
return aVar as? T
}
}
class a1: a { }
class b1: b {
var fullName: String = "new object"
}
let aObj = a()
aObj.bVar = b1()
let bObj = aObj.bConcrete(b1.self)
bObj?.fullName
According to your requirement, calls bConcrete(b1.self) might still not good enough, but at least you need to know what type of data you are expecting to return.

Parameterized Initializer Reflection in Swift

I am trying to apply reflection on a swift class (someClass) to invoke an init method that takes one argument (someArg), I managed to get the init selector and IMP that has 1 argument, but when I invoke the IMP it ends up calling the init with no arguments. In the Playground below I always get "called the wrong init" printed.
If I remove the override init I get the following error:
fatal error: use of unimplemented initializer 'init()' for class '__lldb_expr_15.someClass'
What am I missing?
import UIKit
public class someClass:NSObject{
init( num:someArg){
print("called the right init")
}
override init(){
print("called the wrong init")
}
}
public class someArg:NSObject{
override init(){
}
}
public class Test{
func reflect(){
let classType: NSObject.Type = someClass.self as NSObject.Type
let (initializerWithOneArgImp,selector) = getInitializerWithArguments(classType, argumentsCount: 1)
typealias initializerWithOneArgImpType = #convention(c) (AnyObject, Selector, AnyObject) -> (AnyObject)
let callback = unsafeBitCast(initializerWithOneArgImp , initializerWithOneArgImpType.self)
callback(classType,selector,someArg())
}
func getInitializerWithArguments(classType:AnyClass, argumentsCount:Int)->(IMP,Selector){
var methodCount:CUnsignedInt = 0
let methodList = class_copyMethodList(classType.self, &methodCount)
let n : Int = Int(methodCount)
for var i: Int = 0; i < n; i++ {
let methodSelector = method_getName(methodList[i])
let methodName:String = String(_sel:methodSelector)
if(methodName == "init")
{
let methodArgumentsCount = method_getNumberOfArguments(methodList[i])
if(methodArgumentsCount == UInt32(argumentsCount) + 1)
{
return (method_getImplementation(methodList[i]),methodSelector)
}
}
}
return (nil,nil)
}
}
var test = Test()
test.reflect()
Turns out, the non parametrized init has two arguments by default, and the parameterized init would have "initWithNum" as methodName.
if(methodName.hasPrefix("init"))
{
let methodArgumentsCount = method_getNumberOfArguments(methodList[i])
if(methodArgumentsCount == UInt32(argumentsCount) + 2)
{
return (method_getImplementation(methodList[i]),methodSelector)
}
}

Opposite of __conversion in Swift to assign to a value of a different type

Swift provides a special method called __conversion that allows you to implicitly convert your type to another type. I would like to be able to define a method that allows you to go the other way: to be able to assign a custom type to another type and have it implicitly converted to allow the assignment to work.
Forward usage that is valid:
class MyClass<T> {
var myValue : T
func __conversion() -> T? {
return myValue
}
init(value: T) {
self.myValue = value
}
}
func takesString(aString: String?) {
}
var myInstance = MyClass(value: "Hello")
takesString(myInstance)
What I would like to do:
class MyClass<T> {
func __conversion(aValue: T) -> MyClass<T> {
return MyClass(value: T)
}
}
var myInstance : MyClass<String> = "Hello World" // compiler error
Is there any way to do this?
It turns out that __conversion is a private method and will be removed by the end of the beta so this will definitely not be possible once Swift is released.
Have you tried adding an extension to String?
extension String {
func __conversion() -> MyClass {
var myInstance = MyClass()
myInstance.myString = self
return myInstance
}
}
It worked in an iOS playground in Xcode 6 Beta 4.
let anInstance: MyClass = "test"
To deal with generics:
class MyClass<T> {
var myString = ""
var myT : T?
}
extension String {
func __conversion<T>() -> MyClass<T> {
var myInstance = MyClass<T>()
myInstance.myString = self
return myInstance
}
}
let anInstance: MyClass<Int> = "test"
BTW: I think the Apple approved answer is an init method.
let anInstance = MyClass(myString: "test")