[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Which ObjC2.0 features are missing in the latest GCC?
From: |
H. Nikolaus Schaller |
Subject: |
Re: Which ObjC2.0 features are missing in the latest GCC? |
Date: |
Tue, 26 Nov 2019 15:06:29 +0100 |
> Am 26.11.2019 um 11:09 schrieb Pirmin Braun <pb@busw.de>:
>
> I'd suggest a fork, i.e. "Gnustep2" with LLVM, Clang, libobjc2
just came to my mind: ClangSTEP?
>
> On Tue, 26 Nov 2019 04:55:43 -0500
> Gregory Casamento <greg.casamento@gmail.com> wrote:
>
>> I'd really like some resolution on this topic. There seem to be a lot of
>> reasons for and against.
>>
>> GC
>>
>> On Mon, Nov 25, 2019 at 1:04 PM David Chisnall <gnustep@theravensnest.org>
>> wrote:
>>
>>> On 25 Nov 2019, at 14:07, H. Nikolaus Schaller <hns@goldelico.com> wrote:
>>>> I am not sure that this is the only way to implement it.
>>>>
>>>> First of all the callMethodOn returns some block which is a data
>>> structure knowing that it should take the parameter x and do some function.
>>>> Let's call it NSBlock. NSBlock can be an ordinary object like any other
>>> so that it can follow the same memory management rules as used otherwise.
>>>
>>> That’s shifting the goalposts somewhat. It is not news that objects and
>>> closures are equivalent. Smalltalk implemented blocks as BlockClosure
>>> objects, Ian Piumarta’s Composite Object-Lambda Architecture, and C++
>>> lambdas (which are just shorthand for C++ objects that implement
>>> `operator()`). You can always express anything that uses blocks with
>>> objects.
>>>
>>> There are two issues:
>>>
>>> 1. If you want to be compatible with existing APIs that use blocks, you
>>> need to be ABI compatible with blocks.
>>> 2. The reason that most languages that have objects also have blocks is
>>> that the shorthand syntax is very convenient.
>>>
>>> The following are roughly equivalent:
>>>
>>> ```
>>> @interface Delegate : NSObject
>>> - (void)invoke;
>>> - (instancetype)initWithCapture: (id)someObject;
>>> @end
>>>
>>> @implementation Delegate
>>> {
>>> @private
>>> id obj;
>>> }
>>> - (instancetype)initWithCapture: (id)someObject
>>> {
>>> if ((self = [super init]) == nil) return nil;
>>> obj = [someObject retain];
>>> return self;
>>> }
>>> - (void)invoke
>>> {
>>> [obj doSomething];
>>> }
>>> - (void)dealloc
>>> {
>>> [obj release];
>>> [super dealloc];
>>> }
>>> @end
>>>
>>> // At construction site:
>>>
>>> [[Delegate alloc] initWithCapture: x];
>>>
>>> // At use site:
>>>
>>> [delegate invoke];
>>> ```
>>>
>>> And this, with blocks:
>>>
>>> ```
>>> // At construction site:
>>>
>>> ^() { [x doSomething]; };
>>>
>>> // At use site:
>>>
>>> delegate();
>>> ```
>>>
>>> At use, these are similar complexity for the programmer. At the point of
>>> construction, one is one line of code (two or three if you put lambda
>>> bodies on their own lines), the other is 26. As a programmer, I don’t want
>>> to write 26 lines of code for a one-line callback.
>>>
>>> In C++98 you could probably template that and provide a generic class that
>>> took a struct containing the captures and a C function, so you’d get a lot
>>> less boilerplate. Assuming you had fudged ARC like this (as above, this
>>> code is typed into a mail client and probably doesn’t compile):
>>>
>>> ```
>>> template<typename T>
>>> struct ObjCObjectWrapper
>>> {
>>> ObjCObjectWrapper(T x) : obj(objc_retain(x)) {}
>>> ObjCObjectWrapper(const ObjCObjectWrapper &other) :
>>> obj(objc_retain(other.obj) {}
>>> ObjCObjectWrapper(ObjCObjectWrapper &&other) : obj(other.obj)
>>> {
>>> other.obj = nil;
>>> }
>>> ObjCObjectWrapper()
>>> {
>>> objc_release(obj);
>>> }
>>> operator=(T x)
>>> {
>>> objc_storeStrong(&obj, x);
>>> }
>>> T operator()
>>> {
>>> return obj;
>>> }
>>> private:
>>> T obj;
>>>
>>> };
>>> ```
>>>
>>> You could then define a generic capture structure and invoke method like
>>> this:
>>>
>>> ```
>>> template<typename Capture, typename Ret, typename... Args>
>>> struct BlockImpl
>>> {
>>> using invoke_t = Ret(*)(Capture &, Args...);
>>> void operator()(Args... args)
>>> {
>>> inv(capture, std::forward<Args>(args)…);
>>> }
>>> Block(Capture &&c, invoke_t fn) : capture(c), inv(fn) {}
>>> private:
>>> Capture capture;
>>> invoke_t inv;
>>> };
>>> ```
>>>
>>> This is then generic and you could use it as follows:
>>>
>>> ```
>>> struct CaptureOneObject
>>> {
>>> ObjCObjectWrapper<id> o;
>>> };
>>> void invoke(CaptureOneObject &c)
>>> {
>>> [(id)c.o doSomething];
>>> }
>>> // At construction site:
>>> std::function<void(void)> block(BlockImpl<CaptureOneObject, void>({x},
>>> invoke));
>>> // At use site:
>>> block();
>>> ```
>>>
>>> I *think* you could get the same ABI as blocks if you worked on the
>>> generic templated boilerplate a bit.
>>>
>>> Of course, if you were using C++ then you could also write it using
>>> lambdas as:
>>>
>>> ```
>>> // At construction site
>>> ObjCObjectWrapper<id> capture(x);
>>> auto block = [=capture]() { [(id)capture.o doSomething]; };
>>> // At use site:
>>> block();
>>> ```
>>>
>>> And with this you don’t need the invoke function or the capture class.
>>> Again, much less boiler plate for users, though we don’t have ABI
>>> compatibility with blocks.
>>>
>>> If you were using ARC and C++, then this reduces even further to:
>>>
>>> ```
>>> auto block = [=]() { [x doSomething]; };
>>> ```
>>>
>>> And now we’re back with different syntax for the same thing, though with a
>>> different ABI (I think Clang has support for implicitly converting C++
>>> lambdas to blocks, but it’s been a few years since I tried)
>>>
>>> David
>>>
>>>
>>>
>>
>> --
>> Gregory Casamento
>> GNUstep Lead Developer / OLC, Principal Consultant
>> http://www.gnustep.org - http://heronsperch.blogspot.com
>> http://ind.ie/phoenix/
>
>
> --
> Pirmin Braun pb@pirmin-braun.de +49 261 92199400 +49 174 9747584
> Geschäftsführer der Pirmin Braun GmbH www.pirmin-braun.de
> Im Palmenstück 4 - 56072 Koblenz - www.facebook.com/PB.ERP.Software
> Registergericht: Koblenz HRB 26312 UStID: DE319238613 Steuernummer:
> 22/656/03918
- Re: Which ObjC2.0 features are missing in the latest GCC?, (continued)
- Re: Which ObjC2.0 features are missing in the latest GCC?, Gregory Casamento, 2019/11/25
- Re: Which ObjC2.0 features are missing in the latest GCC?, H. Nikolaus Schaller, 2019/11/25
- Re: Which ObjC2.0 features are missing in the latest GCC?, David Chisnall, 2019/11/25
- Re: Which ObjC2.0 features are missing in the latest GCC?, H. Nikolaus Schaller, 2019/11/25
- Re: Which ObjC2.0 features are missing in the latest GCC?, David Chisnall, 2019/11/25
- Re: Which ObjC2.0 features are missing in the latest GCC?, Gregory Casamento, 2019/11/26
- Re: Which ObjC2.0 features are missing in the latest GCC?, Max Chan, 2019/11/26
- Re: Which ObjC2.0 features are missing in the latest GCC?, Pirmin Braun, 2019/11/26
- Re: Which ObjC2.0 features are missing in the latest GCC?,
H. Nikolaus Schaller <=
- Re: Which ObjC2.0 features are missing in the latest GCC?, Andreas Fink, 2019/11/26
- Re: Which ObjC2.0 features are missing in the latest GCC?, Pirmin Braun, 2019/11/26
- Re: Which ObjC2.0 features are missing in the latest GCC?, Umberto Cerrato, 2019/11/26
- Re: Which ObjC2.0 features are missing in the latest GCC?, hasebastian, 2019/11/26
- libobjc2 build issue, Andreas Fink, 2019/11/26
- Re: libobjc2 build issue, Johannes Brakensiek, 2019/11/26
- Re: libobjc2 build issue, Fred Kiefer, 2019/11/26
- Re: libobjc2 build issue, Andreas Fink, 2019/11/26
- Re: libobjc2 build issue, Patryk Laurent, 2019/11/26
- Re: libobjc2 build issue, Andreas Fink, 2019/11/26