Show HN: Una implementación pura en C89 de canales de Go, con selects bloqueantes
Una nueva biblioteca de código abierto que implementa canales al estilo de Go y selects bloqueantes en C89 ha provocado debate sobre si apuntar a un estándar de C tan antiguo es una fortaleza para la portabilidad o una restricción innecesaria que perjudica la calidad de la API. Los comentaristas analizan en detalle el diseño, como las convenciones de nombres, el uso de `bool`, la semántica de select, los hooks de asignación y casos límite de concurrencia como los bugs de time-of-check/time-of-use cuando los canales se cierran, mientras comparan el proyecto con alternativas como libmill, libdill y ZeroMQ. Junto a la crítica técnica, varios participantes reflexionan sobre el tono y la etiqueta en las revisiones públicas de código, destacando la tensión entre ofrecer feedback riguroso y mantener un entorno acogedor para los mantenedores voluntarios.
Recepción general
- Muchos comentaristas consideran ingeniosa y útil la idea de canales al estilo de Go en C, especialmente para entornos restringidos o embebidos.
- Varios expresan aprecio por el esfuerzo del autor y su enfoque en la portabilidad, aunque personalmente no vayan a usar C89.
C89 frente a estándares de C más nuevos
- Un grupo sostiene que C89 está desfasado: C11/C17 (y en parte C99) están ampliamente disponibles, y las restricciones de solo C89 degradan la claridad de la API (por ejemplo, la falta de
bool) y la calidad del código. - Otros defienden C89 como un objetivo práctico de portabilidad para compiladores antiguos, toolchains embebidas y proyectos construidos con TinyCC u otros entornos limitados.
- Algunos señalan que la biblioteca no es estrictamente C89 de todos modos (declaraciones/instrucciones mezcladas, hilos POSIX, ciertas extensiones), y argumentan que la etiqueta “pure C89” es engañosa; el autor luego aclara que quiere decir “compila con -std=c89” más que pureza formal estricta.
Comentarios sobre la API y el diseño
- Las sugerencias incluyen:
- Usar un tipo similar a
boolpara retornos de estilo estado cuando sea posible. - Preferir la nomenclatura
_create/_destroysobre_dispose. - Evitar el sufijo
_tporque POSIX lo reserva (otros dicen que esto, en la práctica, no es un problema). - Permitir asignadores personalizados, hooks de logging y banderas de depuración.
- Exponer un descriptor de fichero para que los canales puedan integrarse con bucles de eventos existentes (select/epoll/kqueue/io_uring).
- Usar un tipo similar a
- Algunos destacan que estas son decisiones de “nivel de cabecera” que luego son difíciles de cambiar sin romper la ABI.
Semántica de concurrencia y trampas
- Preocupa
while (!closed(chan)) { … }: el clásico bug de time-of-check/time-of-use si el canal se cierra entre la comprobación y la operación. - Comparaciones con Go: su operación de recepción devuelve de forma atómica tanto el valor como el estado “abierto/cerrado”; se recomienda este patrón en lugar de una comprobación separada
closed(). - Se plantean preguntas sobre qué ocurre con los mensajes en búfer al cerrar y el comportamiento al enviar a un canal cerrado; los comentaristas quieren que esto quede claramente documentado.
Comparaciones con otras bibliotecas y modelos
- Se mencionan proyectos relacionados: libmill/libdill (CSP con corrutinas y multiplexación de E/S), sockets
inprocde ZeroMQ,libthreadde Plan 9, CSP y actores. - Se aclara que esta biblioteca usa hilos del sistema operativo, no corrutinas de nivel de usuario, así que no puede mezclarse con seguridad con planificadores de corrutinas que esperan primitivas no bloqueantes.
Comunidad y tono
- Hay una discusión meta considerable sobre el tono de las críticas: algunos sienten que las primeras objeciones fueron demasiado duras; otros insisten en que la retroalimentación técnica es valiosa si se expresa con más cuidado.