objc++ enhancements for new c++ features

classic Classic list List threaded Threaded
42 messages Options
123
Reply | Threaded
Open this post in threaded view
|

objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev

It was recommended to post this message on the clang list rather than the llvm list where it originally appeared...





Is there interest in enhancing the objc++ compiler to make objc mechanisms friendly to the newer features of c++? For instance...

1) making blocks movable so that they can capture things like unique_ptr<> and still be moved off the stack 
2) making @property declarations work with move-only types like unique_ptr<>
3) enabling std::weak_ptr<> to weakly store an objc pointer under ARC.  (see radar: 31177975)
4) add a mechanism to allow template metaprogramming to make full use of selectors. (see radar: 30812297)

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev
On 20 Mar 2018, at 17:52, James Gregurich via cfe-dev <[hidden email]> wrote:
>
> It was recommended to post this message on the clang list rather than the llvm list where it originally appeared...
>
>
>
>
> Is there interest in enhancing the objc++ compiler to make objc mechanisms friendly to the newer features of c++? For instance...
>
> 1) making blocks movable so that they can capture things like unique_ptr<> and still be moved off the stack

This should be relatively simple.  Although the interface is a copy, it is effectively a move operation (it either increments a reference count or modifies the source to use forwarding pointers).  I don’t see why blocks in C++11 or later shouldn’t always use move constructors for __block-qualified variables where available.

> 2) making @property declarations work with move-only types like unique_ptr<>

This shouldn’t be too hard: the compiler already synthesises property setters and getters, though it’s not quite clear what these would look like.  I believe that currently all C++ properties are exposed via copies and take a reference in the set method.  Would you want this to implicitly take an r-value reference for anything that’s only move constructable, or would you add an extra ‘move’ attribute to the property to enforce the fact that it takes an r-value reference?

There’s the related issue that NSInvocation is dangerously broken with move-only types (and anything that has a nontrivial copy constructor), because there’s no way of forcing the objects to be correctly copied.  It would be nice if each selector came with a move helper for its arg frame, but doing that in a way that doesn’t massively bloat the binary size is nontrivial.

> 3) enabling std::weak_ptr<> to weakly store an objc pointer under ARC.  (see radar: 31177975)

I’m not sure what this would look like.  Currently, you create std::weak_ptr from std::shared_ptr.  Presumably you’d want to specialise std::shared_ptr for id and have it just be a bare pointer that called the ARC functions on copy / move, then implement the corresponding std::weak_ptr specialisation do the same thing with a __weak id.

I seem to recall that we also need some type traits for ObjC objects so that you can implement a specialisation for any ObjC object type, but not for non-object types.

> 4) add a mechanism to allow template metaprogramming to make full use of selectors. (see radar: 30812297)

This would be a nice feature, but it’s not clear what it would look like in the language.  You can make a selector a template parameter already, but what would the application look like?

David

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev


> On Mar 20, 2018, at 1:09 PM, David Chisnall <[hidden email]> wrote:
>>
>> 1) making blocks movable so that they can capture things like unique_ptr<> and still be moved off the stack
>
> This should be relatively simple.  Although the interface is a copy, it is effectively a move operation (it either increments a reference count or modifies the source to use forwarding pointers).  I don’t see why blocks in C++11 or later shouldn’t always use move constructors for __block-qualified variables where available.

What would need to happen to push the concept forward?


>
>> 2) making @property declarations work with move-only types like unique_ptr<>
>
> This shouldn’t be too hard: the compiler already synthesises property setters and getters, though it’s not quite clear what these would look like.  I believe that currently all C++ properties are exposed via copies and take a reference in the set method.  Would you want this to implicitly take an r-value reference for anything that’s only move constructable, or would you add an extra ‘move’ attribute to the property to enforce the fact that it takes an r-value reference?

I woud say add an extra attribute to instruct the setter to take the r-value reference instead of the l-value reference. This would give the developer control over what he wants. Is there a way to express both in a single property declaration?...that the compiler should generate implementations for both & and &&?


> There’s the related issue that NSInvocation is dangerously broken with move-only types (and anything that has a nontrivial copy constructor), because there’s no way of forcing the objects to be correctly copied.  It would be nice if each selector came with a move helper for its arg frame, but doing that in a way that doesn’t massively bloat the binary size is nontrivial.

from the sounds of it, the situation would not be made worse.

>
>> 3) enabling std::weak_ptr<> to weakly store an objc pointer under ARC.  (see radar: 31177975)
>
> I’m not sure what this would look like.  Currently, you create std::weak_ptr from std::shared_ptr.  Presumably you’d want to specialise std::shared_ptr for id and have it just be a bare pointer that called the ARC functions on copy / move, then implement the corresponding std::weak_ptr specialisation do the same thing with a __weak id.

the weak_ptr template needs to have a '__unsafe_unretained' added to the __ptr_ data member in the case where it is included in an objc++ compilation unit and ARC is enabled. ARC causes the weak_ptr<> template to strongly retain the pointer which defeats the purpose of the template. We have a codebase which is built both with and without ARC. we use smart pointers to guard the objc pointers. I had to do some standing on my head to make our shared/weak pointer code work correctly when ARC is enabled. It would be nice if it worked correctly out of the box. It would appear that the __enable_weak_this() problem has been fixed in shared_ptr in the most recent xcode available.



>
> I seem to recall that we also need some type traits for ObjC objects so that you can implement a specialisation for any ObjC object type, but not for non-object types.
>
>> 4) add a mechanism to allow template metaprogramming to make full use of selectors. (see radar: 30812297)
>
> This would be a nice feature, but it’s not clear what it would look like in the language.  You can make a selector a template parameter already, but what would the application look like?

