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

Unable to declare a C function pointer with varargs #214

Open
bcardiff opened this issue Sep 20, 2014 · 7 comments
Open

Unable to declare a C function pointer with varargs #214

bcardiff opened this issue Sep 20, 2014 · 7 comments

Comments

@bcardiff
Copy link
Member

Syntax error in ...: unexpected ',' in type (use parenthesis to disambiguate)

@[Link("objc")]
lib LibObjC
  type SEL = Void*
  type IMP = Pointer(UInt8), LibObjC::SEL, ... -> Pointer(UInt8)
end
@asterite
Copy link
Member

For now you can use Void* forIMP.

I can see in class_addMethod you must pass an IMP. Can you get an IMP back from an objective-c call? And how do you use it?

We can add that feature to the language but I need to know how you would use it in order to implement it well.

@bcardiff
Copy link
Member Author

I don't care, at least for now, getting a IMP from obj-c. I just need to create them on crystal and pass it to class_addMethod.

Each IMP instance will vary on the arguments after the 3rd param.

$AppDel_didFinishLaunching = -> (obj : UInt8*, _cmd : LibObjC::SEL, aNotification : UInt8*) {
}

If I declare IMP as Void* I get:

LibObjC.class_addMethod($x_MyAppDelegate_objc_class.obj, "applicationDidFinishLaunching:".to_sel.to_objc, $AppDel_didFinishLaunching, "v@:@")
# argument #3 of 'LibObjC#class_addMethod' must be LibObjC::IMP, not (Pointer(UInt8), LibObjC::SEL, Pointer(UInt8) -> Int32)

if I try to cast, I get:

LibObjC.class_addMethod($x_MyAppDelegate_objc_class.obj, "applicationDidFinishLaunching:".to_sel.to_objc, $AppDel_didFinishLaunching as LibObjC::IMP, "v@:@")
# can't cast (Pointer(UInt8), LibObjC::SEL, Pointer(UInt8) -> Void) to LibObjC::IMP

My only workaround is to define many IMP and menu addMethod aliases, one for each signature :-(

At least I would need a generic function pointer.

FYI: this crocoa code is WIP and not pushed yet.

@asterite
Copy link
Member

You can try doing alias IMP = Void* and then do the cast. Does that work?

@bcardiff
Copy link
Member Author

Same result using alias IMP = Void*

with $AppDel_didFinishLaunching

argument #3 of 'LibObjC#class_addMethod' must be Pointer(Void), not (Pointer(UInt8), LibObjC::SEL, Pointer(UInt8) -> Void)

with $AppDel_didFinishLaunching as LibObjC::IMP

can't cast (Pointer(UInt8), LibObjC::SEL, Pointer(UInt8) -> Void) to Pointer(Void)

bcardiff pushed a commit to manastech/crocoa that referenced this issue Sep 21, 2014
@bcardiff
Copy link
Member Author

I push the spike around this on https://github.com/manastech/crocoa/tree/master/samples/bundled_application . Just in case is easier to check further ideas.

$ build.sh
$ open Sample.app

@asterite
Copy link
Member

I forgot our procs are always a pair containing a pointer to the function and a pointer to the closure context (which is null if it's not a closure). You can access that pointer by invoking pointer:

alias IMP = Void*
f = ->{ 1 }
f.pointer as IMP # works

You can use that workaround until we implement variadic function pointers (only for C bindings, I guess).

Note that Function#pointer doesn't check that the proc is not a closure: if it is and you pass that pointer to C things will probably won't work, so this is unsafe (or we should raise if someone tries to get the pointer of a closure).

bcardiff pushed a commit to manastech/crocoa that referenced this issue Sep 22, 2014
@bcardiff
Copy link
Member Author

Yeap, it did the trick. You choose whether to leave this issue open or not. For me is enough with the workaround.

I agree that an exception for closures should be raised.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants