Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-664] Allow use of @convention(block) on class / struct methods #43279

Closed
iby opened this issue Feb 3, 2016 · 1 comment
Closed

[SR-664] Allow use of @convention(block) on class / struct methods #43279

iby opened this issue Feb 3, 2016 · 1 comment
Labels
compiler The Swift compiler in itself feature A feature request or implementation

Comments

@iby
Copy link

iby commented Feb 3, 2016

Previous ID SR-664
Radar None
Original Reporter @iby
Type New Feature
Status Resolved
Resolution Won't Do
Additional Detail from JIRA
Votes 0
Component/s
Labels New Feature
Assignee None
Priority Medium

md5: 8fc61590c47864f685a070f61dff4949

Issue Description:

I'm making use of `@convention(block)` tag to cast my blocks as objects and compare them later. I've read that Swift nor Objective C don't provide direct comparison due to complexity and other reasons, despite this method working pretty well in my situation. For me this is kind of an important feature, but I'm missing the ability to use `@convention(block)` directly on class methods.

By directly I mean that I can simply same class method to another variable casted with `lazy var swfBlock: ObjBlock = self.swf` and it would work as expected.

import Foundation

// Some interesting observations on block comparing. Apparently swift nor objective c don't allow comparing closures
// due to the complexity of the process and because of compiler optimisations… bla bla. But it seems to be possible
// to do this using conventions blocks, aka the objective c ones that can be cast as objects. The interesting part 
// is how swift freely casts SwfBlock to ObjBlock, yet in reality two casted SwfBlock blocks will always be different
// values, while ObjBlocks won't. When we cast ObjBlock to SwfBlock, the same thing happens to them, they become two
// different values. So, in order to preserve the reference, this sort of casting should be avoided.

typealias SwfBlock = () -> ()
typealias ObjBlock = @convention(block) () -> ()

func testSwfBlock(a: SwfBlock, _ b: SwfBlock) -> String {
    let objA = unsafeBitCast(a as ObjBlock, AnyObject.self)
    let objB = unsafeBitCast(b as ObjBlock, AnyObject.self)
    return "a is ObjBlock: \(a is ObjBlock), b is ObjBlock: \(b is ObjBlock), objA === objB: \(objA === objB)"
}

func testObjBlock(a: ObjBlock, _ b: ObjBlock) -> String {
    let objA = unsafeBitCast(a, AnyObject.self)
    let objB = unsafeBitCast(b, AnyObject.self)
    return "a is ObjBlock: \(a is ObjBlock), b is ObjBlock: \(b is ObjBlock), objA === objB: \(objA === objB)"
}

func testAnyBlock(a: Any?, _ b: Any?) -> String {
    if !(a is ObjBlock) || !(b is ObjBlock) {
        return "a nor b are ObjBlock, they are not equal"
    }
    let objA = unsafeBitCast(a as! ObjBlock, AnyObject.self)
    let objB = unsafeBitCast(b as! ObjBlock, AnyObject.self)
    return "a is ObjBlock: \(a is ObjBlock), b is ObjBlock: \(b is ObjBlock), objA === objB: \(objA === objB)"
}

class Foo
{
    lazy var swfBlock: ObjBlock = self.swf
    func swf() { print("swf") }
    @objc func obj() { print("obj") }
}

let swfBlock: SwfBlock = { print("swf") }
let objBlock: ObjBlock = { print("obj") }
let foo: Foo = Foo()

print(testSwfBlock(swfBlock, swfBlock)) // a is ObjBlock: false, b is ObjBlock: false, objA === objB: false
print(testSwfBlock(objBlock, objBlock)) // a is ObjBlock: false, b is ObjBlock: false, objA === objB: false

print(testObjBlock(swfBlock, swfBlock)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: false
print(testObjBlock(objBlock, objBlock)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: true

print(testAnyBlock(swfBlock, swfBlock)) // a nor b are ObjBlock, they are not equal
print(testAnyBlock(objBlock, objBlock)) //a is ObjBlock: true, b is ObjBlock: true, objA === objB: true

print(testObjBlock(foo.swf, foo.swf)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: false
print(testSwfBlock(foo.obj, foo.obj)) // a is ObjBlock: false, b is ObjBlock: false, objA === objB: false
print(testAnyBlock(foo.swf, foo.swf)) // a nor b are ObjBlock, they are not equal
print(testAnyBlock(foo.swfBlock, foo.swfBlock)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: true
@belkadan
Copy link
Contributor

belkadan commented Feb 3, 2016

Block comparison, even in Objective-C, only compares pointers. Curried methods like self.doTheThing have to make a new closure value every time, since they don't have any way of knowing if one's been created before. The best you could do is find out if one closure has the same identity as another closure, but that doesn't actually tell you anything.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@AnthonyLatsis AnthonyLatsis added compiler The Swift compiler in itself feature A feature request or implementation and removed new feature labels Nov 11, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler The Swift compiler in itself feature A feature request or implementation
Projects
None yet
Development

No branches or pull requests

3 participants