the link shows the idea I proposed in the radar report.


https://gist.github.com/bayoubengal/e4877efd84b32fb48b4fb00fb1e4a5c9

I'm not married to that specific idea. I think is an interesting way to generate something functional in the c++ sense from a selector....but other may have a better idea.


>  You can make a selector a template parameter already,


you mean an @selector value? or a selector as expressed in code? If you mean the latter, how do you set that set that up?








_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev
On 20 Mar 2018, at 20:06, James Gregurich <[hidden email]> wrote:

>
>
>
>> On Mar 20, 2018, at 1:09 PM, David Chisnall <[hidden email]> wrote:
>>>
>>> 1) making blocks movable so that they can capture things like unique_ptr<> and still be moved off the stack
>>
>> This should be relatively simple.  Although the interface is a copy, it is effectively a move operation (it either increments a reference count or modifies the source to use forwarding pointers).  I don’t see why blocks in C++11 or later shouldn’t always use move constructors for __block-qualified variables where available.
>
> What would need to happen to push the concept forward?

Someone to actually do the work.

>>> 2) making @property declarations work with move-only types like unique_ptr<>
>>
>> This shouldn’t be too hard: the compiler already synthesises property setters and getters, though it’s not quite clear what these would look like.  I believe that currently all C++ properties are exposed via copies and take a reference in the set method.  Would you want this to implicitly take an r-value reference for anything that’s only move constructable, or would you add an extra ‘move’ attribute to the property to enforce the fact that it takes an r-value reference?
>
> I woud say add an extra attribute to instruct the setter to take the r-value reference instead of the l-value reference. This would give the developer control over what he wants. Is there a way to express both in a single property declaration?...that the compiler should generate implementations for both & and &&?

Objective-C methods don’t support overloading (with Apple runtimes, at least), so you’d need to generate only one.

> There’s the related issue that NSInvocation is dangerously broken with move-only types (and anything that has a nontrivial copy constructor), because there’s no way of forcing the objects to be correctly copied.  It would be nice if each selector came with a move helper for its arg frame, but doing that in a way that doesn’t massively bloat the binary size is nontrivial.
>
> from the sounds of it, the situation would not be made worse.
>
>>
>>> 3) enabling std::weak_ptr<> to weakly store an objc pointer under ARC.  (see radar: 31177975)
>>
>> I’m not sure what this would look like.  Currently, you create std::weak_ptr from std::shared_ptr.  Presumably you’d want to specialise std::shared_ptr for id and have it just be a bare pointer that called the ARC functions on copy / move, then implement the corresponding std::weak_ptr specialisation do the same thing with a __weak id.
>
> the weak_ptr template needs to have a '__unsafe_unretained' added to the __ptr_ data member in the case where it is included in an objc++ compilation unit and ARC is enabled. ARC causes the weak_ptr<> template to strongly retain the pointer which defeats the purpose of the template. We have a codebase which is built both with and without ARC. we use smart pointers to guard the objc pointers. I had to do some standing on my head to make our shared/weak pointer code work correctly when ARC is enabled. It would be nice if it worked correctly out of the box. It would appear that the __enable_weak_this() problem has been fixed in shared_ptr in the most recent xcode available.

Why do you use std:: pointers for this?  Before ARC existed, I created a C++ smart pointer class that just called retain / release.  When ARC was introduced, I extended it to use the same functions that ARC uses, so you can use ARC-like smart pointers in a non-ARC codebase.  Is there a reason why you need these to be std::shared / weak pointers, which imply some different semantics?

>> I seem to recall that we also need some type traits for ObjC objects so that you can implement a specialisation for any ObjC object type, but not for non-object types.
>>
>>> 4) add a mechanism to allow template metaprogramming to make full use of selectors. (see radar: 30812297)
>>
>> This would be a nice feature, but it’s not clear what it would look like in the language.  You can make a selector a template parameter already, but what would the application look like?
>
> the link shows the idea I proposed in the radar report.
>
>
> https://gist.github.com/bayoubengal/e4877efd84b32fb48b4fb00fb1e4a5c9
>
> I'm not married to that specific idea. I think is an interesting way to generate something functional in the c++ sense from a selector....but other may have a better idea.

There isn’t enough information in that gist for me to understand what the desired behaviour is.

>> You can make a selector a template parameter already,
>
>
> you mean an @selector value? or a selector as expressed in code? If you mean the latter, how do you set that set that up?

A SEL typed parameter.

David

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev


On Mar 20, 2018, at 3:46 PM, David Chisnall <[hidden email]> wrote:

On 20 Mar 2018, at 20:06, James Gregurich <[hidden email]> wrote:



On Mar 20, 2018, at 1:09 PM, David Chisnall <[hidden email]> wrote:

1) making blocks movable so that they can capture things like unique_ptr<> and still be moved off the stack 

This should be relatively simple.  Although the interface is a copy, it is effectively a move operation (it either increments a reference count or modifies the source to use forwarding pointers).  I don’t see why blocks in C++11 or later shouldn’t always use move constructors for __block-qualified variables where available.

What would need to happen to push the concept forward?

Someone to actually do the work.

I could do it with some hand holding. I have no experience with compiler development or the clang codebase, but pointed in the right direction, I could figure it out.


Objective-C methods don’t support overloading (with Apple runtimes, at least), so you’d need to generate only one.

which is the answer I expected. One could still manually implement the other if needed.


