<p>Am 16.07.2014 14:13 schrieb "Jonas Maebe" <<a href="mailto:jonas.maebe@elis.ugent.be">jonas.maebe@elis.ugent.be</a>>:<br>
><br>
> Hi,<br>
><br>
> I've (locally, not yet in svn) implemented support for blocks in FPC ( <a href="http://en.wikipedia.org/wiki/Blocks_(C_language_extension)">http://en.wikipedia.org/wiki/Blocks_(C_language_extension)</a> ). Blocks are basically procedural variables with support for capturing local context in various ways. As implemented in C/C++/Objective-C, they also introduce the syntactic sugar of declaring them as inline code fragments (anonymous procdures), but I have not implemented this in FPC. Such functionality is completely orthogonal to the support for blocks, and can be added later if/when support for anonymous methods is added to FPC in general.</p>
<p>Woah O.o Didn't expect that ^^ Maybe some of this can be reused for anonymous methods support :)</p>
<p>> The way I've implemented it right now is that a block-type is declared like a regular procedure variable, followed by "is block". E.g.:<br>
><br>
> type<br>
> NSArrayEnumeratorBlock = procedure (obj: id; idx: NSUInteger; var stop: boolean) is block;</p>
<p>As I see below it's part of a modeswitch, right?</p>
<p>> Now, to the hard part. In case of global routines, the block does not capture any local state and everything works perfectly as it is. There is however not much point to using them this way, other than with library APIs that accept blocks rather than regular procedure variables (which forms an increasing part of the OS X/iOS system interface, so it is already useful by itself).<br>
><br>
> "Capturing local state" means that the block gets a copy or a reference to a variable that is local to the context where it is instantiated (instantiated in our case means "the place where we assign the address of a procedure/function to an "is block" variable). </p>
<p>Delphi is a bit confusing here: each anonymous function instantiated in a function shares a reference to a copy of the variable... :/ (at least if I remember correctly)</p>
<p>> However:<br>
><br>
> * Methods of Pascal classes<br>
><br>
> As explained above, the "self" parameter has to be captured by the block in this case. If nothing special is done, then this self pointer will be treated like a regular pointer and you will be responsible for freeing it. However, in case a block is passed to an asynchronous routine, the question will most likely be "when is it safe to free that instance", and I'm not sure how to do that. The blocks runtime supports adding code that will be executed when a block is copied and when it is freed, but since Pascal classes don't have an internal reference count, there's not much we can do automatically here.<br>
><br>
> There is a way to make a Pascal class reference counted, by making it a descendent of TInterfacedObject (or more generally, by implementing the IUnknown interface) and only handling it via interface variables, so maybe the compiler could generate special code in that case to make sure that the block does update the reference counts in that case. That way, you can have a choice between manual and automatic reference counting. I still have to think this through to determine whether this reference counted approach is in fact feasible to implement.</p>
<p>We would need reference counting support anyway for Pascal strings and arrays if we'd allow it on non-Mac OS X (btw: does invoking in Pascal code also work correctly? Your example does not show this...). And interfaces and ARC classes will "simply" need that as well... For normal classes I'd say that it's the responsibility of the programmer to free them, but maybe we could somehow provide access to that "after use" functionality you mentioned (e.g. another function that can be assigned or something like that, though I don't have a good syntax idea right now)</p>
<p>> I currently have no idea how to encapsulate this in Pascal. We could add __block and __weak modifiers (the __weak modifier would also be useful for non-block-related Objective-Pascal once we add support for ARC/Automated Reference Counting), but that's not really nice.<br>
><br>
> Another option is to only support by-value copies, and basically always use cases 1) and 3) above depending on the type of the variable. If you want to change something by reference, then you would have to manually set up a pointer (or object instance) first.</p>
<p>I could (at least on first sight) live with that.</p>
<p>><br>
> Or maybe someone has another idea that combines the flexibility with a Pascalish syntax/way of working?</p>
<p>I'll need to think about this a bit...</p>
<p>Regards,<br>
Sven</p>