* As per my offline comment and as Jake had pointed out, you can cast pointers 
to incomplete types, this will leverage the C type system better than mere 
typedefs, and enforce a modicum of an interface’s contract.
* C does not have namespaces or overloading, so we will need a naming 
convention to differentiate our types and methods from any other library or the 
application code. That means all types and functions should be prepended with 
“geode_” or something similar.
* We must absolutely produce a dynamic library. Not all FFI’s support static 
linking. This will also give us greater control over the symbols being 
exported. I agree that this dynamic link target should not share it’s symbol 
space with the C++ library. This grants much greater flexibility 
* I recommend we avoid introducing real types in the exported interface. In 
order to support future revision, we’d have to introduce version and size 
information into the struct a la THE WIN32 API. Remember that? Having to zero 
out the struct then setting the size and version members before the other 
members? This is why they did that.
* The implementation needs to guard against throwing exceptions across the 
library boundary.
* This library needs a thread safe means of error handling. There is not enough 
fleshed out in this RFC to have a meaningful conversation about this at this 
time.
* I would like to see an ability for the client to specify their own 
allocators. This would require an overhaul of the existing C++ ABI and may have 
an impact on our dependencies. This is another talk for a more complete RFC.

> On Mar 27, 2020, at 8:52 AM, Jacob Barrett <jbarr...@pivotal.io> wrote:
> 
> Another couple of thing I thought of last night. 
> 
> The RFC should probably include mentions of tools like SWIG or Clang 
> libtooling for auto generating C-bindings for C++ headers.
> 
> One important area that isn’t covered is how this would address serialization 
> of types/objects in the bound language. For example, if I used this to bind 
> to Go how would my Go object be passed to put, get, or any other method that 
> takes a serializable object? When received how is this language going to be 
> invoked to de-serialize? More time needs to be spent on this aspect of the 
> interface.
> 
> -Jake
> 
> 
>> On Mar 26, 2020, at 3:10 PM, Jacob Barrett <jbarr...@pivotal.io> wrote:
>> 
>> Forgot to include the source example: 
>> https://github.com/pivotal-jbarrett/geode-native/tree/e47698bad3cf725dcbddaad458813e26e75c8c71/ccache
>>  
>> <https://github.com/pivotal-jbarrett/geode-native/tree/e47698bad3cf725dcbddaad458813e26e75c8c71/ccache>
>> 
>> 
>>> On Mar 26, 2020, at 2:56 PM, Jacob Barrett <jbarr...@pivotal.io 
>>> <mailto:jbarr...@pivotal.io>> wrote:
>>> 
>>> On the strongly typed, I found a solution I like even better.
>>> 
>>> struct CacheFactory;
>>> typedef struct CacheFactory CacheFactory;
>>> 
>>> struct Cache;
>>> typedef struct Cache Cache;
>>> 
>>> CacheFactory* createCacheFactory() {
>>>  return reinterpret_cast<CacheFactory*>(
>>>      new apache::geode::client::CacheFactory());
>>> }
>>> 
>>> void destroyCacheFactory(CacheFactory* cacheFactory) {
>>>  delete 
>>> reinterpret_cast<apache::geode::client::CacheFactory*>(cacheFactory);
>>> }
>>> 
>>> Cache* createCache(CacheFactory* cacheFactory) {
>>>  return reinterpret_cast<Cache*>(new apache::geode::client::Cache(
>>>      reinterpret_cast<apache::geode::client::CacheFactory*>(cacheFactory)
>>>          ->create()));
>>> }
>>> 
>>> void destroyCache(Cache* cache) {
>>>  delete reinterpret_cast<apache::geode::client::Cache*>(cache);
>>> }
>>> 
>>> The code below is type safe and won’t compile.
>>> CacheFactory cacheFactory = createCacheFactory();
>>> destroyCache(cacheFactory);
>>> 
>>> 
>>> -Jake
>>> 
>>> 
>>>> On Mar 26, 2020, at 12:22 PM, Jacob Barrett <jbarr...@pivotal.io 
>>>> <mailto:jbarr...@pivotal.io>> wrote:
>>>> 
>>>> I am onboard with the idea but I would like more details in the RFC.
>>>> 
>>>> I would prefer that the C bindings be in its own library. The only symbols 
>>>> that should be visible from this library should be the C exported symbols, 
>>>> the internal C++ symbols should be hidden.
>>>> 
>>>> I feel like this library makes the most sense as a static library. I saw 
>>>> this because in .NET we would link it as a mixed mode assembly to avoid 
>>>> having multiple shared libraries to link. If we did a node client I would 
>>>> expect it too would statically link this library as into its shared 
>>>> library. Same I imagine would apply to all other language bindings.
>>>> 
>>>> How are you planning on managing allocation and deallocation of these 
>>>> opaque void* pointers. You vaguely showed the allocation but deallocation 
>>>> would be a good example. I would assume some “destroy” method for every 
>>>> “create” method.
>>>> 
>>>> Does it make sense to have the CacheFactory concept at all (especially 
>>>> since it is more of a builder)? Could we have some C struct that can be 
>>>> used to create the cache, where the struct has fields for all the 
>>>> configuration? In general can we rethink the API so that it makes sense 
>>>> for C or other language bindings?
>>>> 
>>>> What about finding a way to be more expressive than void*. Typedefs at 
>>>> least express some meaning when hovering but will just decay without 
>>>> warning to the void*.
>>>> 
>>>> Consider:
>>>> typedef void* CacheFactory;
>>>> typedef void* Cache;
>>>> CacheFactory createCacheFactory(void);
>>>> void destroyCacheFactory(CacheFactory cacheFactory);
>>>> Cache createCache(CacheFactory cacheFactory);
>>>> void destroyCache(Cache cache);
>>>> 
>>>> But this compiles:
>>>> CacheFactory cacheFactory = createCacheFactory();
>>>> destroyCache(cacheFactory);
>>>> 
>>>> And explodes at runtime.
>>>> Example 
>>>> https://github.com/pivotal-jbarrett/geode-native/tree/2d7d0a28fb6f85988e7b921fd96ebb975bad8126/ccache
>>>>  
>>>> <https://github.com/pivotal-jbarrett/geode-native/tree/2d7d0a28fb6f85988e7b921fd96ebb975bad8126/ccache>
>>>> 
>>>> We could use structs to hold the opaque pointers, and other values.
>>>> typedef struct {
>>>>  void* ptr;
>>>> } CacheFactory;
>>>> typedef struct {
>>>>  void* ptr;
>>>> } Cache;
>>>> 
>>>> And now this does not compile:
>>>> CacheFactory cacheFactory = createCacheFactory();
>>>> destroyCache(cacheFactory);
>>>> Example 
>>>> https://github.com/pivotal-jbarrett/geode-native/tree/23b44e281fd9771474ff3555020710bf23f454ae/ccache
>>>>  
>>>> <https://github.com/pivotal-jbarrett/geode-native/tree/23b44e281fd9771474ff3555020710bf23f454ae/ccache>
>>>> 
>>>> 
>>>> -Jake
>>>> 
>>>> 
>>>>> On Mar 24, 2020, at 2:20 PM, Blake Bender <bben...@pivotal.io 
>>>>> <mailto:bben...@pivotal.io>> wrote:
>>>>> 
>>>>> Hello everyone,
>>>>> 
>>>>> We'd like to add C bindings to the native client, in preparation for the
>>>>> larger task of adding support for new languages, e.g. .net core.  Please
>>>>> have a look at the proposal below and let me know what you think.
>>>>> 
>>>>> Thanks,
>>>>> 
>>>>> Blake
>>>>> 
>>>>> 
>>>>> https://cwiki.apache.org/confluence/display/GEODE/Add+C+Bindings+to+Native+Client+Library
>>>>>  
>>>>> <https://cwiki.apache.org/confluence/display/GEODE/Add+C+Bindings+to+Native+Client+Library>
>>>> 
>>> 
>> 
> 

Reply via email to