Why do you use std:: pointers for this?  Before ARC existed, I created a C++ smart pointer class that just called retain / release. When ARC was introduced, I extended it to use the same functions that ARC uses, so you can use ARC-like smart pointers in a non-ARC codebase.  Is there a reason why you need these to be std::shared / weak pointers, which imply some different semantics?

why roll my own when I can use the standard ones? they work perfectly fine with custom deallocators to call [release] in the non-arc case.

you can't do threading-friendly weak pointers without ARC using only retain/release. Why write some new mechanism when the standard one works fine and makes for wonderfully maintainable code? The only issue remaining is making weak_ptr<> a little smarter to handle ARC correctly.




https://gist.github.com/bayoubengal/e4877efd84b32fb48b4fb00fb1e4a5c9

There isn’t enough information in that gist for me to understand what the desired behaviour is.


the idea is to change the compiler to handle the following syntax:


auto tmpCalcuStringLmbda = @lambda( -[cMyClass calculateStringValue:withNumber:]  );


the compiler would automatically generate the following code:


   auto tmpCalcuStringLmbda = [](cMyClass* theObjPtr, NSString* theValue1Ptr, size_t theValue)
   {
      return [theObjPtr calculateStringValue: theValue1Ptr withNumber: theValue];
   };


in essence, the compiler would create a lambda whose signature matches the signature of the selector declaration.  calling the lambda calls the selector passing in the arguments.

once you have a lambda declared, that could be passed to template machinery in the usual way.



A SEL typed parameter.


that isn't a convenient mechanism as the template machinery has no way to deduce the signature of the method. you end up have to manually cast the IMP. having the compiler handle the type checking on the invocation would be much preferable.








_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev


On Mar 20, 2018, at 14:08, James Gregurich via cfe-dev <[hidden email]> wrote:



On Mar 20, 2018, at 3:46 PM, David Chisnall <[hidden email]> wrote:

On 20 Mar 2018, at 20:06, James Gregurich <[hidden email]> wrote:



On Mar 20, 2018, at 1:09 PM, David Chisnall <[hidden email]> wrote:

1) making blocks movable so that they can capture things like unique_ptr<> and still be moved off the stack 

This should be relatively simple.  Although the interface is a copy, it is effectively a move operation (it either increments a reference count or modifies the source to use forwarding pointers).  I don’t see why blocks in C++11 or later shouldn’t always use move constructors for __block-qualified variables where available.

What would need to happen to push the concept forward?

Someone to actually do the work.

I could do it with some hand holding. I have no experience with compiler development or the clang codebase, but pointed in the right direction, I could figure it out.

Thanks for getting involved – if you add me to any reviews, I can help you find appropriate reviewers at Apple.

Objective-C methods don’t support overloading (with Apple runtimes, at least), so you’d need to generate only one.

which is the answer I expected. One could still manually implement the other if needed.


Why do you use std:: pointers for this?  Before ARC existed, I created a C++ smart pointer class that just called retain / release. When ARC was introduced, I extended it to use the same functions that ARC uses, so you can use ARC-like smart pointers in a non-ARC codebase.  Is there a reason why you need these to be std::shared / weak pointers, which imply some different semantics?

why roll my own when I can use the standard ones? they work perfectly fine with custom deallocators to call [release] in the non-arc case.

you can't do threading-friendly weak pointers without ARC using only retain/release. Why write some new mechanism when the standard one works fine and makes for wonderfully maintainable code? The only issue remaining is making weak_ptr<> a little smarter to handle ARC correctly.

I agree it would be great to get ARC-managed pointers working well in std::shared_ptr and std::weak_ptr.  The usual subtlety with templates is that __strong doesn't show up in C++ mangling, so it's not straightforward to avoid ODR violations when ARC and MRR translation units are linked together.  I think this is solvable, but I doubt it's trivial.

https://gist.github.com/bayoubengal/e4877efd84b32fb48b4fb00fb1e4a5c9

There isn’t enough information in that gist for me to understand what the desired behaviour is.


the idea is to change the compiler to handle the following syntax:


auto tmpCalcuStringLmbda = @lambda( -[cMyClass calculateStringValue:withNumber:]  );


the compiler would automatically generate the following code:


   auto tmpCalcuStringLmbda = [](cMyClass* theObjPtr, NSString* theValue1Ptr, size_t theValue)
   {
      return [theObjPtr calculateStringValue: theValue1Ptr withNumber: theValue];
   };


in essence, the compiler would create a lambda whose signature matches the signature of the selector declaration.  calling the lambda calls the selector passing in the arguments.

once you have a lambda declared, that could be passed to template machinery in the usual way.

I'm skeptical of inventing an ObjC++-specific terse lambda syntax.  I'm tempted to let C++ evolve/improve lambda syntax first.

A SEL typed parameter.


that isn't a convenient mechanism as the template machinery has no way to deduce the signature of the method. you end up have to manually cast the IMP. having the compiler handle the type checking on the invocation would be much preferable.







_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev

I agree it would be great to get ARC-managed pointers working well in std::shared_ptr and std::weak_ptr.  The usual subtlety with templates is that __strong doesn't show up in C++ mangling, so it's not straightforward to avoid ODR violations when ARC and MRR translation units are linked together.  I think this is solvable, but I doubt it's trivial.


I've come to the conclusion that mixing ARC and non-ARC c++ modules is not viable because of the ODR limitation. Its probably not worth the effort to make it viable. However, all-arc and all-non-arc are both perfectly viable. the use case is the situation where you have a big legacy codebase that will never be made ARC-compatible in its entirety but pieces of it need to work in an ARC process.


