SlideShare a Scribd company logo
Hourglass Interfaces 
for C++ APIs 
Stefanus Du Toit 
Thalmic Labs 
@stefanusdutoit 
Image © Erik Fitzpatrick, CC BY 2.0
Motivation and 
Introduction
Shared Libraries 
Library Code Data
Shared Libraries 
Interface 
Code Data 
Library
Shared Libraries 
Interface 
Code Data 
Client! 
Program 
Library 
Code Data
Shared Libraries 
Interface 
Code Data 
Client! 
Program 
Library 
Code Data 
ABI! 
! 
Common libraries
Different ABIs? Subtle problems… 
Class A 
Class B
Different ABIs? Subtle problems… 
Class A 
Class B 
Debug Build 
Release Build
My Goal for Libraries 
Get out of the client’s way.
My Goal for Libraries 
Don’t make my clients: 
• build my code if they don’t want to 
• change how they build their code 
• rebuild their code because I shipped a fix in mine 
• learn a new language if they don’t want to
Why does this help? 
• Avoids ABI-related binary compatibility issues 
• Enforces no use of non-trivial C++ types in the 
binary interface (e.g. std::string) 
• Keeps internal layout of data types a secret 
• Makes binding to other languages much easier 
! 
• Still get all the convenience of C++ at both ends
Example: libhairpoll 
• A library for creating hair-related polls, taking 
votes, and tallying the results
hairpoll.h 
typedef struct hairpoll* hairpoll_t; 
! 
hairpoll_t hairpoll_construct(const char* person); 
void hairpoll_destruct(hairpoll_t poll); 
! 
int32_t hairpoll_add_option(hairpoll_t hairpoll, 
const char* name, const char* image_url); 
! 
void hairpoll_vote(hairpoll_t hairpoll, int32_t option); 
! 
typedef void (*hairpoll_result_handler_t)(void* client_data, 
const char* name, int32_t votes, const char* html); 
! 
void hairpoll_tally(const hairpoll_t hairpoll, 
hairpoll_result_handler_t handler, void* client_data);
HairPoll class - client-facing 
class HairPoll { 
public: 
HairPoll(std::string person); 
~HairPoll(); 
! 
int addOption(std::string name, std::string imageUrl); 
void vote(int option); 
! 
struct Result { 
std::string name; 
int votes; 
std::string html; 
}; 
std::vector<Result> results() const; 
! 
private: 
hairpoll_t _opaque; 
};
Best Practices
Parts of C to use in the thin API 
• C89 + const and // comments 
• Functions, but no variadic functions 
• C primitive types (char, void, etc.) 
• Pointers 
• forward-declared structs 
• enumerations 
• Function pointers are OK, too
Opaque Types 
typedef struct hairpoll* hairpoll_t; 
! 
void hairpoll_vote( 
hairpoll_t hairpoll, 
int32_t option 
);
Opaque Types 
extern "C" 
struct hairpoll { 
Poll actual; 
};
Opaque Types 
extern "C" 
struct hairpoll { 
template<typename... Args> 
hairpoll(Args&&... args) 
: actual(std::forward<Args>(args)...) 
{ 
} 
! 
Poll actual; 
};
Opaque Types 
class Poll { 
public: 
Poll(std::string person); 
! 
struct option { 
option(std::string name, std::string url); 
! 
std::string name; 
std::string url; 
int votes; 
}; 
! 
std::string person; 
std::vector<option> options; 
};
Opaque Types 
hairpoll_t 
hairpoll_construct(const char* person) 
{ 
return new hairpoll(person); 
} 
! 
void hairpoll_destruct(hairpoll_t poll) 
{ 
delete poll; 
}
Integral types 
Prefer stdint.h types (int32_t, int64_t, etc.) over plain 
C integer types (short, int, long): 
! 
void hairpoll_vote( 
hairpoll_t hairpoll, 
int32_t option 
);
Integral types 
Using char is OK, though: 
! 
int32_t 
hairpoll_add_option( 
hairpoll_t hairpoll, 
const char* name, 
const char* image_url 
);
Enumerations 
typedef enum motu_alignment { 
heroic_warrior = 0, 
evil_warrior = 1, 
}; 
! 
int32_t motu_count( 
int32_t alignment 
);
Error Handling 
void hairpoll_vote( 
hairpoll_t hairpoll, 
int32_t option, 
error_t* out_error 
);
Error Handling 
typedef struct error* error_t; 
! 
const char* error_message( 
error_t error 
); 
! 
void error_destruct(error_t error); 
! 
! 
void hairpoll_vote(hairpoll_t hairpoll, int32_t option, error_t* out_error);
Errors → Exceptions 
struct Error { 
Error() : opaque(nullptr) {} 
~Error() { if (opaque) { error_destruct(opaque); } } 
error_t opaque; 
}; 
! 
class ThrowOnError { 
public: 
~ThrowOnError() noexcept(false) { 
if (_error.opaque) { 
throw std::runtime_error(error_message(_error.opaque)); 
} 
} 
! 
operator error_t*() { return &_error.opaque; } 
! 
private: 
Error _error; 
};
Errors → Exceptions 
void hairpoll_vote(hairpoll_t hairpoll, int32_t option, error_t* out_error); 
! 
void vote(int option) { 
return hairpoll_vote( 
_opaque, 
option, 
ThrowOnError{} 
); 
}
Exceptions → Errors 
template<typename Fn> 
bool translateExceptions(error_t* out_error, Fn&& fn) 
{ 
try { 
fn(); 
} catch (const std::exception& e) { 
*out_error = new error{e.what()}; 
return false; 
} catch (...) { 
*out_error = new error{"Unknown internal error"}; 
return false; 
} 
return true; 
}
Exceptions → Errors 
void hairpoll_vote(const hairpoll_t poll, 
int32_t option, error_t* out_error) 
{ 
translateExceptions(out_error, [&]{ 
if (option < 0 || 
option >= poll->actual.options.size()) { 
throw std::runtime_error("Bad optn index"); 
} 
! 
poll->actual.options[option].votes++; 
}); 
}
Callbacks 
typedef void (*hairpoll_result_handler_t)( 
void* client_data, 
const char* name, 
int32_t votes, 
const char* html 
); 
! 
void hairpoll_tally(const hairpoll_t hairpoll, 
hairpoll_result_handler_t handler, 
void* client_data, error_t* out_error);
Using lambdas as callbacks 
std::vector<Result> results() const { 
std::vector<Result> ret; 
! 
auto addResult = [&ret](const char* name, int32_t votes, 
const char* html){ 
ret.push_back(Result{name, votes, html}); 
}; 
! 
auto callback = [](void* client_data, const char* name, int32_t votes, 
const char* html){ 
auto fn = static_cast<decltype(&addResult)>(client_data); 
(*fn)(name, votes, html); 
}; 
! 
hairpoll_tally(_opaque, callback, &addResult, ThrowOnError{}); 
! 
return ret; 
}
Symbol visibility 
#if defined(_WIN32) || defined(__CYGWIN__) 
#ifdef hairpoll_EXPORTS 
#ifdef __GNUC__ 
#define HAIRPOLL_EXPORT __attribute__ ((dllexport)) 
#else 
#define HAIRPOLL_EXPORT __declspec(dllexport) 
#endif 
#else 
#ifdef __GNUC__ 
#define HAIRPOLL_EXPORT __attribute__ ((dllimport)) 
#else 
#define HAIRPOLL_EXPORT __declspec(dllimport) 
#endif 
#endif 
#else 
#if __GNUC__ >= 4 
#define HAIRPOLL_EXPORT __attribute__ ((visibility ("default"))) 
#else 
#define HAIRPOLL_EXPORT 
#endif 
#endif
Symbol visibility 
#include "visibility.h" 
! 
… 
! 
HAIRPOLL_EXPORT 
hairpoll_t hairpoll_construct(const char* person); 
! 
HAIRPOLL_EXPORT 
void hairpoll_destruct(hairpoll_t poll); 
! 
…
Symbol visibility 
On Clang and GCC, add to your compile: 
! 
-fvisibility=hidden 
! 
(applies to library only)
Remember to extern “C”! 
#ifdef __cplusplus 
extern "C" { 
#endif 
! 
// C API goes here 
! 
#ifdef __cplusplus 
} // extern "C" 
#endif
Lifetime and Ownership 
• Keep it simple: construct (if needed) and destruct 
• Always use RAII on the client side! 
• Can use refcounting (e.g. shared_ptr) both 
internally to the library and in the client 
• For callbacks, you can use the stack
Interfacing with those 
“other” languages
Foreign Function Interfaces 
• “something that allows calling code written in one 
language from another language” 
• C = de-facto standard 
• Languages with support for calling C functions in 
shared libraries include: 
• Common Lisp, Java, JavaScript, Matlab, .NET 
(C#, F#, etc.), Python, Ruby, OCaml, basically everything…
Hair Polls in Python 
hairpoll = lib.hairpoll_construct("Stefanus Du Toit", None) 
! 
skeletor = lib.hairpoll_add_option(hairpoll, "Skeletor", 
"<long URL omitted>", None) 
beast = lib.hairpoll_add_option(hairpoll, "Beast Man", 
"<long URL omitted>", None) 
! 
lib.hairpoll_vote(hairpoll, skeletor, None) 
lib.hairpoll_vote(hairpoll, beast, None) 
lib.hairpoll_vote(hairpoll, beast, None) 
! 
def print_result(client_data, name, votes, html): 
print name, votes 
! 
lib.hairpoll_tally(hairpoll, hairpoll_result_handler(print_result), 
None, None) 
! 
lib.hairpoll_destruct(hairpoll)
Hair Polls In Python 
from ctypes import * 
! 
lib = CDLL("libhairpoll.dylib") 
lib.hairpoll_construct.restype = c_void_p 
lib.hairpoll_construct.argtypes = [c_char_p, c_void_p] 
! 
lib.hairpoll_destruct.restype = None 
lib.hairpoll_destruct.argtypes = [c_void_p] 
! 
lib.hairpoll_add_option.restype = c_int 
lib.hairpoll_add_option.argtypes = [c_void_p, c_char_p, c_char_p, c_void_p] 
! 
lib.hairpoll_vote.restype = None 
lib.hairpoll_vote.argtypes = [c_void_p, c_int, c_void_p] 
! 
hairpoll_result_handler = CFUNCTYPE(None, c_void_p, c_char_p, c_int, c_char_p) 
lib.hairpoll_tally.restype = None 
lib.hairpoll_tally.argtypes = [c_void_p, hairpoll_result_handler, c_void_p, 
c_void_p]
Summary 
• Hourglass = C++ on top of C89 on top of C++ 
• Avoids ABI issues, sneaky dependencies, etc. 
• Hides object layout and other implementation 
details 
• Makes FFI bindings easy
Q&A 
http://blog.sduto.it/ @stefanusdutoit

More Related Content

What's hot

Android OS Porting: Introduction
Android OS Porting: IntroductionAndroid OS Porting: Introduction
Android OS Porting: Introduction
Jollen Chen
 
Using the Android Native Development Kit (NDK)
Using the Android Native Development Kit (NDK)Using the Android Native Development Kit (NDK)
Using the Android Native Development Kit (NDK)
Xavier Hallade
 
Embedded Android : System Development - Part IV
Embedded Android : System Development - Part IVEmbedded Android : System Development - Part IV
Embedded Android : System Development - Part IV
Emertxe Information Technologies Pvt Ltd
 
Clang tidy
Clang tidyClang tidy
Clang tidy
Yury Yafimachau
 
Introduction to kotlin
Introduction to kotlinIntroduction to kotlin
Introduction to kotlin
NAVER Engineering
 
Modern C++ Explained: Move Semantics (Feb 2018)
Modern C++ Explained: Move Semantics (Feb 2018)Modern C++ Explained: Move Semantics (Feb 2018)
Modern C++ Explained: Move Semantics (Feb 2018)
Olve Maudal
 
Android audio system(audioflinger)
Android audio system(audioflinger)Android audio system(audioflinger)
Android audio system(audioflinger)fefe7270
 
Linux Internals - Part I
Linux Internals - Part ILinux Internals - Part I
Embedded Android : System Development - Part I
Embedded Android : System Development - Part IEmbedded Android : System Development - Part I
Embedded Android : System Development - Part I
Emertxe Information Technologies Pvt Ltd
 
GCC RTL and Machine Description
GCC RTL and Machine DescriptionGCC RTL and Machine Description
GCC RTL and Machine Description
Priyatham Bollimpalli
 
Embedded Android : System Development - Part II (HAL)
Embedded Android : System Development - Part II (HAL)Embedded Android : System Development - Part II (HAL)
Embedded Android : System Development - Part II (HAL)
Emertxe Information Technologies Pvt Ltd
 
Android IPC Mechanism
Android IPC MechanismAndroid IPC Mechanism
Android IPC MechanismLihan Chen
 
Vulkan 1.1 Reference Guide
Vulkan 1.1 Reference GuideVulkan 1.1 Reference Guide
Vulkan 1.1 Reference Guide
The Khronos Group Inc.
 
C Programming - Refresher - Part II
C Programming - Refresher - Part II C Programming - Refresher - Part II
C Programming - Refresher - Part II
Emertxe Information Technologies Pvt Ltd
 
Camera2 API, SHIM, and HAL 3.2 in Android 5.1
Camera2 API, SHIM, and HAL 3.2 in Android 5.1Camera2 API, SHIM, and HAL 3.2 in Android 5.1
Camera2 API, SHIM, and HAL 3.2 in Android 5.1
Cheng Hsien Chen
 
Ninja Build: Simple Guide for Beginners
Ninja Build: Simple Guide for BeginnersNinja Build: Simple Guide for Beginners
Ninja Build: Simple Guide for Beginners
Chang W. Doh
 
Effective CMake
Effective CMakeEffective CMake
Effective CMake
Daniel Pfeifer
 
Understanding the Android System Server
Understanding the Android System ServerUnderstanding the Android System Server
Understanding the Android System Server
Opersys inc.
 

What's hot (20)

Android OS Porting: Introduction
Android OS Porting: IntroductionAndroid OS Porting: Introduction
Android OS Porting: Introduction
 
Using the Android Native Development Kit (NDK)
Using the Android Native Development Kit (NDK)Using the Android Native Development Kit (NDK)
Using the Android Native Development Kit (NDK)
 
Embedded Android : System Development - Part IV
Embedded Android : System Development - Part IVEmbedded Android : System Development - Part IV
Embedded Android : System Development - Part IV
 
Clang tidy
Clang tidyClang tidy
Clang tidy
 
Introduction to kotlin
Introduction to kotlinIntroduction to kotlin
Introduction to kotlin
 
Modern C++ Explained: Move Semantics (Feb 2018)
Modern C++ Explained: Move Semantics (Feb 2018)Modern C++ Explained: Move Semantics (Feb 2018)
Modern C++ Explained: Move Semantics (Feb 2018)
 
Android audio system(audioflinger)
Android audio system(audioflinger)Android audio system(audioflinger)
Android audio system(audioflinger)
 
Linux Internals - Part I
Linux Internals - Part ILinux Internals - Part I
Linux Internals - Part I
 
Tech talks#6: Code Refactoring
Tech talks#6: Code RefactoringTech talks#6: Code Refactoring
Tech talks#6: Code Refactoring
 
Embedded Android : System Development - Part I
Embedded Android : System Development - Part IEmbedded Android : System Development - Part I
Embedded Android : System Development - Part I
 
GCC RTL and Machine Description
GCC RTL and Machine DescriptionGCC RTL and Machine Description
GCC RTL and Machine Description
 
Embedded Android : System Development - Part II (HAL)
Embedded Android : System Development - Part II (HAL)Embedded Android : System Development - Part II (HAL)
Embedded Android : System Development - Part II (HAL)
 
Android IPC Mechanism
Android IPC MechanismAndroid IPC Mechanism
Android IPC Mechanism
 
Vulkan 1.1 Reference Guide
Vulkan 1.1 Reference GuideVulkan 1.1 Reference Guide
Vulkan 1.1 Reference Guide
 
C Programming - Refresher - Part II
C Programming - Refresher - Part II C Programming - Refresher - Part II
C Programming - Refresher - Part II
 
Camera2 API, SHIM, and HAL 3.2 in Android 5.1
Camera2 API, SHIM, and HAL 3.2 in Android 5.1Camera2 API, SHIM, and HAL 3.2 in Android 5.1
Camera2 API, SHIM, and HAL 3.2 in Android 5.1
 
Ninja Build: Simple Guide for Beginners
Ninja Build: Simple Guide for BeginnersNinja Build: Simple Guide for Beginners
Ninja Build: Simple Guide for Beginners
 
The Internals of "Hello World" Program
The Internals of "Hello World" ProgramThe Internals of "Hello World" Program
The Internals of "Hello World" Program
 
Effective CMake
Effective CMakeEffective CMake
Effective CMake
 
Understanding the Android System Server
Understanding the Android System ServerUnderstanding the Android System Server
Understanding the Android System Server
 

Viewers also liked

Connecting C++ and JavaScript on the Web with Embind
Connecting C++ and JavaScript on the Web with EmbindConnecting C++ and JavaScript on the Web with Embind
Connecting C++ and JavaScript on the Web with Embind
Chad Austin
 
Refactoring
RefactoringRefactoring
Refactoring
Herez Moise Kattan
 
Software Development Practices Patterns
Software Development Practices PatternsSoftware Development Practices Patterns
Software Development Practices Patterns
Herez Moise Kattan
 
Introduction to Mob Programming
Introduction to Mob ProgrammingIntroduction to Mob Programming
Introduction to Mob Programming
Herez Moise Kattan
 
Programação simultânea em pares
Programação simultânea em paresProgramação simultânea em pares
Programação simultânea em paresHerez Moise Kattan
 
Nonvital pulp therapy in pediatric dentistry
Nonvital pulp therapy in pediatric dentistryNonvital pulp therapy in pediatric dentistry
Nonvital pulp therapy in pediatric dentistry
Priyank Pareek
 
Cleaning and shaping the root canal system
Cleaning and shaping the root canal systemCleaning and shaping the root canal system
Cleaning and shaping the root canal systemParth Thakkar
 
Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented Programming
Scott Wlaschin
 
How To Design A Good A P I And Why It Matters G O O G L E
How To Design A Good  A P I And Why It Matters    G O O G L EHow To Design A Good  A P I And Why It Matters    G O O G L E
How To Design A Good A P I And Why It Matters G O O G L Eguestbe92f4
 

Viewers also liked (9)

Connecting C++ and JavaScript on the Web with Embind
Connecting C++ and JavaScript on the Web with EmbindConnecting C++ and JavaScript on the Web with Embind
Connecting C++ and JavaScript on the Web with Embind
 
Refactoring
RefactoringRefactoring
Refactoring
 
Software Development Practices Patterns
Software Development Practices PatternsSoftware Development Practices Patterns
Software Development Practices Patterns
 
Introduction to Mob Programming
Introduction to Mob ProgrammingIntroduction to Mob Programming
Introduction to Mob Programming
 
Programação simultânea em pares
Programação simultânea em paresProgramação simultânea em pares
Programação simultânea em pares
 
Nonvital pulp therapy in pediatric dentistry
Nonvital pulp therapy in pediatric dentistryNonvital pulp therapy in pediatric dentistry
Nonvital pulp therapy in pediatric dentistry
 
Cleaning and shaping the root canal system
Cleaning and shaping the root canal systemCleaning and shaping the root canal system
Cleaning and shaping the root canal system
 
Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented Programming
 
How To Design A Good A P I And Why It Matters G O O G L E
How To Design A Good  A P I And Why It Matters    G O O G L EHow To Design A Good  A P I And Why It Matters    G O O G L E
How To Design A Good A P I And Why It Matters G O O G L E
 

Similar to Hourglass Interfaces for C++ APIs - CppCon 2014

Modern C++
Modern C++Modern C++
Modern C++
Michael Clark
 
Bringing nullability into existing code - dammit is not the answer.pptx
Bringing nullability into existing code - dammit is not the answer.pptxBringing nullability into existing code - dammit is not the answer.pptx
Bringing nullability into existing code - dammit is not the answer.pptx
Maarten Balliauw
 
Glimpses of C++0x
Glimpses of C++0xGlimpses of C++0x
Glimpses of C++0x
ppd1961
 
devLink - What's New in C# 4?
devLink - What's New in C# 4?devLink - What's New in C# 4?
devLink - What's New in C# 4?
Kevin Pilch
 
Solid C++ by Example
Solid C++ by ExampleSolid C++ by Example
Solid C++ by Example
Olve Maudal
 
Session 2 - Objective-C basics
Session 2 - Objective-C basicsSession 2 - Objective-C basics
Session 2 - Objective-C basicsVu Tran Lam
 
Things to Remember When Developing 64-bit Software
Things to Remember When Developing 64-bit SoftwareThings to Remember When Developing 64-bit Software
Things to Remember When Developing 64-bit SoftwareAndrey Karpov
 
What has to be paid attention when reviewing code of the library you develop
What has to be paid attention when reviewing code of the library you developWhat has to be paid attention when reviewing code of the library you develop
What has to be paid attention when reviewing code of the library you develop
Andrey Karpov
 
Fundamentals of Programming Constructs.pptx
Fundamentals of  Programming Constructs.pptxFundamentals of  Programming Constructs.pptx
Fundamentals of Programming Constructs.pptx
vijayapraba1
 
Design Patterns in Modern C++
Design Patterns in Modern C++Design Patterns in Modern C++
Design Patterns in Modern C++
Dmitri Nesteruk
 
Vocabulary Types in C++17
Vocabulary Types in C++17Vocabulary Types in C++17
Vocabulary Types in C++17
Bartlomiej Filipek
 
Aspdot
AspdotAspdot
Programming using c++ tool
Programming using c++ toolProgramming using c++ tool
Programming using c++ tool
Abdullah Jan
 
Hooking signals and dumping the callstack
Hooking signals and dumping the callstackHooking signals and dumping the callstack
Hooking signals and dumping the callstack
Thierry Gayet
 
C
CC
Presentation 2nd
Presentation 2ndPresentation 2nd
Presentation 2ndConnex
 
Data types and Operators
Data types and OperatorsData types and Operators
Data types and Operators
raksharao
 
Introduction Of C++
Introduction Of C++Introduction Of C++
Introduction Of C++
Sangharsh agarwal
 

Similar to Hourglass Interfaces for C++ APIs - CppCon 2014 (20)

Modern C++
Modern C++Modern C++
Modern C++
 
Gcrc talk
Gcrc talkGcrc talk
Gcrc talk
 
Bringing nullability into existing code - dammit is not the answer.pptx
Bringing nullability into existing code - dammit is not the answer.pptxBringing nullability into existing code - dammit is not the answer.pptx
Bringing nullability into existing code - dammit is not the answer.pptx
 
Glimpses of C++0x
Glimpses of C++0xGlimpses of C++0x
Glimpses of C++0x
 
devLink - What's New in C# 4?
devLink - What's New in C# 4?devLink - What's New in C# 4?
devLink - What's New in C# 4?
 
Solid C++ by Example
Solid C++ by ExampleSolid C++ by Example
Solid C++ by Example
 
Session 2 - Objective-C basics
Session 2 - Objective-C basicsSession 2 - Objective-C basics
Session 2 - Objective-C basics
 
Things to Remember When Developing 64-bit Software
Things to Remember When Developing 64-bit SoftwareThings to Remember When Developing 64-bit Software
Things to Remember When Developing 64-bit Software
 
What has to be paid attention when reviewing code of the library you develop
What has to be paid attention when reviewing code of the library you developWhat has to be paid attention when reviewing code of the library you develop
What has to be paid attention when reviewing code of the library you develop
 
Fundamentals of Programming Constructs.pptx
Fundamentals of  Programming Constructs.pptxFundamentals of  Programming Constructs.pptx
Fundamentals of Programming Constructs.pptx
 
Design Patterns in Modern C++
Design Patterns in Modern C++Design Patterns in Modern C++
Design Patterns in Modern C++
 
Vocabulary Types in C++17
Vocabulary Types in C++17Vocabulary Types in C++17
Vocabulary Types in C++17
 
Aspdot
AspdotAspdot
Aspdot
 
Programming using c++ tool
Programming using c++ toolProgramming using c++ tool
Programming using c++ tool
 
Lecture03
Lecture03Lecture03
Lecture03
 
Hooking signals and dumping the callstack
Hooking signals and dumping the callstackHooking signals and dumping the callstack
Hooking signals and dumping the callstack
 
C
CC
C
 
Presentation 2nd
Presentation 2ndPresentation 2nd
Presentation 2nd
 
Data types and Operators
Data types and OperatorsData types and Operators
Data types and Operators
 
Introduction Of C++
Introduction Of C++Introduction Of C++
Introduction Of C++
 

Recently uploaded

Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
XfilesPro
 
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket ManagementUtilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate
 
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissancesAtelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Neo4j
 
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Globus
 
Mobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona InfotechMobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona Infotech
Drona Infotech
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
Globus
 
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing SuiteAI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
Google
 
First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
Globus
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
Donna Lenk
 
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Crescat
 
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
rickgrimesss22
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
Safe Software
 
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOMLORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
lorraineandreiamcidl
 
Quarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden ExtensionsQuarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden Extensions
Max Andersen
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
Globus
 
Introduction to Pygame (Lecture 7 Python Game Development)
Introduction to Pygame (Lecture 7 Python Game Development)Introduction to Pygame (Lecture 7 Python Game Development)
Introduction to Pygame (Lecture 7 Python Game Development)
abdulrafaychaudhry
 
Enterprise Software Development with No Code Solutions.pptx
Enterprise Software Development with No Code Solutions.pptxEnterprise Software Development with No Code Solutions.pptx
Enterprise Software Development with No Code Solutions.pptx
QuickwayInfoSystems3
 
BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024
Ortus Solutions, Corp
 
APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)
Boni García
 
