The cblock Macro Does Not Work #31

Open
sorin-ionescu opened this Issue Jan 8, 2012 · 19 comments

Projects

None yet

4 participants

It claims to not be able to find signature_for_identifier.

It would be helpful if blocks would just work like in MacRuby. I do not wish to distinguish between Nu blocks and Objective-C blocks.

#!/usr/bin/env nush

(load "nu")
(load "cblocks") 

(set myList '("one" "two" "three"))
(set myArray (myList array))

(puts "each: works")
(myList each:
    (do (obj)
        (puts obj)))

(puts "cBlockWithNuBlock: works")
(myArray enumerateObjectsUsingBlock:
    (NuBridgedBlock cBlockWithNuBlock:
        (do (obj idx stop)
            (puts obj))
        signature:"v@I^?")) 

(puts "cblock: fails")
(myArray enumerateObjectsUsingBlock:
    (cblock void ((id) obj (unsigned long) idx (BOOL*) stop)
        (puts obj)))
each: works
one
two
three
cBlockWithNuBlock: works
one
two
three
cblock: fails
Nu uncaught exception: NuCantFindBridgedFunction: dlsym(RTLD_DEFAULT, signature_for_identifier): symbol not found
If you are using a release build, try rebuilding with the KEEP_PRIVATE_EXTERNS variable set.
In Xcode, check the 'Preserve Private External Symbols' checkbox.

  from <TopLevel>:-1: in NuBridgedFunction
  from <TopLevel>:-1: in (NuBridgedFunction functionWithName: "signature_for_identifier" signature: "@@@")
  from <TopLevel>:-1: in ((NuBridgedFunction functionWithName: "signature_for_identifier" signature: "@@@") identifier (NuSymbolTable sharedSymbolTable))
  from <TopLevel>:-1: in g1804289383__get_type_signature
  from <TopLevel>:-1: in set
  from <TopLevel>:-1: in progn
  from <TopLevel>:-1: in bridgedblock
  from <TopLevel>:-1: in (bridgedblock (obj idx stop) (puts obj) ())
  from ./test.nu:23: in cblock
  from ./test.nu:22: in myArray
  from /Library/Frameworks/Nu.framework/Resources/help.nu:136: in progn
Contributor

I get a different, more informative error, but it still doesn't work. The signature_for_identifier function only recognizes two types of pointers: id* and void*. So this code does work:

(myArray enumerateObjectsUsingBlock:
   (cblock void ((id) obj (unsigned long) idx (void*) stop)
      (puts obj)))

It should be a pretty simple matter to add support for other pointer types. Other than improving code readability, I don't think it is necessary though. I'll try to work on that this week if no one else if eager to do so.

Thank you. I hope that in the future, this macro will be unnecessary and that blocks will be bridged automatically like in MacRuby.

Contributor
ksjogo commented Jan 11, 2012
Contributor

Hi,

I've been looking into this and while I'm not sure what the problem is, I am going to rewrite part of the code to use some relevant run-time functions which became available in Lion. These functions allow for the graceful creation of blocks from functions and I hope will eliminate the iOS problem.

More to come,
Philip

On Jan 11, 2012, at 10:50 AM, ksjogo wrote:

iOS has some cBlock issue at the moment too: http://groups.google.com/group/programming-nu/browse_thread/thread/b819d3e56cef2949


Reply to this email directly or view it on GitHub:
#31 (comment)

Objective-C blocks are implemented through NSGlobalBlock, NSStackBlock, and NSMallocBlock. So why not have NuBlock extend the Objective-C block classes? Instead of bridging, you can just downcast and upcast between a NuBlock and an Objective-C block automatically.

Contributor

It looks like MacRuby uses BridgeSupport to determine the signatures of blocks passed as arguments to Cocoa methods. So I suppose that could be done so the programmer doesn't have to manually input the signature.

Making NuBlock a subclass of a obj-c block class (presumably NSMallocBlock) sounds a little hairy. Is that what MacRuby does?. Alternately, when Nu finds that the user is passing an object to a method expecting a block, it could see if the object implements a method (say -cBlock) and, if so, call that method and pass the return value instead of the original object.

Along with this, the (do ...) syntax could be extended to allow the user to input type information. If information is not included for any argument, id can be assumed, similar to declaring instance and class methods in nu. This info would then be used if the NuBlock were passed to a method expecting an obj-c block. That would avoid the complexity of using BridgeSupport while eliminating the separate cblock macro. To my mind, that seems the best solution.

Does MacRuby allow objc-blocks to be used as Ruby blocks? I don't see a lot of utility in this, though perhaps it could be useful. Are there any Cocoa or GCD methods that return objc-blocks?

-Philip

On Jan 11, 2012, at 11:41 AM, Sorin Ionescu wrote:

Objective-C blocks are implemented through NSGlobalBlock, NSStackBlock, and NSMallocBlock. So why not have NuBlock extend the Objective-C block classes? Instead of bridging, you can just downcast and upcast between a NuBlock and an Objective-C block automatically.


Reply to this email directly or view it on GitHub:
#31 (comment)

The Apple blocks documentation does not mention how they are implemented, just the usage, but I have found an article explaining the implementation of Objective-C blocks, and it does not look very complicated. Thus, I do no think that extending it to fit Nu is hairy.

I do not know what MacRuby uses from the Scripting Bridge framework, but I have found that anything that has do with AppleScript and the Scripting Bridge is notoriously slow. I do remember that Objective-C blocks support was added in MacRuby 0.7.

Blocks should just work irrespective of whether they were written in Nu, Objective-C, or MacRuby. I am not aware of the top of my head, but methods that deal with iteration or asynchronicities may return blocks.

Owner

Sorin, I think you are right that Nu blocks should be interchangeable with C blocks. I also think that making NuBlock inherit from one of the Objective-C block classes sounds like a good idea. However, I haven't found documentation of these classes, and am concerned that they could be considered private APIs by the iOS app review team. Still, I think it's worth investigating. I am interested to see how MacRuby does this, but haven't looked at its source code yet.

@timburks clang is open source, is it not? While said classes may not be documented in the usual places, or documented at all, private, I believe, they are not, and even if they were private, they should be safe to use since Apple cannot change them without breaking not only MacRuby but also Objective-C.

Apple should release an App Store self audit tool. One should not have to wait days, weeks, months to only be disappointed by rejection.

Owner

Thanks for your thoughts. Of course clang is open source, but as you also know, "Apple should" might not be enough to get what we want in Cupertino.

Contributor
ksjogo commented Mar 6, 2012

Perhaps we could write Apple and ask them?
Blocks seem to be going more important with them and it would be great to be able to use them without hassle.
Some gcd wrappers would be hot as hell too.

Contributor

It seems to me that subclassing NSBlock would be nice, but not worth the uncertainty. Since Nu already does various automatic conversions during method calls, it would be fairly easy to have it convert a NuBlock to an Obj-C block whenever one of the former is passed as a parameter to a method that expects an Obj-C block. We would have to use BridgeSupport to get the correct block signature though, I believe. I've have been told that this is what LuaCocoa does. I also believe that the Bridge Support data is incomplete in this regard, so we would also have to allow ways to explicitly specify block signatures.

-Philip

On Mar 6, 2012, at 6:44 AM, ksjogo wrote:

Perhaps we could write Apple and ask them?
Blocks seem to be going more important with them and it would be great to be able to use them without hassle.
Some gcd wrappers would be hot as hell too.


Reply to this email directly or view it on GitHub:
#31 (comment)

LuaCocoa is a bridged language. MacRuby and Nu are the only native ones. Let's not use slow bridges.

Contributor

When writing C/Obj-C, you have to explicitly specify the signatures of your blocks (aside from letting the compiler intuit the return type or defaulting to id). So at some point, Nu needs to be informed what the parameter types are as well. As far as I can tell, the only ways to do this are to let the user specify explicitly or to gather that information from Bridge Support. If MacRuby doesn't require the user to specify types, then dollars to donuts they are getting that info from Bridge Support.

Personally, I think there is nothing wrong with having the user specify explicitly. I've written about it before on the mailing list, or maybe here, but I think the "do" syntax should be extended to accept optional argument types. Any type excluded is assumed to be id. This information would be used when Nu automatically converts the NuBlocks to objc blocks during a method call. Then we wouldn't have to worry about all of the complications that come with Bridge Support.

-Philip

On Mar 6, 2012, at 9:50 AM, Sorin Ionescu wrote:

LuaCocoa is a bridged language. MacRuby and Nu are the only native ones. Let's not use slow bridges.


Reply to this email directly or view it on GitHub:
#31 (comment)

Contributor
ksjogo commented Mar 6, 2012

So having something like this?
(do ( (NSArray) array (int) index ) (array objectAtIndex:index))
Looks good for me.

And would it be possible to convert a returned cBlock to a NuBlock when the user provides the signature?

Any news on the iOS side?

@ksjogo That should be optional. MacRuby doesn't ask you to mention types. It just works.

Contributor
ksjogo commented Mar 7, 2012

That is for sure.
Thinking about one could probably go even further.
Default values and named parameters.
Named parameters would increase the homogeneous interweaving with Objc and provide its readability for blocks.
And default values would decrease the need for boilerplate code.

Contributor

Nu amalgamated on my github repository has some updates to the block bridge that should ease the transition to seamless passing of NuBlocks to methods and functions expecting c blocks. I removed the NuBridgedBlock class entirely and moved its functionality to a method -cBlockWithSignature: in the NuBlock class. I also now use the struct definition of a block found in clang documentation when editing the block. Next step will be to make the appropriate changes to set_objc_value_from_nu_value so that when nu_value is a NuBlock and typeString is a block ("@?"), it looks up the signature for the block in bridge support and then calls this new method to get the objc_value.

In regards to iOS, I'm not sure how to fix that problem. I spent several hours yesterday trying to figure this out, but since it works when the debugger is attached, its pretty hard to debug… Given that it dies with signal 9, I kind of suspect that the OS is killing it. Maybe it does some kind of security check and sees that a block is being screwed with. There are quite a few flags in the block object, of which four or five are documented; maybe a flag needs to be set or unset somewhere for it to work. I did some experiments along those lines but gave up for now. Sorry!

Contributor
ksjogo commented Mar 20, 2012

I had an idea to circumvent the block hassling at runtime. I think most times Nu will get shipped with the binary (on iOS a must, on Mac probably because having the user to install a framework is 'not good'). Meaning the developer could customize Nu a bit.
We could add predefined block handlers like the method handlers and then create blocks from the block handlers and let the cblocks just capture our NuBlocks.
For the most common types int/void/float/bool/id return with int/void/float/bool/id we could add the handlers to the Nu.m file, the missing ones the developer could add for himself.

This approach has the disadvantage of being not automatic on uncommen types (we could add them over time) but will be safe to go with upcoming versions because we do no binary tricks with blocks.

What do you think?

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