the memory header just needs to be changed like so...

template<class _Tp>
class _LIBCPP_TEMPLATE_VIS weak_ptr
{
public:
    typedef _Tp element_type;
private:



#if defined(__OBJC__) && __has_feature(objc_arc)
    element_type __unsafe_unretained * __ptr_;
#else
    element_type*        __ptr_;
#endif

    __shared_weak_count* __cntrl_;


I'm skeptical of inventing an ObjC++-specific terse lambda syntax.  I'm tempted to let C++ evolve/improve lambda syntax first.

There is no need for any new lambda syntax, and I don't propose any.  the compiler already automatically creates a block from standard lambda syntax in a .mm file...all that works great. What is needed is a directive to tell the compiler to generate a function that will invoke a method with a set of correctly typed arguments. basically...tell the compiler to create a lambda function that does a perfect forwarding to the objc method. once you have that, you can easily stuff a selector invocation inside a std::function or std::packaged_task in the usual manner.


something like this...

std::packaged_task< int (cTest*, NSString*)  >  tmpTask(   @lambda( -[cMyClass methodUsingString:] )   );
auto tmpCFuture = tmpTask.get_future();

auto tmpCPtr = [[[cTest alloc] init] autorelease];

tmpTask( tmpCPtr, @"hello world"  );

auto tmpResult = tmpCFuture.get();




The objc++ compiler works pretty well and is very thorough in integrating the objc world into the c++ world. there are just holes in its capabilities here and there that need to be filled.



_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev
On 21 Mar 2018, at 18:38, James Gregurich <[hidden email]> wrote:
>
>> I agree it would be great to get ARC-managed pointers working well in std::shared_ptr and std::weak_ptr.  The usual subtlety with templates is that __strong doesn't show up in C++ mangling, so it's not straightforward to avoid ODR violations when ARC and MRR translation units are linked together.  I think this is solvable, but I doubt it's trivial.
>
>
> I've come to the conclusion that mixing ARC and non-ARC c++ modules is not viable because of the ODR limitation. Its probably not worth the effort to make it viable. However, all-arc and all-non-arc are both perfectly viable. the use case is the situation where you have a big legacy codebase that will never be made ARC-compatible in its entirety but pieces of it need to work in an ARC process.

I believe that you are conflating ARC-language and ARC-library features.  You should be able to use an __unsafe_unretained pointer and directly call the underlying runtime library ARC functions.  This is what I have done in smart pointers in the past to use ARC with non-ARC-aware ObjC++ compilers.

David

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev


> On Mar 21, 2018, at 1:43 PM, David Chisnall <[hidden email]> wrote:
>
> I believe that you are conflating ARC-language and ARC-library features.  You should be able to use an __unsafe_unretained pointer and directly call the underlying runtime library ARC functions.  This is what I have done in smart pointers in the past to use ARC with non-ARC-aware ObjC++ compilers.
>

not sure why you mention that. its not really relevant to my point.
 
My only point to raising the whole issue is that std::weak_pointer<NSObject> should do the right thing out of the box even if ARC is enabled. Currently..based on the last time I did experimentation...it strongly retains under ARC  and there was no way I could find to externally coerce std::weak_ptr<NSObject> to behave as a weak reference.

The STL weak_ptr template needs to be adjusted to work correctly with objc pointers when ARC is enabled.



_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev


> On Mar 21, 2018, at 2:52 PM, James Gregurich via cfe-dev <[hidden email]> wrote:
>
>
>
>> On Mar 21, 2018, at 1:43 PM, David Chisnall <[hidden email]> wrote:
>>
>> I believe that you are conflating ARC-language and ARC-library features.  You should be able to use an __unsafe_unretained pointer and directly call the underlying runtime library ARC functions.  This is what I have done in smart pointers in the past to use ARC with non-ARC-aware ObjC++ compilers.
>>
>
> not sure why you mention that. its not really relevant to my point.
>
> My only point to raising the whole issue is that std::weak_pointer<NSObject> should do the right thing out of the box even if ARC is enabled. Currently..based on the last time I did experimentation...it strongly retains under ARC  and there was no way I could find to externally coerce std::weak_ptr<NSObject> to behave as a weak reference.
>
> The STL weak_ptr template needs to be adjusted to work correctly with objc pointers when ARC is enabled.

I think this is just a misunderstanding of what std::weak_ptr is supposed to do.  std::weak_ptr is a defined part of the std::shared_ptr system.  I would be very surprised if std::shared_ptr<NSObject> actually worked in any sensible way; if it does, it works by adding an extra level of indirection, more or less by accident.  I do not think it would be appropriate to try to special-case these templates so that they transparently just created ARC strong/weak references; I doubt that such a solution would really conform to the standard.

John.
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev
In reply to this post by Manuel Klimek via cfe-dev


On Mar 20, 2018, at 2:09 PM, David Chisnall via cfe-dev <[hidden email]> wrote:

On 20 Mar 2018, at 17:52, James Gregurich via cfe-dev <[hidden email]> wrote:

It was recommended to post this message on the clang list rather than the llvm list where it originally appeared...




Is there interest in enhancing the objc++ compiler to make objc mechanisms friendly to the newer features of c++? For instance...

1) making blocks movable so that they can capture things like unique_ptr<> and still be moved off the stack

This should be relatively simple.  Although the interface is a copy, it is effectively a move operation (it either increments a reference count or modifies the source to use forwarding pointers).  I don’t see why blocks in C++11 or later shouldn’t always use move constructors for __block-qualified variables where available.

