Stupid block syntax!

  • Why doesn't this compile?

    NSComparisonResult (^comp)( id<DKStorableObject>, id<DKStorableObject> ) = ^( id<DKStorableObject> a, id<DKStorableObject> b )
    {
      if( a.index < b.index )
      return NSOrderedAscending;
      else if ( a.index > b.index )
      return NSOrderedDescending;
      else
      return NSOrderedSame;
    };

    error: incompatible block pointer types initializing 'NSComparisonResult (^)(id<DKStorableObject>, id<DKStorableObject>)' with an expression of type 'int (^)(id<DKStorableObject>, id<DKStorableObject>)'

    Why does it assume that the return type is 'int"? There is nothing here that appears to suggest it is one. NSComparisonResult is a typedef of NSInteger. If I attempt to cast the result, I get an equally baffling error:

    error: invalid block pointer conversion initializing 'NSComparisonResult (^)(id<DKStorableObject>, id<DKStorableObject>)' with an expression of type 'NSComparisonResult' (aka 'long')

    I see there is a typedef for a generic comparator already, but I want to declare it as conforming to a protocol.

    Could the stupid block syntax be any less intuitive?

    --Graham
  • Put 'NSComparisonResult' after = and before ^ to declare the return value of the block in the code below.

    When that fails. Err. Not sure.

    > NSComparisonResult (^comp)( id<DKStorableObject>, id<DKStorableObject> ) = ^( id<DKStorableObject> a, id<DKStorableObject> b )  {

    On 4 Jul, 2012, at 13:40, Graham Cox <graham.cox...> wrote:

    > Why doesn't this compile?
    >
    >
    > NSComparisonResult (^comp)( id<DKStorableObject>, id<DKStorableObject> ) = ^( id<DKStorableObject> a, id<DKStorableObject> b )
    > {
    > if( a.index < b.index )
    > return NSOrderedAscending;
    > else if ( a.index > b.index )
    > return NSOrderedDescending;
    > else
    > return NSOrderedSame;
    > };
    >
    > error: incompatible block pointer types initializing 'NSComparisonResult (^)(id<DKStorableObject>, id<DKStorableObject>)' with an expression of type 'int (^)(id<DKStorableObject>, id<DKStorableObject>)'
    >
    > Why does it assume that the return type is 'int"? There is nothing here that appears to suggest it is one. NSComparisonResult is a typedef of NSInteger. If I attempt to cast the result, I get an equally baffling error:
    >
    > error: invalid block pointer conversion initializing 'NSComparisonResult (^)(id<DKStorableObject>, id<DKStorableObject>)' with an expression of type 'NSComparisonResult' (aka 'long')
    >
    > I see there is a typedef for a generic comparator already, but I want to declare it as conforming to a protocol.
    >
    >
    > Could the stupid block syntax be any less intuitive?
    >
    > --Graham
  • On Jul 4, 2012, at 12:40 AM, Graham Cox wrote:

    > Why doesn't this compile?
    >
    >
    > NSComparisonResult (^comp)( id<DKStorableObject>, id<DKStorableObject> ) = ^( id<DKStorableObject> a, id<DKStorableObject> b )
    > {
    > if( a.index < b.index )
    > return NSOrderedAscending;
    > else if ( a.index > b.index )
    > return NSOrderedDescending;
    > else
    > return NSOrderedSame;
    > };
    >
    > error: incompatible block pointer types initializing 'NSComparisonResult (^)(id<DKStorableObject>, id<DKStorableObject>)' with an expression of type 'int (^)(id<DKStorableObject>, id<DKStorableObject>)'
    >
    > Why does it assume that the return type is 'int"? There is nothing here that appears to suggest it is one.

    Yes, there is.  NSOrderedAscending, NSOrderedDescending, and NSOrderedSame are elements of an enum.  They are effectively ints.

    > NSComparisonResult is a typedef of NSInteger.

    Right, but the elements of the enum are not of type NSComparisonResult.  In traditional C, there's no way to declare the type of elements of an enum.  There's a coming extension to the language in clang that addresses this.  <http://clang.llvm.org/docs/LanguageExtensions.html#objc_fixed_enum>  I don't know what version of Xcode includes or will include this.  Even when it arrives in the compiler, the SDK will have to be updated to take advantage of it.

    > If I attempt to cast the result, I get an equally baffling error:

    Cast what result?  I bet if you cast the value in each return statement, that would work.

    > error: invalid block pointer conversion initializing 'NSComparisonResult (^)(id<DKStorableObject>, id<DKStorableObject>)' with an expression of type 'NSComparisonResult' (aka 'long')

    Sounds like you tried to cast the block reference to an NSComparisonResult.  Roland has suggested the syntax for explicitly declaring the return type of the block, which is not a cast as such.  It just means the compiler doesn't have to / get to infer it from the return statements within the block.

    > Could the stupid block syntax be any less intuitive?

    It follows the general form for C declarations, such as for function pointers.  However, blocks can be defined in different contexts than functions, which makes it seem out of place.  In general, try writing it exactly as though you were writing a function.  Then replace the function name with either "^" or, when defining a variable or typedef, "(^name_of_variable_or_typedef)".

    Regards,
    Ken
  • On Jul 3, 2012, at 22:40 , Graham Cox wrote:

    > NSComparisonResult (^comp)( id<DKStorableObject>, id<DKStorableObject> ) = ^( id<DKStorableObject> a, id<DKStorableObject> b )

    Actually, for a block literal, it's:

    … = ^NSComparisonResult ( id<DKStorableObject> a, id<DKStorableObject> b ) { … }

    The literal syntax puts the return type after the [unparenthesized] "^", unlike the pointer syntax which puts the return type before the [parenthesized] "^".

    > Could the stupid block syntax be any less intuitive?

    Well, to be fair, it's *two* stupid syntaxes.
  • On Jul 4, 2012, at 12:40 AM, Graham Cox wrote:
    >
    > Could the stupid block syntax be any less intuitive?

    There’s a reason that the very first items in the Code Snippets inspector are block declarations.

    Charles
  • > Could the stupid block syntax be any less intuitive?

    Sure. It could be a C++ block syntax and mix some '*', '&' and 'const's in there :)
  • On 04/07/2012, at 3:50 PM, Roland King wrote:

    > Put 'NSComparisonResult' after = and before ^ to declare the return value of the block in the code below.

    That didn't work, but after a few more wild guesses, I stumbled on the correct form:

    NSComparisonResult (^comp)( id<DKStorableObject>, id<DKStorableObject> ) = ^NSComparisonResult( id<DKStorableObject> a, id<DKStorableObject> b )
    {
      if( a.index < b.index )
      return NSOrderedAscending;
      else if ( a.index > b.index )
      return NSOrderedDescending;
      else
      return NSOrderedSame;
    };

    >
    > When that fails. Err. Not sure.

    That's the trouble - when it doesn't work, even when you follow the examples in the documentation apparently to the letter, you're stuck.

    On 04/07/2012, at 4:12 PM, Ken Thomases wrote:

    > t follows the general form for C declarations, such as for function pointers.  However, blocks can be defined in different contexts than functions, which makes it seem out of place.  In general, try writing it exactly as though you were writing a function.  Then replace the function name with either "^" or, when defining a variable or typedef, "(^name_of_variable_or_typedef)".

    OK, that's a handy bit of help. Mind you, function pointers themselves are not always that easy to get right, though I haven't run into anywhere near as much trouble with them as I have with blocks.

    Thanks for all the advice,

    --Graham
  • On 04/07/2012, at 4:19 PM, Quincey Morris wrote:

    > Actually, for a block literal, it's:
    >
    > … = ^NSComparisonResult ( id<DKStorableObject> a, id<DKStorableObject> b ) { … }
    >
    > The literal syntax puts the return type after the [unparenthesized] "^", unlike the pointer syntax which puts the return type before the [parenthesized] "^".
    >

    Ah, and I just saw this after reading the earlier replies and drunkenly stumbling around in my code for a bit longer...

    Thanks!!

    --Graham
  • On Jul 4, 2012, at 8:13 PM, Graham Cox wrote:

    >
    > On 04/07/2012, at 3:50 PM, Roland King wrote:
    >
    >> Put 'NSComparisonResult' after = and before ^ to declare the return value of the block in the code below.
    >
    >
    > That didn't work, but after a few more wild guesses, I stumbled on the correct form:
    >
    > NSComparisonResult (^comp)( id<DKStorableObject>, id<DKStorableObject> ) = ^NSComparisonResult( id<DKStorableObject> a, id<DKStorableObject> b )

    Sorry 'bout that Graham, I was writing it on the bus and proved that indeed the syntax is a beast and I didn't remember it either, and I went through this myself just a few days back. I sort of understand the explanation by Ken Thomas, although I never really gelled with the C function pointer syntax and always had to look that up. Not sure whether that last little wrinkle, the ^ before the return type when you declare one, is easily explained by anything.
  • On Jul 4, 2012, at 7:45 AM, Roland King wrote:

    > I sort of understand the explanation by Ken Thomas, although I never really gelled with the C function pointer syntax and always had to look that up.

    Well, my suggestion was actually to think in terms of just C function syntax, not function pointer syntax, precisely so it would be something familiar and (pardon the pun) routine.

    Of course, it doesn't help that I also got the position of the return type when defining a block object wrong.

    > Not sure whether that last little wrinkle, the ^ before the return type when you declare one, is easily explained by anything.

    I'm guessing it's necessary to make it parseable by the compiler.  Having a type name come first where an expression is required would be ambiguous and hard to parse.  Having the ^ come first presumably resolves the ambiguity.

    Regards,
    Ken
  • On Wed, 4 Jul 2012 01:12:12 -0500, Ken Thomases said:

    > Right, but the elements of the enum are not of type NSComparisonResult.
    > In traditional C, there's no way to declare the type of elements of an
    > enum.  There's a coming extension to the language in clang that
    > addresses this.  < http://clang.llvm.org/docs/
    >LanguageExtensions.html#objc_fixed_enum>  I don't know what version of
    > Xcode includes or will include this.  Even when it arrives in the
    > compiler, the SDK will have to be updated to take advantage of it.

    The SDK will indeed have to change... In Objective-C++11 this is problematic because NSComparisonResult and NSInteger are now different enough that, for example, NSArray's declaration of:

    - (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context;

    is quite wrong to use NSInteger when it means NSComparisonResult.

    --
    ____________________________________________________________
    Sean McBride, B. Eng                <sean...>
    Rogue Research                        www.rogue-research.com
    Mac Software Developer              Montréal, Québec, Canada
  • On 4 Jul 2012, at 07:19, Quincey Morris wrote:

    > On Jul 3, 2012, at 22:40 , Graham Cox wrote:
    >
    >> NSComparisonResult (^comp)( id<DKStorableObject>,
    >> id<DKStorableObject> ) = ^( id<DKStorableObject> a,
    >> id<DKStorableObject> b )
    >
    > Actually, for a block literal, it's:
    >
    > … = ^NSComparisonResult ( id<DKStorableObject> a,
    > id<DKStorableObject> b ) { … }
    >
    > The literal syntax puts the return type after the [unparenthesized]
    > "^", unlike the pointer syntax which puts the return type before
    > the [parenthesized] "^".
    >
    >> Could the stupid block syntax be any less intuitive?
    >
    > Well, to be fair, it's *two* stupid syntaxes.
    >

    I'm so glad that I'm not the only one that find the Block Syntax the
    pits. Myself and a colleague struggled for over an hour trying to get
    it right and I'm still no wiser really!

    What I can't understand is why it was implemented that way?!? I mean
    surely there could have been a clearer way of defining and executing
    a block of code that the one we have at present?

    Cheers
    Dave
  • On Jul 4, 2012, at 4:37 PM, Dave wrote:

    > On 4 Jul 2012, at 07:19, Quincey Morris wrote:
    >
    >> On Jul 3, 2012, at 22:40 , Graham Cox wrote:
    >>
    >>> NSComparisonResult (^comp)( id<DKStorableObject>, id<DKStorableObject> ) = ^( id<DKStorableObject> a, id<DKStorableObject> b )
    >>
    >> Actually, for a block literal, it's:
    >>
    >> … = ^NSComparisonResult ( id<DKStorableObject> a, id<DKStorableObject> b ) { … }
    >>
    >> The literal syntax puts the return type after the [unparenthesized] "^", unlike the pointer syntax which puts the return type before the [parenthesized] "^".
    >>
    >>> Could the stupid block syntax be any less intuitive?
    >>
    >> Well, to be fair, it's *two* stupid syntaxes.
    >>
    >
    > I'm so glad that I'm not the only one that find the Block Syntax the pits. Myself and a colleague struggled for over an hour trying to get it right and I'm still no wiser really!
    >
    > What I can't understand is why it was implemented that way?!? I mean surely there could have been a clearer way of defining and executing a block of code that the one we have at present?

    They did it that way because they were following the C function pointer syntax, just replacing the * with a ^. Really, the blame for this lies with Kernighan and Ritchie more than anyone else. I think Apple followed the C syntax because they may have some hopes about getting blocks officially added to some future revision of the C specification, although I’m not sure how realistic that is.

    Charles
  • On 05/07/2012, at 7:53 AM, Charles Srstka wrote:

    > They did it that way because they were following the C function pointer syntax, just replacing the * with a ^. Really, the blame for this lies with Kernighan and Ritchie more than anyone else. I think Apple followed the C syntax because they may have some hopes about getting blocks officially added to some future revision of the C specification, although I’m not sure how realistic that is.

    I read recently that the '^' was the only possible operator that could be used due to the inherent grammar of C meaning that anything else would have introduced ambiguity.

    Doesn't make it any easier to use knowing that though.

    --Graham
  • On Thu, 5 Jul 2012 10:45:57 +1000, Graham Cox said:

    > I read recently that the '^' was the only possible operator that could
    > be used due to the inherent grammar of C meaning that anything else
    > would have introduced ambiguity.

    IIRC, the other reason was for Objective-C++.  I think ^ is one of the few operators that can't be overloaded in C++.

    --
    ____________________________________________________________
    Sean McBride, B. Eng                <sean...>
    Rogue Research                        www.rogue-research.com
    Mac Software Developer              Montréal, Québec, Canada
  • On Jul 5, 2012, at 9:40 AM, Sean McBride <sean...> wrote:
    > On Thu, 5 Jul 2012 10:45:57 +1000, Graham Cox said:
    >> I read recently that the '^' was the only possible operator that could
    >> be used due to the inherent grammar of C meaning that anything else
    >> would have introduced ambiguity.
    >
    > IIRC, the other reason was for Objective-C++.  I think ^ is one of the few operators that can't be overloaded in C++.

    In C and C++, ^ is a binary operator. Block objects would look like a unary ^, so there is no ambiguity.

    Note that C++ allows overloading of almost everything, including binary ^, but it doesn't allow creation of new operators like unary ^.

    --
    Greg Parker    <gparker...>    Runtime Wrangler
  • On 5 juil. 2012, at 02:45, Graham Cox <graham.cox...> wrote:

    > I read recently that the '^' was the only possible operator that could be used due to the inherent grammar of C meaning that anything else would have introduced ambiguity

    If I remember correctly, it has more to do with C++ overloading. ^ is not overloadable in C++, that was the unique such operator left.

    Vincent
  • On 9 Jul 2012, at 13:33, Vincent Habchi wrote:

    > On 5 juil. 2012, at 02:45, Graham Cox <graham.cox...> wrote:
    >
    >> I read recently that the '^' was the only possible operator that
    >> could be used due to the inherent grammar of C meaning that
    >> anything else would have introduced ambiguity
    >
    > If I remember correctly, it has more to do with C++ overloading. ^
    > is not overloadable in C++, that was the unique such operator left.
    >
    > Vincent

    I just *knew* it *had* to be something to do with C++ Voodoo! I've
    never gotten on with it and now it's managed to infect me!

    Dave
  • Le 5 juil. 2012 à 20:23, Greg Parker <gparker...> a écrit :

    > Note that C++ allows overloading of almost everything, including binary ^, but it doesn't allow creation of new operators like unary ^.

    Thanks Greg for that precision.

    Vincent
previous month july 2012 next month
MTWTFSS
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
Go to today