Я оцінюю бібліотеку, публічний API якої зараз виглядає так:
libengine.h
/* Handle, used for all APIs */ typedef size_t enh; /* Create new engine instance; result returned in handle */ int en_open(int mode, enh *handle); /* Start an engine */ int en_start(enh handle); /* Add a new hook to the engine; hook handle returned in h2 */ int en_add_hook(enh handle, int hooknum, enh *h2);
Зауважте, що enh
це універсальна ручка, яка використовується як ручка для декількох різних типів даних ( двигуни та гачки ).
Внутрішня частина більшості цих API-інтерфейсів, звичайно, кидає "ручку" внутрішній структурі, яку вони мали malloc
:
двигун.c
struct engine { // ... implementation details ... }; int en_open(int mode, *enh handle) { struct engine *en; en = malloc(sizeof(*en)); if (!en) return -1; // ...initialization... *handle = (enh)en; return 0; } int en_start(enh handle) { struct engine *en = (struct engine*)handle; return en->start(en); }
Особисто я ненавиджу ховати речі за typedef
s, особливо коли це загрожує безпеці типу. (З огляду на enh
, як я можу знати, на що йдеться насправді?)
Тож я подав запит на витяг, пропонуючи наступну зміну API (після зміни всієї бібліотеки на відповідну):
libengine.h
struct engine; /* Forward declaration */
typedef size_t hook_h; /* Still a handle, for other reasons */
/* Create new engine instance, result returned in en */
int en_open(int mode, struct engine **en);
/* Start an engine */
int en_start(struct engine *en);
/* Add a new hook to the engine; hook handle returned in hh */
int en_add_hook(struct engine *en, int hooknum, hook_h *hh);
Звичайно, це робить внутрішні реалізації API виглядати набагато краще, усуваючи касти та підтримуючи безпеку типу до / з точки зору споживача.
libengine.c
struct engine
{
// ... implementation details ...
};
int en_open(int mode, struct engine **en)
{
struct engine *_e;
_e = malloc(sizeof(*_e));
if (!_e)
return -1;
// ...initialization...
*en = _e;
return 0;
}
int en_start(struct engine *en)
{
return en->start(en);
}
Я вважаю за краще це з наступних причин:
- Додано тип безпеки
- Поліпшена чіткість типів та їх призначення
- Вилучені касти та
typedef
с - Він дотримується рекомендованої схеми для непрозорих типів у С
Однак власник проекту відмовився від запиту на витяг (перефразоване):
Особисто мені не подобається ідея викриття
struct engine
. Я все ще думаю, що поточний спосіб є чистішим та дружнішим.Спочатку я використовував інший тип даних для ручки гачка, але потім вирішив переключитися на використання
enh
, тому всі види ручок поділяють один і той же тип даних, щоб зробити це просто. Якщо це заплутано, ми, звичайно, можемо використовувати інший тип даних.Подивимося, що думають інші про цей піар.
Наразі ця бібліотека перебуває на стадії бета-версії, тому споживчого коду не варто турбуватися (поки що). Крім того, я трохи заблукав імена.
Як непрозора ручка краще, ніж названа непрозора структура?
Примітка. Я задав це запитання в Code Review , де воно було закрите.