We already use the move constructor when moving the contents of __block variables to the heap.

I believe James is referring to a non-__block capture of move-only type.  For that, we run into two very similar problems:
  - We have no way of guaranteeing that a stack block will be abandoned after it is copied to the heap; there is no forwarding mechanism for block objects.
  - We have no way of guaranteeing that the original variable will be abandoned after it is captured in the block; there is no "capture-by-move" for block captures.

I don't know how to solve either of these problems without major extensions to the current language design of blocks.  Fortunately, __block captures exist; they're not perfectly efficient, but they exist.

2) making @property declarations work with move-only types like unique_ptr<>

This shouldn’t be too hard: the compiler already synthesises property setters and getters, though it’s not quite clear what these would look like.  I believe that currently all C++ properties are exposed via copies and take a reference in the set method.  Would you want this to implicitly take an r-value reference for anything that’s only move constructable, or would you add an extra ‘move’ attribute to the property to enforce the fact that it takes an r-value reference?

I think we actually take the parameter as a pr-value, which in some ways is better because it means that you can pass something either by copy or by move.  I don't know if we then try to move-assign the ivar from the parameter, but we certainly should.

I think the more interesting question is the type of the getter.  The getter really can't return a && or pr-value.  Do we recognize that a type is move-only and just make the getter return a `const &`?  Does that mean we forbid synthesizing such a property as atomic?

There’s the related issue that NSInvocation is dangerously broken with move-only types (and anything that has a nontrivial copy constructor), because there’s no way of forcing the objects to be correctly copied.  It would be nice if each selector came with a move helper for its arg frame, but doing that in a way that doesn’t massively bloat the binary size is nontrivial.

3) enabling std::weak_ptr<> to weakly store an objc pointer under ARC.  (see radar: 31177975)

I’m not sure what this would look like.  Currently, you create std::weak_ptr from std::shared_ptr.  Presumably you’d want to specialise std::shared_ptr for id and have it just be a bare pointer that called the ARC functions on copy / move, then implement the corresponding std::weak_ptr specialisation do the same thing with a __weak id.

I seem to recall that we also need some type traits for ObjC objects so that you can implement a specialisation for any ObjC object type, but not for non-object types.

4) add a mechanism to allow template metaprogramming to make full use of selectors. (see radar: 30812297)

This would be a nice feature, but it’s not clear what it would look like in the language.  You can make a selector a template parameter already, but what would the application look like?

And what would the rules be for type-checking such an application?  If we're talking about C++ interactions here, we can't very well pretend that the parameters and return value are all going to be `id`.  (I wouldn't want to add new dependencies on that behavior anyway, even in pure Objective-C.)

Also, you can't actually make a selector a template argument today.  You can use SEL as the type of a template parameter, but it's basically useless because @selector is not a constant expression.

Now, there's an idea we've been kicking around for a long time to support typed selectors; I guess they would look something like
  SEL<NSString*()>
for the type of
  - (NSString*) foo;

Note that that argument is just a function type, and that it's not the actual type of an IMP because both `self` and `_cmd` are implicit.  That's an interesting thing to discuss.  You could make an argument that `self` should be explicit, so that you could say "this is a selector that only works on object arguments of a certain type".  That would be more type-safe, but I would worry about it making it more awkward to use this for the sorts of dynamic features that people use untyped selectors for today.  Maybe it'd be fine as long as you could convert `SEL<void(NSCell*)>` to `SEL<void(id)>`.

Anyway, since it's an ordinary function type, it can carry attributes like NS_RETURNS_RETAINED and NS_CONSUMED because we already taught the type system about those for ARC.  (It can't express the behavior of -init methods unless `self` is an explicit parameter, though.)

I think the application syntax is pretty obvious: you would just call the selector as if it were a C function, with the first argument being the receiver, and the compiler would automatically call the right objc_msgSend variant for the type.

You'd need some way of constructing one of these, probably by referring to an existing method.  Maybe that could be @selector(-Foo.bar) or something.

Anyway, if you had that, you could then add special template support for them.

John.

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev
In reply to this post by Manuel Klimek via cfe-dev

>
> I think this is just a misunderstanding of what std::weak_ptr is supposed to do.  std::weak_ptr is a defined part of the std::shared_ptr system.  I would be very surprised if std::shared_ptr<NSObject> actually worked in any sensible way; if it does, it works by adding an extra level of indirection, more or less by accident.  I do not think it would be appropriate to try to special-case these templates so that they transparently just created ARC strong/weak references; I doubt that such a solution would really conform to the standard.
>
> John.

Actually, I have this mechanism running in production in a live-tv environment where a crash could mean the stage goes dark in front of millions of tv viewers or the lights go out on the Superbowl halftime show. Crashes are not an option in such a circumstance. Using this mechanism, I've tracked down and eradicated a large number of long-standing memory leaks and core animation misbehaviors that caused problems in production. It is a high-quality solution to the pitfalls inherent in the objc retain/release/autorelease design pattern.  