Game Development with Unity3D (Game Development lecture 3)
Game Development  with Unity3D (Game Development lecture 3)Game Development  with Unity3D (Game Development lecture 3)
Game Development with Unity3D (Game Development lecture 3)
abdulrafaychaudhry
 

Recently uploaded (20)

Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
 
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket ManagementUtilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
 
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissancesAtelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissances
 
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
 
Mobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona InfotechMobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona Infotech
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
 
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing SuiteAI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
 
First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
 
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
 
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
 
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOMLORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
 
Quarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden ExtensionsQuarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden Extensions
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
 
Introduction to Pygame (Lecture 7 Python Game Development)
Introduction to Pygame (Lecture 7 Python Game Development)Introduction to Pygame (Lecture 7 Python Game Development)
Introduction to Pygame (Lecture 7 Python Game Development)
 
Enterprise Software Development with No Code Solutions.pptx
Enterprise Software Development with No Code Solutions.pptxEnterprise Software Development with No Code Solutions.pptx
Enterprise Software Development with No Code Solutions.pptx
 
BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024
 
APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)
 
Game Development with Unity3D (Game Development lecture 3)
Game Development  with Unity3D (Game Development lecture 3)Game Development  with Unity3D (Game Development lecture 3)
Game Development with Unity3D (Game Development lecture 3)
 

