Hi Stefan,

First of all I want to thank you for this mail, which showed me a bug that I had in TalkFFI (the git_repository 'NBVoid *') which introduces one more indirection level, which is wrong.

On Fri, Jan 25, 2013 at 2:13 AM, Stefan Marr <smalltalk@stefan-marr.de> wrote:
Hi:

I don't really understand how NativeBoostFFI handles pointers.

probably Igor is the best to answer this question... in details

I have two functions like this:


self call: #(int git_repository_open(git_repository * * handle, char * path))

� �and

self call: #(int git_repository_head(git_reference * * refHandle, git_repository * repo))



They use a type mapping like this:
� �#('git_repository' 'NBVoid'
� � �'git_reference' �'NBVoid' )

So, nothing special going on here, just pointers to pointers,
and pointers to opaque data structures.

Now, the call to the _open function is done with a `repoHandle := NBExternalHandle new`.
This works, and I get the result value of the c lib inside my repoHandle.

However, if I want to use it in the _head call, I first have to convert it into a NBExternalAddress (`NBExternalAddress value: repoHandle value`).

Took me a while to figure out that passing in the repoHandle to _head does actually do the wrong thing.
The _head function then gets the address of repoHandle instead of its value, which is wrong for my usecase.

However, just passing in `repoHandle value` results in some strange _nil_ error.

So, the main question is, why do I need to convert between Handle and Address?

For the library I am trying to use, that becomes a somehow recurring pattern:


| repo repoPath cb branches headHandle |
repo := NBExternalHandle new.
repoPath := NBExternalAddress fromString: '/Users/smarr/tmp/filetree'.

LG2RepositoryH uniqueInstance repository_open: repo path: repoPath.
repo := NBExternalAddress value: repo value. "<-- Why is this necessary?"

headHandle := NBExternalHandle new.
LG2RepositoryH uniqueInstance repository_head: headHandle repo: repo.

^ (LG2RefsH uniqueInstance
� � �reference_name: (NBExternalAddress value: headHandle value)) "<-- Why is this necessary?"
� � � � readString


Another solution which removes this recurring pattern is to use the NBExternalObject, either directly, or by subclassing it. Here is a snippet showing how:

|headHandle path repo name|
repo := �NBExternalObject new.
path := NBExternalAddress fromString: '/Users/ciprian/github/local/enso'.
LG2RepositoryH �uniqueInstance �repository_open: repo path: path.

headHandle := �NBExternalObject new.
LG2RepositoryH uniqueInstance repository_head: headHandle repo: repo.

name := LG2RefsH uniqueInstance reference_name: headHandle.
name readString.
but now FFI methods need to be changed to:�

repository_open: out path: path
� � � ^self call: #(NBInt32 git_repository_open(NBExternalObject * out, NBCharacterType * path)) options: #( �)

repository_head: out repo: repo�
� �^self call: #(NBInt32 git_repository_head(NBExternalObject * out, NBExternalObject repo)) options: #( �)

reference_name: ref�
^self call: #(NBCharacterType * git_reference_name(NBExternalObject ref)) options: #( �)

Notice that when using NBExternalObject one level of indirection is gone so git_repository ** becomes NBExternalObject *

Even nicer, if you subclass the NBExternalObject to have LG2Repository and LG2Reference, the signatures become clearer...

I will look this weekend at TalkFFI to see how can I make use of this NBExternalObject, at least in the simple cases... to prevent the need for�(NBExternalAddress value: repo value) all over the place.

Cheers,
Ciprian

Thanks
Stefan


--
Stefan Marr
Software Languages Lab
Vrije Universiteit Brussel
Pleinlaan 2 / B-1050 Brussels / Belgium
http://soft.vub.ac.be/~smarr
Phone: +32 2 629 2974
Fax: � +32 2 629 3525





--
Dr. Ciprian TEODOROV
Ing
nieur�D�veloppement�CAO

t�l : 06 08 54 73 48

mail :�ciprian.teodorov@gmail.com
www.teodorov.ro