The system runs well and allows me to have a codebase that works correctly under ARC or non-ARC with no awful macro-checking injected in the code.  I just had to jury rig a way to work around the remaining limitation of std::weak_ptr<>....which I am currently advocating to fix. You'll note that I've previously reported a bug in ARC (radar 31170126) which was fixed by Apple  that caused shared_ptr<> to misbehave and crash. If I remember correctly, when I did that analysis, the shared_ptr<> templated retains twice...once in shared_ptr itself and once more in the internals of the retain counting mechanism...which based on my reading of the ARC docs is exactly what it should do. yes, it does do an extra retain/release, but who cares. When you are utilizing the shared_ptr in such a manner, it is typically for a use where the extra retain and release has no real-world impact...such as sharing an objc object with a task to be passed off to a dispatch queue.  in the non-arc case, typically, you alloc/init a class instance and pass it off to shared_pointer...just as you would do with any raw pointer. on shared_ptr destruction, [release] is called. there is no unnecessary labor involved.  ok...there is an extra counter for a retain count built into the objc object...again one doesn't typically use shared_ptr in places where that extra cost has any real-world impact. I also note that if once is concerned about keeping a class size to an absolute minimum,  he'd be better off using a c++ class that imposed NO extra overhead rather than an objc class.


I'm not sure how any of this has relevance to the standard. The change I am advocating will allow a raw pointer (objc in this case) to be stored weakly in the weak_ptr instance...which is exactly what the weak_ptr is supposed to do.  Currently, the weak_ptr strongly retains by the rules of ARC because it is storing the objc pointer in a data member of a class.


Note that the system works correctly out of the box when ARC is off. Even if there is disagreement over the utility of the mechanism, I content that the mechanism should work correctly out of the box regardless of the state of ARC.






_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev


> On Mar 28, 2018, at 4:07 PM, James Gregurich <[hidden email]> wrote:
>
>
>>
>> I think this is just a misunderstanding of what std::weak_ptr is supposed to do.  std::weak_ptr is a defined part of the std::shared_ptr system.  I would be very surprised if std::shared_ptr<NSObject> actually worked in any sensible way; if it does, it works by adding an extra level of indirection, more or less by accident.  I do not think it would be appropriate to try to special-case these templates so that they transparently just created ARC strong/weak references; I doubt that such a solution would really conform to the standard.
>>
>> John.
>
> Actually, I have this mechanism running in production in a live-tv environment where a crash could mean the stage goes dark in front of millions of tv viewers or the lights go out on the Superbowl halftime show. Crashes are not an option in such a circumstance. Using this mechanism, I've tracked down and eradicated a large number of long-standing memory leaks and core animation misbehaviors that caused problems in production. It is a high-quality solution to the pitfalls inherent in the objc retain/release/autorelease design pattern.  
>
> The system runs well and allows me to have a codebase that works correctly under ARC or non-ARC with no awful macro-checking injected in the code.  I just had to jury rig a way to work around the remaining limitation of std::weak_ptr<>....which I am currently advocating to fix. You'll note that I've previously reported a bug in ARC (radar 31170126) which was fixed by Apple  that caused shared_ptr<> to misbehave and crash. If I remember correctly, when I did that analysis, the shared_ptr<> templated retains twice...once in shared_ptr itself and once more in the internals of the retain counting mechanism...which based on my reading of the ARC docs is exactly what it should do. yes, it does do an extra retain/release, but who cares. When you are utilizing the shared_ptr in such a manner, it is typically for a use where the extra retain and release has no real-world impact...such as sharing an objc object with a task to be passed off to a dispatch queue.  in the non-arc case, typically, you alloc/init a class instance and pass it off to shared_pointer...just as you would do with any raw pointer. on shared_ptr destruction, [release] is called. there is no unnecessary labor involved.  ok...there is an extra counter for a retain count built into the objc object...again one doesn't typically use shared_ptr in places where that extra cost has any real-world impact. I also note that if once is concerned about keeping a class size to an absolute minimum,  he'd be better off using a c++ class that imposed NO extra overhead rather than an objc class.

I absolutely understand the benefits of having smart pointer types that automatically manage your retains and releases.  I'm not arguing that you shoudn't use smart pointers.  I don't know why you specifically want to call your smart pointers std::shared_ptr and std::weak_ptr, though, because you are just creating problems for yourself.

> I'm not sure how any of this has relevance to the standard. The change I am advocating will allow a raw pointer (objc in this case) to be stored weakly in the weak_ptr instance...which is exactly what the weak_ptr is supposed to do.  Currently, the weak_ptr strongly retains by the rules of ARC because it is storing the objc pointer in a data member of a class.
>
>
> Note that the system works correctly out of the box when ARC is off. Even if there is disagreement over the utility of the mechanism, I content that the mechanism should work correctly out of the box regardless of the state of ARC.

This would be adding some pretty unusual non-orthogonality in an attempt to make std::shared_ptr and std::weak_ptr do things they're not meant to do, which is transparently interoperate with a completely foreign shared-reference system.

John.
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev
In reply to this post by Manuel Klimek via cfe-dev


On Mar 28, 2018, at 3:07 PM, John McCall <[hidden email]> wrote:

We already use the move constructor when moving the contents of __block variables to the heap.

I believe James is referring to a non-__block capture of move-only type.  For that, we run into two very similar problems:
  - We have no way of guaranteeing that a stack block will be abandoned after it is copied to the heap; there is no forwarding mechanism for block objects.
  - We have no way of guaranteeing that the original variable will be abandoned after it is captured in the block; there is no "capture-by-move" for block captures.


below is an example of what I'd like to see made workable to make the c++ experience more convenient. Currently, this code won't compile because the block is move-only due to the capture of a move-only class. For capturing c++ variables to be viable in the first place, you already have to have some mechanism in the blocks runtime that invoke copy constructors of the captured classes. Why is it that much of a leap to make it perform a move on a move-only block?...suck the guts out of the stack instance of the block in the usual c++ sense...leave it empty but valid state?


