[fpc-devel] Blocks support
Jonas Maebe
jonas.maebe at elis.ugent.be
Wed Jul 16 18:45:02 CEST 2014
On 16/07/14 15:11, Sven Barth wrote:
> Am 16.07.2014 14:13 schrieb "Jonas Maebe" <jonas.maebe at elis.ugent.be
> <mailto:jonas.maebe at elis.ugent.be>>:
> >
> > 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 :)
Indeed (especially after the changes I've added below).
> > 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?
Yes, since it's an extension.
> > "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)
While working on this, I didn't realise at all that Delphi had to have
rules already regarding capturing local variables for its own anonymous
method support. I've now read what it does and it indeed always has the
same behaviour as variables declared as "__block" in C blocks. So I
would propose to use this behaviour for consistency and leave out
support for capturing local variables as const/snapshot values.
Similarly, they also already have a syntax for "block type" variables
(var proc: reference to function(l: longint): longint;"), so I propose
to use that one as well instead of my "is block". Possibly with "cdecl;"
at the end to differentiate between C blocks and whatever the FPC
implementation will be, since some people will probably want to
reimplement the blocks runtime, or something similar, in Pascal
(definitely not me).
> > 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
I don't understand this. As mentioned, there are block-specific
callbacks that are automatically invoked whenever a block is copied or
destroyed (which has to be performed by ABI-defined helpers). In those
callbacks (which are compiler-generated), the compiler can put code to
handle the reference counting of reference-counted types. The problem is
only with non-reference-counted types such as classes.
An implementation not based on the blocks runtime would indeed need the
same functionality, but it would have exactly the same problem (it can't
reference count arbitrary class instances). Note that there is an open
source blocks run time that is not specific to Mac OS X; there are at
least Linux and FreeBSD ports of it, both supported by clang/llvm on
those platforms (but of course it depends on libc).
> (btw: does invoking in Pascal
> code also work correctly? Your example does not show this...).
Yes. Invoking a block is the easy part :) You just call the "invoke"
function pointer in the block record, passing the address of the block
record as hidden first parameter.
> 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)
There's no callback that is called only when the last instance of a
block is destroyed. Although I guess we could do that ourselves by
inserting a reference count of our own as part of the "captured" data...
The syntax could be done similar as with enumeration callbacks: provide
a static class method with a particular name that takes an instance of
that class as parameter and if it exists, the compiler will generate the
cleanup call/reference counting stuff and call the method with the
instance as parameter).
This is definitely not something for a first implementation though.
Jonas
PS: the blocks ABI and their behaviour is fairly well documented at
http://clang.llvm.org/docs/Block-ABI-Apple.html
More information about the fpc-devel
mailing list