https://github.com/feeley/gambit/pull/61 - for a quick proof of concept, that's a very neat use of the ffi type!!!


2013/12/25 Estevo <euccastro@gmail.com>

I have never been aware of anything like that. Can you provide a proof of concept example code that shows how weak references to a FFI object would be inconsistent?

The problem is not that they're inconsistent.  The problem is they can't really tell you when an object that is depended upon is safe to free.  I gave an example of that in this thread:

https://mercure.iro.umontreal.ca/pipermail/gambit-list/2013-December/007335.html

So you tried to somehow use wills to force GC order? Without having studied this, I guess that was not what they were intended for in the first place and it makes good sense that that did not work out well.


You can implement this kind of behavior in Gambit (i.e. B is referenced to by or actually contained in A so you want freeing of B to be conditioned to the freeing of A happening before) yourself, for instance by

 1) ensuring you have a reference to B in some vector or alike, one that guaranteedly will stick around until A is freed. Also, you could

Once user code gets hold of A, pure Scheme code can't really know when it's OK to let go of that vector.  It's the same problem.  Of course you can keep a reference forever, but you don't want to hold on to unneeded memory either.

You should be able to work that out and question is just how heavy it would be implementation-wise to do, no??

If not why not?
 
 2) use the "refcount" facility that Gambit exports to the C world, to keep B's refcount +1 as long as A refers to it, and then have A's release procedure -1 its refcount on invocation.

Something like this might work, thanks!  I had given up on foreign release functions because they are C functions that can only be set (or so I thought) per foreign object type (the ones you create in c-define-type) and not per instance, they can't be closures, and they won't get any arguments but the foreign's pointer to C data.  Also, you can only set one, so if you use it for this you can't use it for anything else.

But these restrictions need not be showstoppers.  A scheme that might work:
 - on initalization, create an ___alloc_rc'ed table[1] and assign a global C pointer to it
 - whenever you create a dependent foreign pointer F, store in the table a reference to its dependent object D, keyed by the address of the F's C pointer, and
 - set a release function for F that will clear that entry in the table.

Why do you need a "table" (by table here you mean resizable vector)?


This should work because unlike wills, release functions will only be called when their object is not reachable from Scheme code (barring FFI black magic).

What practical task are you solving?
 
I'm making a library that lets you define C struct/union/type constructors, accessors and mutators using a syntax analogous to that of define-structure. 

Nice!

Gambit's builtin functionality for this is fully sufficient at Gambit's level of abstraction over the underlying system, and indeed there's plenty of space for higher-level abstractions that more in this area.

So the totality of what you are looking to provide is

 a) the c-struct form which is analogous to define-type with

 b) Scheme-like automatic dependency GC-reference handling between c structure instances as discussed here

?

 
Here's how you define C structure wrappers:

https://github.com/euccastro/gambit-SDL2/blob/master/c-test-ffi.scm


This is from a very old version and it shows that I didn't know what I was doing :), but it does showcase the user interface.  The point is that using C structures from Gambit code should be effortless, straightforward, safe, and fit well both with Scheme and with FFI code that doesn't follow your approach.

I'll give the scheme above a go and let you know how it goes.  I think the solution involving my patch[2] should yield better performance because it doesn't involve any table following and,
 
not requiring the use of release functions,

well, if it's some exotic type where you need C code invoked for the release work then indeed there is the need for a release function, however if that's not the case then yep right, with this model you suggest, there's no need for a release function.
 
allows you to set the last parameter of c-define-type to false.  But maybe this won't matter in practice.

Thanks again!

[1] Globals won't do because the garbage collector doesn't scan those.  Movable objects won't do because you can't reliably keep a C pointer to them.
[2] Which, by the way, I've simplified down to a 5-line change.  See https://github.com/feeley/gambit/pull/61