class cTest3
{
   public:
   void f()
   {
      NSLog(@"cTest3");
   }

   

};

...

   auto tmp1 = std::make_unique<cTest3>();

   

   dispatch_async(dispatch_get_main_queue(), [cap1 = std::move(tmp1)] mutable
   {
      cap1->f();
   });

   


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev
In reply to this post by Manuel Klimek via cfe-dev


On Mar 28, 2018, at 3:21 PM, John McCall <[hidden email]> wrote:

I absolutely understand the benefits of having smart pointer types that automatically manage your retains and releases.  I'm not arguing that you shoudn't use smart pointers.  I don't know why you specifically want to call your smart pointers std::shared_ptr and std::weak_ptr, though, because you are just creating problems for yourself.


Why should one re-invent the wheel? the std classes work great in the non-arc mode.  Once the bug in ARC was fixed, shared_ptr worked exactly as it should with respect to ARC. weak_ptr would also work correctly too with a minor adjustment that should not affect anyone not using objc++ and ARC. Secondly, I'm not aware of any way that weak referencing smart pointer could be implemented only using retain, release and autorelease calls....which is useful in sharing resources across threads and dispatch tasks and allowing for asynchronous callbacks. You'd basically have to clone what shared_ptr and weak_ptr already do. 

BTW. my workaround that I mentioned functions by bridging the objc pointer to CFType and storing the CFTypeRef in the weak_ptr.  



This would be adding some pretty unusual non-orthogonality in an attempt to make std::shared_ptr and std::weak_ptr do things they're not meant to do, which is transparently interoperate with a completely foreign shared-reference system.

Please pardon my ignorance...I''m not a compiler/standard-lib developer....but why is the following proposed change (in blue assuming that gets through to email clients) considered "non-orthogonal" or "unusual"?  Its a very straightforward change that wouldn't affect anyone but people using objc++ with ARC and weak_ptr. Based on my experience in implementing a rather large, complex system based on the mechanism, it would be the only change necessary.



template<class _Tp>
class _LIBCPP_TEMPLATE_VIS weak_ptr
{
public:
    typedef _Tp element_type;
private:



#if defined(__clang__) && defined(__OBJC__) && __has_feature(objc_arc)
    element_type __unsafe_unretained * __ptr_;
#else

    element_type*        __ptr_;
#endif

    __shared_weak_count* __cntrl_;



I the end, the hook upon which I hang my hat is the argument that if a non-arc system is built on shared_ptr/weak_ptr, it should still work as expected once ARC is switched on...assuming it conforms to the rules laid out in the arc docs. 


-James

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev
In reply to this post by Manuel Klimek via cfe-dev


On Mar 28, 2018, at 3:07 PM, John McCall <[hidden email]> wrote:

Now, there's an idea we've been kicking around for a long time to support typed selectors; I guess they would look something like
  SEL<NSString*()>
for the type of
  - (NSString*) foo;


I'm not a stickler for exactly what gets done. My goal is to be able to write code like that below. I'm open to any idea that allows templating to utilize objc method declarations as easily as can utilize c++ class member function declarations. My end goal in posting to the list is to make the cocoa programming experience from c++ be as convenient and complete as possible. the objc++ compiler is one of the best pieces of software that Apple has engineered. The experience can be improved significantly by filling in a few gaps.




std::packaged_task< int (cTest*, NSString*)  >  tmpTask(   @lambda( -[cMyClass methodUsingString:] )   );
auto tmpCFuture = tmpTask.get_future();

auto tmpCPtr = [[[cTest alloc] init] autorelease];

tmpTask( tmpCPtr, @"hello world"  );

auto tmpResult = tmpCFuture.get();




_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev
In reply to this post by Manuel Klimek via cfe-dev


On Mar 28, 2018, at 3:07 PM, John McCall <[hidden email]> wrote:

I think we actually take the parameter as a pr-value, which in some ways is better because it means that you can pass something either by copy or by move.  I don't know if we then try to move-assign the ivar from the parameter, but we certainly should.

I think the more interesting question is the type of the getter.  The getter really can't return a && or pr-value.  Do we recognize that a type is move-only and just make the getter return a `const &`?  Does that mean we forbid synthesizing such a property as atomic?


Let me focus on issues I encounter that make @property problematic or inconvenient. perhaps I'm misusing the tool.


consider the code below.  What I want to be able to do is get a reference to the map instance variable and modify it. but the code doesn't compile because the property wants to return a  copy. 


@interface AppDelegate ()
@property (nonatomicassignstd::map<std::stringint> prop;
@end

@implementation AppDelegate
@synthesize prop;


- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
   autotmpP = self.prop;
   tmpP["test"] = 1;
}


@end


ok. so I try this... 


@property (nonatomic, assign) std::map<std::string, int>& prop;


but then I encounter the following that doesn't work...

self.prop = std::map<std::string, int>{{"test",1}, {"test2",2}};

and of course this doesn't compile...


@property (nonatomic, assign) std::map<std::string, int>&& prop;


The only answer I see here is to manually write the accessor functions and have an explicit instance variable declaration. I'd like to be able to use @property for convenience, but I see no way to make it work for what I naturally want.  is there an answer that isn't "don't use @property"?

-James






_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev


On Mar 28, 2018, at 5:15 PM, James Gregurich <[hidden email]> wrote:



On Mar 28, 2018, at 3:07 PM, John McCall <[hidden email]> wrote:

I think we actually take the parameter as a pr-value, which in some ways is better because it means that you can pass something either by copy or by move.  I don't know if we then try to move-assign the ivar from the parameter, but we certainly should.

I think the more interesting question is the type of the getter.  The getter really can't return a && or pr-value.  Do we recognize that a type is move-only and just make the getter return a `const &`?  Does that mean we forbid synthesizing such a property as atomic?


Let me focus on issues I encounter that make @property problematic or inconvenient. perhaps I'm misusing the tool.


consider the code below.  What I want to be able to do is get a reference to the map instance variable and modify it. but the code doesn't compile because the property wants to return a  copy. 


@interface AppDelegate ()
@property (nonatomicassignstd::map<std::stringint> prop;
@end

@implementation AppDelegate
@synthesize prop;


- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
   autotmpP = self.prop;
   tmpP["test"] = 1;
}


@end


ok. so I try this... 


@property (nonatomic, assign) std::map<std::string, int>& prop;


but then I encounter the following that doesn't work...

self.prop = std::map<std::string, int>{{"test",1}, {"test2",2}};

and of course this doesn't compile...


@property (nonatomic, assign) std::map<std::string, int>&& prop;


The only answer I see here is to manually write the accessor functions and have an explicit instance variable declaration. I'd like to be able to use @property for convenience, but I see no way to make it work for what I naturally want.  is there an answer that isn't "don't use @property"?

I think this is a pretty poor match for @property, yes.

John.

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev
In reply to this post by Manuel Klimek via cfe-dev


On Mar 28, 2018, at 4:27 PM, James Gregurich <[hidden email]> wrote:



On Mar 28, 2018, at 3:07 PM, John McCall <[hidden email]> wrote:

We already use the move constructor when moving the contents of __block variables to the heap.

I believe James is referring to a non-__block capture of move-only type.  For that, we run into two very similar problems:
  - We have no way of guaranteeing that a stack block will be abandoned after it is copied to the heap; there is no forwarding mechanism for block objects.
  - We have no way of guaranteeing that the original variable will be abandoned after it is captured in the block; there is no "capture-by-move" for block captures.


below is an example of what I'd like to see made workable to make the c++ experience more convenient. Currently, this code won't compile because the block is move-only due to the capture of a move-only class. For capturing c++ variables to be viable in the first place, you already have to have some mechanism in the blocks runtime that invoke copy constructors of the captured classes. Why is it that much of a leap to make it perform a move on a move-only block?...suck the guts out of the stack instance of the block in the usual c++ sense...leave it empty but valid state?

There is no existing concept of a move-only block.  That is just not how blocks work.

Just add __block to the declaration of tmp1.

John.



class cTest3
{
   public:
   void f()
   {
      NSLog(@"cTest3");
   }
   
};

...

