go lang bumper

«Go, Rust, C++, C#, Java…¿Qué lenguaje me gusta más?» (parte 4 – Go)

De nuevo vuelvo a la carga con una nueva entrega (y ya van 4) de nuestro análisis de los lenguajes de programación más populares hoy en día. Después de varios posts analizando lenguajes como C/C++, C#, Java/JavaScript y Rust, en esta ocasión le toca a Go.

Como siempre, primero un poco de historia acerca del lenguaje. Como en el caso de Rust, Goes un lenguaje de programación que aunque pueda parecer joven, lleva desde 2009 entre nosotros, siendo ese el año en que por primera vez apareció publicado como proyecto «open source» en Google. La primera versión oficial (1.0) consta de 3 años después, alrededor de 2012, y desde entonces se han publicado 13 «dot versions«. Desde sus inicios fue un lenguaje apadrinado por Google y sus creadores (Robert Griesemer, Rob Pike, y Ken Thompson) decidieron crear el lenguaje para aumentar la productividad de los desarrolladores, y también porque no les gustaba C++ (¡¡¡anatema!!!)

Premisas de diseño

Entre las premisas principales (exceptuando la animadversión a C++) que dirigieron su diseño e implementación estaban las siguientes:

  • Lenguaje altamente productivo desde el punto de vista del desarrollador y adaptado a una época de sistemas interconectados y con capacidades de multi-procesamiento
  • Cercano en rendimiento a lenguajes a un nivel un poco mas bajo como C
  • Combinando las características de productividad de los lenguajes de «tipado» dinámicos con la seguridad de los lenguajes con tipos estáticos
  • Aportando una visión nueva y fresca (sic) en características como la orientación a objetos o el multi-proceso
golang mascota gopher

Características principales

Vamos a resaltar las principales características del lenguaje Go:

  • Sintaxis «curly bracket» por tomar como origen la sintaxis del lenguaje C (sí, empiezo a ver un patrón común en todos los lenguajes analizados hasta ahora), pero curiosamente prescinde de los puntos y comas como delimitadores de las sentencias. También omite en algunas construcciones los tradicionales paréntesis (por ejemplo en las instrucciones «if» y «for«)
  • Compilación nativa con «linkado» estático optimizada para que el proceso sea tremendamente eficiente
  • Uso de «garbage collector» y asignación automática de memoria, pero curiosamente mantiene el concepto de punteros (aunque no con la misma orientación y uso que en su lenguaje inspirador, C)
  • Orientación a objetos utilizando «struct» e «interface«, pero no clases (en este punto me ha recordado a Rust pero con aspectos diferentes al mismo tiempo) y un mecanismo de implementación de interfaces mas «relajado» que en otros lenguajes OOP más tradicionales
  • Manejo de errores pero sin usar el mecanismo de las «excepciones» (de nuevo cierta similitud con Rust y su manejo de errores)
  • Soporte para closures, funciones anónimas y un curioso generador de secuencias de constantes llamado iota que aparte cierta nota curiosa no aporta gran cosa (desde mi humilde opinión)
  • Uso de valores nulos («nil«) en contraposición a Rust por ejemplo
  • Incluye soporte para tuplas y «slices«
  • No soporta «generics» cosa que le ha valido amargas críticas en contra
  • Incluye de serie un conjunto de mecanismos para facilitar la programación concurrente (las famosas «goroutines«, los «channels» y la construcción «select» que sea dicho de paso están muy chulos, pero la gestión de esa concurrencia no está soportada por el SO que está por debajo sino que es el propio «runtime» de Go quien la gestiona.
  • Utiliza «packages» como método de gestión de módulos de código y además éstos pueden ser locales u «online«
  • Incluye mecanismos para «string templates» así como notación/decoración específica para serializar estructuras de datos en JSON que son curiosos
  • Complementado por una «standard library» que cubre las necesidades básicas de cualquier proyecto software

Os dejo a continuación unos snippets de código para que os hagáis una idea de que aspecto tiene el código fuente en Go.

package main
 
import (
   "fmt"
   "time"
)
 
func main() {
   fmt.Println("Hello World!")
   for i := 0; i < 10; i++ {
      go myThread(i)
      time.Sleep(100 * time.Millisecond)
   }
}
 
/*
 * This is an example of a Goroutine. It's easy to program just in case
 * you don't need to share data between instances of it. If you need that
 * then there are mechanisms for doing it
 */
func myThread(id int) {
   fmt.Println("I'm goroutine ", id, " starting to work!...")
   for i := 1; i < 10; i++ {
      fmt.Println("Goroutine ", id, " iterating ", i)
      time.Sleep(150 * time.Millisecond)
   }
   fmt.Println("Goroutine ", id, " leaving for home")
}

Paso ahora a hacer unos comentarios sobre los aspectos que más me han gustado y también los que menos he apreciado.

Consideraciones

Puedo decir que su sintaxis, recordando mucho mucho a un C «modernizado», junto con la eliminación de los puntos y comas y otras sutilezas le permite a los recién llegados al lenguaje ganar familiaridad con él muy rápidamente. Eso sí, los «if» y «for» sin paréntesis al principio resultan chocantes. La declaración de variables y parámetros de funciones dejando el tipo de los mismos al final de la declaración me resulta más natural a la hora de leer código. Incluso la declaración de arrays me parece mas intuitiva a como venía siendo habitual.

La declaración de variables con tipado dinámico utilizando «:=» me retrotraía a mis tiempos mozos con PASCAL (!¡) pero es cierto que el incluir este tipo de construcciones parece un «must» en lenguajes más modernos. No tengo muy claro qué aporta la construcción de los punteros en el lenguaje, puesto que la asignación y liberación de memoria la hace el compilador mediante su garbage collector. Quizá yo hubiese utilizado el mismo mecanismo pero con la sintaxis de referencias «&» de C++ por ejemplo. También la función «new()» me hace dudar de su utilidad práctica.

Que no exista una construcción sintáctica para gestionar la visibilidad de las funciones o los miembros de un objeto y eso se realice por convenio de nomenclatura (los elementos públicos siempre han de comenzar por una letra mayúscula) es también curioso pero cuando te acostumbras, simplifica mucho el código.

Creo que se le ha dado mucho pábulo a su supuesto soporte para el multi-proceso, y las construcciones como los «channel» o la sentencia «select» están muy bien, pero creo que las «goroutines» no aportan gran cosa (sintácticamente) y el hecho de que no estén soportadas por debajo por el SO hace que dude de su supuesta «ligereza» a la hora de ejecutar.

En resumen, si bien al principio iba con ciertas reticencias debido a las ambiciosas premisas de partida del lenguaje, y también porque en la actualidad hay mucho desarrollador de Go abanderando el lenguaje, he de confesar que me ha resultado un lenguaje interesante, divertido y familiar con el que trabajar. Sencillo de empezar a dar los primeros pasos y muy en boga en los desarrolladores de «backoffice«, especialmente cuando hablamos de microservicios. No aporta tantos cambios de paradigma como pueda hacer Rust pero sí que considero que podrá ser un lenguaje de «cabecera» en un futuro cercano. Está actualmente en la posición 19 del índice TIOBE (ha bajado 5 posiciones desde el año pasado) y es uno de los 5 lenguajes más «amados» en el informe de Octoverse 2018 -me refiero a los que más «corazones» ha recibido de los contribuyentes en GitHub-. En resumen, un lenguaje a tener en cuenta si pretendéis aumentar vuestro acervo de conocimientos.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.