Hourglass Interfaces for C++ APIs - CppCon 2014

  • 1. Hourglass Interfaces for C++ APIs Stefanus Du Toit Thalmic Labs @stefanusdutoit Image © Erik Fitzpatrick, CC BY 2.0
  • 4. Shared Libraries Interface Code Data Library
  • 5. Shared Libraries Interface Code Data Client! Program Library Code Data
  • 6. Shared Libraries Interface Code Data Client! Program Library Code Data ABI! ! Common libraries
  • 7. Different ABIs? Subtle problems… Class A Class B
  • 8. Different ABIs? Subtle problems… Class A Class B Debug Build Release Build
  • 9. My Goal for Libraries Get out of the client’s way.
  • 10. My Goal for Libraries Don’t make my clients: • build my code if they don’t want to • change how they build their code • rebuild their code because I shipped a fix in mine • learn a new language if they don’t want to
  • 11.
  • 12.
  • 13. Why does this help? • Avoids ABI-related binary compatibility issues • Enforces no use of non-trivial C++ types in the binary interface (e.g. std::string) • Keeps internal layout of data types a secret • Makes binding to other languages much easier ! • Still get all the convenience of C++ at both ends
  • 14. Example: libhairpoll • A library for creating hair-related polls, taking votes, and tallying the results
  • 15. hairpoll.h typedef struct hairpoll* hairpoll_t; ! hairpoll_t hairpoll_construct(const char* person); void hairpoll_destruct(hairpoll_t poll); ! int32_t hairpoll_add_option(hairpoll_t hairpoll, const char* name, const char* image_url); ! void hairpoll_vote(hairpoll_t hairpoll, int32_t option); ! typedef void (*hairpoll_result_handler_t)(void* client_data, const char* name, int32_t votes, const char* html); ! void hairpoll_tally(const hairpoll_t hairpoll, hairpoll_result_handler_t handler, void* client_data);
  • 16. HairPoll class - client-facing class HairPoll { public: HairPoll(std::string person); ~HairPoll(); ! int addOption(std::string name, std::string imageUrl); void vote(int option); ! struct Result { std::string name; int votes; std::string html; }; std::vector<Result> results() const; ! private: hairpoll_t _opaque; };
  • 18. Parts of C to use in the thin API • C89 + const and // comments • Functions, but no variadic functions • C primitive types (char, void, etc.) • Pointers • forward-declared structs • enumerations • Function pointers are OK, too
  • 19. Opaque Types typedef struct hairpoll* hairpoll_t; ! void hairpoll_vote( hairpoll_t hairpoll, int32_t option );
  • 20. Opaque Types extern "C" struct hairpoll { Poll actual; };
  • 21. Opaque Types extern "C" struct hairpoll { template<typename... Args> hairpoll(Args&&... args) : actual(std::forward<Args>(args)...) { } ! Poll actual; };
  • 22. Opaque Types class Poll { public: Poll(std::string person); ! struct option { option(std::string name, std::string url); ! std::string name; std::string url; int votes; }; ! std::string person; std::vector<option> options; };
  • 23. Opaque Types hairpoll_t hairpoll_construct(const char* person) { return new hairpoll(person); } ! void hairpoll_destruct(hairpoll_t poll) { delete poll; }
  • 24. Integral types Prefer stdint.h types (int32_t, int64_t, etc.) over plain C integer types (short, int, long): ! void hairpoll_vote( hairpoll_t hairpoll, int32_t option );
  • 25. Integral types Using char is OK, though: ! int32_t hairpoll_add_option( hairpoll_t hairpoll, const char* name, const char* image_url );
  • 26. Enumerations typedef enum motu_alignment { heroic_warrior = 0, evil_warrior = 1, }; ! int32_t motu_count( int32_t alignment );
  • 27. Error Handling void hairpoll_vote( hairpoll_t hairpoll, int32_t option, error_t* out_error );
  • 28. Error Handling typedef struct error* error_t; ! const char* error_message( error_t error ); ! void error_destruct(error_t error); ! ! void hairpoll_vote(hairpoll_t hairpoll, int32_t option, error_t* out_error);
  • 29. Errors → Exceptions struct Error { Error() : opaque(nullptr) {} ~Error() { if (opaque) { error_destruct(opaque); } } error_t opaque; }; ! class ThrowOnError { public: ~ThrowOnError() noexcept(false) { if (_error.opaque) { throw std::runtime_error(error_message(_error.opaque)); } } ! operator error_t*() { return &_error.opaque; } ! private: Error _error; };
  • 30. Errors → Exceptions void hairpoll_vote(hairpoll_t hairpoll, int32_t option, error_t* out_error); ! void vote(int option) { return hairpoll_vote( _opaque, option, ThrowOnError{} ); }
  • 31. Exceptions → Errors template<typename Fn> bool translateExceptions(error_t* out_error, Fn&& fn) { try { fn(); } catch (const std::exception& e) { *out_error = new error{e.what()}; return false; } catch (...) { *out_error = new error{"Unknown internal error"}; return false; } return true; }
  • 32. Exceptions → Errors void hairpoll_vote(const hairpoll_t poll, int32_t option, error_t* out_error) { translateExceptions(out_error, [&]{ if (option < 0 || option >= poll->actual.options.size()) { throw std::runtime_error("Bad optn index"); } ! poll->actual.options[option].votes++; }); }
  • 33. Callbacks typedef void (*hairpoll_result_handler_t)( void* client_data, const char* name, int32_t votes, const char* html ); ! void hairpoll_tally(const hairpoll_t hairpoll, hairpoll_result_handler_t handler, void* client_data, error_t* out_error);
  • 34. Using lambdas as callbacks std::vector<Result> results() const { std::vector<Result> ret; ! auto addResult = [&ret](const char* name, int32_t votes, const char* html){ ret.push_back(Result{name, votes, html}); }; ! auto callback = [](void* client_data, const char* name, int32_t votes, const char* html){ auto fn = static_cast<decltype(&addResult)>(client_data); (*fn)(name, votes, html); }; ! hairpoll_tally(_opaque, callback, &addResult, ThrowOnError{}); ! return ret; }
  • 35. Symbol visibility #if defined(_WIN32) || defined(__CYGWIN__) #ifdef hairpoll_EXPORTS #ifdef __GNUC__ #define HAIRPOLL_EXPORT __attribute__ ((dllexport)) #else #define HAIRPOLL_EXPORT __declspec(dllexport) #endif #else #ifdef __GNUC__ #define HAIRPOLL_EXPORT __attribute__ ((dllimport)) #else #define HAIRPOLL_EXPORT __declspec(dllimport) #endif #endif #else #if __GNUC__ >= 4 #define HAIRPOLL_EXPORT __attribute__ ((visibility ("default"))) #else #define HAIRPOLL_EXPORT #endif #endif
  • 36. Symbol visibility #include "visibility.h" ! … ! HAIRPOLL_EXPORT hairpoll_t hairpoll_construct(const char* person); ! HAIRPOLL_EXPORT void hairpoll_destruct(hairpoll_t poll); ! …
  • 37. Symbol visibility On Clang and GCC, add to your compile: ! -fvisibility=hidden ! (applies to library only)
  • 38. Remember to extern “C”! #ifdef __cplusplus extern "C" { #endif ! // C API goes here ! #ifdef __cplusplus } // extern "C" #endif
  • 39. Lifetime and Ownership • Keep it simple: construct (if needed) and destruct • Always use RAII on the client side! • Can use refcounting (e.g. shared_ptr) both internally to the library and in the client • For callbacks, you can use the stack
  • 40. Interfacing with those “other” languages
  • 41. Foreign Function Interfaces • “something that allows calling code written in one language from another language” • C = de-facto standard • Languages with support for calling C functions in shared libraries include: • Common Lisp, Java, JavaScript, Matlab, .NET (C#, F#, etc.), Python, Ruby, OCaml, basically everything…
  • 42. Hair Polls in Python hairpoll = lib.hairpoll_construct("Stefanus Du Toit", None) ! skeletor = lib.hairpoll_add_option(hairpoll, "Skeletor", "<long URL omitted>", None) beast = lib.hairpoll_add_option(hairpoll, "Beast Man", "<long URL omitted>", None) ! lib.hairpoll_vote(hairpoll, skeletor, None) lib.hairpoll_vote(hairpoll, beast, None) lib.hairpoll_vote(hairpoll, beast, None) ! def print_result(client_data, name, votes, html): print name, votes ! lib.hairpoll_tally(hairpoll, hairpoll_result_handler(print_result), None, None) ! lib.hairpoll_destruct(hairpoll)
  • 43. Hair Polls In Python from ctypes import * ! lib = CDLL("libhairpoll.dylib") lib.hairpoll_construct.restype = c_void_p lib.hairpoll_construct.argtypes = [c_char_p, c_void_p] ! lib.hairpoll_destruct.restype = None lib.hairpoll_destruct.argtypes = [c_void_p] ! lib.hairpoll_add_option.restype = c_int lib.hairpoll_add_option.argtypes = [c_void_p, c_char_p, c_char_p, c_void_p] ! lib.hairpoll_vote.restype = None lib.hairpoll_vote.argtypes = [c_void_p, c_int, c_void_p] ! hairpoll_result_handler = CFUNCTYPE(None, c_void_p, c_char_p, c_int, c_char_p) lib.hairpoll_tally.restype = None lib.hairpoll_tally.argtypes = [c_void_p, hairpoll_result_handler, c_void_p, c_void_p]
  • 44. Summary • Hourglass = C++ on top of C89 on top of C++ • Avoids ABI issues, sneaky dependencies, etc. • Hides object layout and other implementation details • Makes FFI bindings easy
  • 45.