   auto tmp1 = std::make_unique<cTest3>();
   
   dispatch_async(dispatch_get_main_queue(), [cap1 = std::move(tmp1)] mutable
   {
      cap1->f();
   });
   


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: objc++ enhancements for new c++ features

Manuel Klimek via cfe-dev
In reply to this post by Manuel Klimek via cfe-dev


On Mar 28, 2018, at 4:48 PM, James Gregurich <[hidden email]> wrote:



On Mar 28, 2018, at 3:21 PM, John McCall <[hidden email]> wrote:

I absolutely understand the benefits of having smart pointer types that automatically manage your retains and releases.  I'm not arguing that you shoudn't use smart pointers.  I don't know why you specifically want to call your smart pointers std::shared_ptr and std::weak_ptr, though, because you are just creating problems for yourself.


Why should one re-invent the wheel? the std classes work great in the non-arc mode.

I don't understand how.  In non-ARC mode, std::shared_ptr will not retain the value it holds or release it when the shared_ptr is destroyed.  It will *compile*, of course, and probably run fine in many cases because of the autorelease pool.

 Once the bug in ARC was fixed, shared_ptr worked exactly as it should with respect to ARC. weak_ptr would also work correctly too with a minor adjustment that should not affect anyone not using objc++ and ARC. Secondly, I'm not aware of any way that weak referencing smart pointer could be implemented only using retain, release and autorelease calls....which is useful in sharing resources across threads and dispatch tasks and allowing for asynchronous callbacks. You'd basically have to clone what shared_ptr and weak_ptr already do. 

BTW. my workaround that I mentioned functions by bridging the objc pointer to CFType and storing the CFTypeRef in the weak_ptr.  



This would be adding some pretty unusual non-orthogonality in an attempt to make std::shared_ptr and std::weak_ptr do things they're not meant to do, which is transparently interoperate with a completely foreign shared-reference system.

Please pardon my ignorance...I''m not a compiler/standard-lib developer....but why is the following proposed change (in blue assuming that gets through to email clients) considered "non-orthogonal" or "unusual"?  Its a very straightforward change that wouldn't affect anyone but people using objc++ with ARC and weak_ptr. Based on my experience in implementing a rather large, complex system based on the mechanism, it would be the only change necessary.



template<class _Tp>
class _LIBCPP_TEMPLATE_VIS weak_ptr
{
public:
    typedef _Tp element_type;
private:



#if defined(__clang__) && defined(__OBJC__) && __has_feature(objc_arc)
    element_type __unsafe_unretained * __ptr_;
#else

    element_type*        __ptr_;
#endif

    __shared_weak_count* __cntrl_;

This would break std::weak_ptr for all non-ObjC element types.

John.





I the end, the hook upon which I hang my hat is the argument that if a non-arc system is built on shared_ptr/weak_ptr, it should still work as expected once ARC is switched on...assuming it conforms to the rules laid out in the arc docs. 


-James


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
123