C es lo mejor (2025)
(sqlite.org)- SQLite es desde 2000 un motor de base de datos ligero implementado en lenguaje C, y no tiene planes de reescribirse en otro lenguaje
- C se considera el lenguaje más adecuado para SQLite en términos de rendimiento, compatibilidad, mínimas dependencias y estabilidad
- Los lenguajes orientados a objetos (C++, Java, etc.) tienen grandes limitaciones para llamadas entre lenguajes, y un enfoque procedural puede ser más simple y rápido
- Los “lenguajes seguros” como Rust o Go todavía no han madurado lo suficiente y no se ajustan a la estrategia de calidad de SQLite (por ejemplo, pruebas del 100% de ramas y recuperación ante OOM)
- La posibilidad de portar SQLite a Rust sigue abierta en el futuro, pero solo si se cumplen varias condiciones relacionadas con madurez, compatibilidad, rendimiento y soporte de herramientas
1. Por qué C es la mejor opción
- SQLite fue implementado desde el principio en lenguaje C estándar el 29 de mayo de 2000, y hasta hoy no hay planes de cambiar a otro lenguaje
- Se presentan como razones por las que C es adecuado para SQLite el rendimiento, la compatibilidad, las bajas dependencias y la estabilidad
1.1 Rendimiento
- SQLite es una biblioteca de bajo nivel usada intensivamente, por lo que la velocidad es indispensable
- Como ejemplo, su rendimiento se demuestra en los documentos “Internal Versus External BLOBs” y “35% Faster Than The Filesystem”
- A C se le llama un “lenguaje ensamblador portable”, ya que ofrece control cercano al hardware y al mismo tiempo mantiene la portabilidad entre plataformas
- Aunque otros lenguajes afirman ser “tan rápidos como C”, ninguno afirma ser más rápido que C
1.2 Compatibilidad
- Casi todos los sistemas ofrecen capacidad para llamar bibliotecas escritas en C
- Por ejemplo, Android puede llamar a SQLite desde aplicaciones Java mediante un adaptador
- Si SQLite hubiera sido escrito en Java, no podría usarse en apps de iPhone basadas en Objective-C o Swift
1.3 Bajas dependencias
- Las bibliotecas escritas en C tienen muy pocas dependencias de runtime
- En una configuración mínima, SQLite solo necesita las siguientes funciones de la biblioteca estándar de C
- memcmp(), memcpy(), memmove(), memset(), strcmp(), strlen(), strncmp()
- Incluso en una compilación completa, solo usa malloc(), free() y entrada/salida de archivos
- En cambio, los lenguajes modernos requieren runtimes de varios MB y miles de interfaces
1.4 Estabilidad
- C es un lenguaje antiguo y con pocos cambios, que ofrece un comportamiento claro y predecible
- Al desarrollar un motor de base de datos pequeño, rápido y confiable como SQLite, es importante que la especificación del lenguaje no cambie con frecuencia
2. Por qué no está escrito en un lenguaje orientado a objetos
-
Algunos desarrolladores creen que un sistema complejo solo puede implementarse con un lenguaje orientado a objetos, pero SQLite demuestra lo contrario
-
Una biblioteca escrita en C++ o Java normalmente solo puede usarse desde aplicaciones escritas en ese mismo lenguaje
- En cambio, una biblioteca en C puede llamarse desde casi cualquier lenguaje
-
La orientación a objetos es un patrón de diseño, no el lenguaje en sí, y una estructura orientada a objetos también puede implementarse en C
-
La orientación a objetos no siempre es lo mejor, y en algunos casos el código procedural puede ser más simple y ventajoso en mantenimiento y rendimiento
-
En los inicios de SQLite (principios de los 2000), Java todavía era inmaduro y C++ tenía graves problemas de compatibilidad entre compiladores
- En ese momento, C era claramente una mejor elección, y hoy sigue habiendo muy pocos beneficios en reescribirlo
3. Por qué no está escrito en un “lenguaje seguro”
- En años recientes han llamado la atención los “lenguajes seguros” como Rust y Go, pero SQLite sigue manteniéndose en C
- Durante los primeros 10 años de SQLite no existían lenguajes seguros
- Se podría reescribir en Go o Rust, pero existe el riesgo de introducir nuevos errores y perder rendimiento
- Los lenguajes seguros insertan ramas (branches) adicionales, como verificaciones de límites de arreglos
- En código correcto, esas ramas no se ejecutan, por lo que no es posible hacer pruebas del 100% de ramas
- La mayoría de los lenguajes seguros detienen el programa cuando falta memoria (OOM)
- SQLite está diseñado para recuperarse normalmente incluso ante OOM, y ese comportamiento entra en conflicto con eso
- Todos los lenguajes seguros existentes son nuevos y cambian rápidamente
- SQLite prefiere lenguajes antiguos y estables
4. Posibilidad de portar SQLite a Rust
- Existe la posibilidad de reescribir SQLite en Rust, pero portarlo a Go es casi imposible
- Motivo: a Go no le gusta assert()
- Condiciones previas para portar SQLite a Rust
- Que Rust madure más y reduzca su ritmo de cambio hasta convertirse en un “lenguaje antiguo y estable”
- Que Rust pueda generar bibliotecas de propósito general invocables desde todos los lenguajes
- Que pueda generar código objeto que funcione incluso en dispositivos embebidos sin sistema operativo
- Que cuente con un ecosistema de herramientas que soporte pruebas con cobertura del 100% de ramas
- Que ofrezca un mecanismo de recuperación ante OOM
- Que demuestre una implementación a nivel de C sin pérdida de rendimiento
- Los desarrolladores que crean que Rust cumple estas condiciones pueden contactar directamente al equipo de SQLite para discutirlo
5. Conclusión
- SQLite es un motor de base de datos pequeño, rápido y confiable, y las características del lenguaje C encajan con ese objetivo
- Cambiar a un lenguaje orientado a objetos o a uno seguro no ofrece beneficios reales en compatibilidad, rendimiento ni control de calidad
- La simplicidad y estabilidad de C respaldan el mantenimiento a largo plazo y la confiabilidad de SQLite
8 comentarios
Total, es un proyecto que ni siquiera acepta PRs, así que... usan lo que ellos quieren usar.
Si la situación es compacta, no hay un lenguaje que reemplace a C, C++ y Rust. Simplemente no hay muchos desarrolladores que se identifiquen con eso de desarrollar preocupándose por overflow a nivel de bits o por posibles hacks en structs o maps.
El título es demasiado sensacionalista. Si ven el artículo original, trata sobre por qué C es el más adecuado para el desarrollo de SQLite. Ojalá todos se calmen un poco.
¿No, pero incluso el texto en sí fue escrito hace 7 años? Parece que le fueron agregando cosas después y que se actualizó parcialmente en 2025... 🤦
Lo importante es poder hacer ese tipo de juicio de usar un lenguaje adecuado según cada situación de desarrollo; poner un título así, como si un lenguaje en particular siempre fuera bueno, es un nivel de pensamiento de alguien que apenas terminó la secundaria...
Creo que la mayor ventaja de C es que toca directamente la esencia de que “una computadora es una secuencia de bits”. Tiene el atractivo de que, gracias a la filosofía simple de C y al agresivo
reinterpret casting, el usuario casi siempre puede saber a qué código máquina se va a traducir. No es que por ser C se pueda llamar desde todos los lenguajes; lo que se puede invocar es el ABI, y en C simplemente es posible predecir —o se debe poder predecir— qué secuencia de bits entra y sale. También creo que, cuando siempre discutimos sobre la viabilidad de implementación, es importante distinguir si algo es imposible en una máquina de Turing o si es imposible en el lenguaje o framework que estamos usando ahora mismo.Comentarios de Hacker News
No creo que haya que justificar por qué no todos los proyectos o programadores usan Rust o Zig.
En Hacker News y en otras plataformas hay una tendencia a empujar demasiado esos lenguajes.
Si con C ya se están logrando buenos resultados y los usuarios están satisfechos, no hay razón para que desde afuera se ande opinando de más.
Es normal que a la gente interesada en el avance tecnológico le atraiga explorar el potencial de los nuevos lenguajes.
Aun así, aunque desde afuera exista la libertad de opinar, los proyectos no tienen la obligación de escuchar.
Rust reduce la exposición a bugs, pero ese mismo tipo de bugs sigue existiendo.
Los desarrolladores de C tienden a reaccionar con más sensibilidad ante las condiciones de carrera, y en Rust existe el riesgo de confiarse demasiado en las anotaciones de “seguridad”.
Además, en Rust las correcciones no siempre son simples, así que la carga de refactorización puede ser mayor.
Al final, Rust es un lenguaje interesante, pero no es una solución universal, y no debería imponerse.
Lenguajes como Rust o Zig tienen la intención de alejarse de los patrones tradicionales de programación orientada a objetos.
La POO en algún momento fue atractiva como un marco conceptual que ofrecía una especie de “iluminación”, pero en la práctica muchas veces aumenta la complejidad y perjudica la modularidad.
Igual que es natural usar un taladro eléctrico en vez de uno manual, si existe una herramienta mejor, lo normal es usarla.
Pero también hace falta que evolucionen lo suficiente las herramientas y la capacitación para poder escribir C seguro.
Soy un Rustacean bastante serio, pero no creo que sea razonable reescribir todos los proyectos en Rust.
Si se migra a Rust un proyecto en C que ya está bien probado, a corto plazo incluso puede haber más bugs.
Aun así, algunos están intentando reescribir partes en Rust; por ejemplo, está Limbo: un proyecto que reescribe SQLite por completo en Rust.
Una de las grandes ventajas de SQLite es que varios procesos pueden acceder a él al mismo tiempo; si eso desaparece, su campo de uso se reduce bastante.
Pueden crear su propia versión y probar por cuenta propia si tiene éxito o no.
Tuve experiencia migrando RediSearch a Rust.
Eso fue porque últimamente había muchas vulnerabilidades CVE.
Si SQLite no tiene ese tipo de problemas, entonces hay menos motivos para moverlo a Rust.
Creo que harán falta décadas para entender de verdad las fortalezas y limitaciones de Rust.
En particular, la utilidad de Rust en las aplicaciones GUI todavía no está clara.
Para que Rust alcance un nivel similar de confianza, quizá tenga que llegar alrededor de 2040.
Como mencionó Linus, Rust necesita un mecanismo de recuperación ante OOM (Out of Memory).
Se puede ver más sobre esto en el enlace a la discusión en LKML.
malloc.En código embebido o de kernel, incluso se puede desactivar por completo la funcionalidad de asignación.
Es decir, Rust ya ofrece control total sobre la memoria.
La afirmación de que “no existe un lenguaje de propósito general más rápido que C” es una comparación parcial que ignora el tiempo del desarrollador.
En vez de tardar 5 horas en hacer con C un programa que corre en 4 segundos, puede ser más realista hacer en otro lenguaje uno que corre en 5 segundos pero está listo en 5 minutos.
Cuantos más usuarios haya, más valor acumulado tienen incluso pequeñas diferencias de velocidad.
A Rust todavía le falta bastante para convertirse en un lenguaje “aburrido y estable”.
Mientras que C es administrado por un comité conservador que cuida con rigor la compatibilidad, Rust prioriza la innovación por encima de la compatibilidad para resolver problemas.
Código de versiones viejas puede seguir compilándose con compiladores nuevos.
Me parece un enfoque mejor que el de C++, que sigue cargando con funcionalidades del pasado.
En cambio, lenguajes diseñados por comité, como C++ o Common Lisp, aumentaron su complejidad.
Rust también es grande, así que conviene usarlo con cautela en sistemas embebidos o sistemas críticos.
Coincido con la actitud de “si algo funciona bien, no hay que romperlo porque sí”.
La historia de la evolución de los lenguajes parece una repetición constante del proceso de resolver problemas para luego crear nueva complejidad.
C es un caso representativo de la filosofía de “Worse is Better”, y tuvo éxito durante décadas gracias a su simplicidad.
Rust, en cambio, apunta al “Right Thing™”.
Hoy, como en la mayoría de los entornos la carga de implementar todo manualmente ha disminuido, ahora puede ser una mejor opción.
Pero no hace falta mover a la fuerza proyectos que ya tuvieron éxito.
Si es un proyecto nuevo, es muy probable que Rust sea una mejor elección.
La simplicidad y estabilidad de C son ventajas subestimadas.
Me parece mejor pulir la biblioteca estándar o el ecosistema que seguir cambiando el lenguaje en sí.
No solo importa la simplicidad, también es importante la garantía de comportamiento determinista.
Por ejemplo, me gustan características como designated initializer, compound literal,
alignasymemset_explicit.Personalmente, sigo pensando que C sigue siendo lo mejor.
Rust tiene muchas buenas ideas, pero también es un lenguaje con desventajas muy claras.
Todavía hay un ambiente en el que es difícil discutir con frialdad los problemas de Rust.
Por ejemplo, podrían mencionarse cosas como la curva de aprendizaje o la complejidad del empaquetado.
Ya no es cierto eso de que “todos los sistemas pueden llamar bibliotecas en C”.
Rust y Zig también cumplen con ese requisito.
Aun así, la biblioteca estándar de Rust muchas veces hace panic en vez de recuperarse ante OOM, y además la documentación es insuficiente.
extern "C"oexportpara tener compatibilidad con la ABI de C.De lo contrario, la ABI no está definida y puede ser incluso más inestable que C++.
En especial, este problema puede hacerse mayor en distribuciones Linux que distribuyen crates de Rust.