[fpc-devel] Blocks support

Sven Barth pascaldragon at googlemail.com
Wed Jul 16 15:11:25 CEST 2014


Am 16.07.2014 14:13 schrieb "Jonas Maebe" <jonas.maebe at elis.ugent.be>:
>
> Hi,
>
> I've (locally, not yet in svn) implemented support for blocks in FPC (
http://en.wikipedia.org/wiki/Blocks_(C_language_extension) ). 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.

Woah O.o Didn't expect that ^^ Maybe some of this can be reused for
anonymous methods support :)

> 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.:
>
> type
>   NSArrayEnumeratorBlock = procedure (obj: id; idx: NSUInteger; var stop:
boolean) is block;

As I see below it's part of a modeswitch, right?

> 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).
>
> "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).

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)

> However:
>
> * Methods of Pascal classes
>
> 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.
>
> 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.

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)

> 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.
>
> 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.

I could (at least on first sight) live with that.

>
> Or maybe someone has another idea that combines the flexibility with a
Pascalish syntax/way of working?

I'll need to think about this a bit...

Regards,
Sven
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freepascal.org/pipermail/fpc-devel/attachments/20140716/0a0e78bd/attachment.html>


More information about the fpc-devel mailing list