Imaginate un lenguaje con la potencia de C pero la sintaxis de Ruby. En resumen eso es Crystal, un lenguaje con chequeo de tipos y sintaxis similar a Ruby.
Veamos un ejemplo:
# A very basic HTTP server
require "http/server"
server = HTTP::Server.new(8080) do |context|
context.response.content_type = "text/plain"
context.response.print "Hello world, got #{context.request.path}!"
end
puts "Listening on http://127.0.0.1:8080"
server.listen
Este pequeño ejemplo hemos montado un servidor web con una página de ejemplo.
Crystal tiene chequeo de tipo forma estática, por lo que el compilador detectará cualquier tipo de error antes de que falle en el tiempo de ejecución. Además, y para mantener el lenguaje limpio, Crystal tiene inferencia de tipos, por lo que no es necesario indicar el tipo la mayoría de las veces.
def shout(x)
# Notice that both Int32 and String respond_to `to_s`
x.to_s.upcase
end
foo = ENV["FOO"]? || 10
typeof(foo) # => (Int32 | String)
typeof(shout(foo)) # => String
Los tipos no permiten null y las variables nullable se representan como una unión entre el tipo y null. Como consecuencia, el compilador comprobará automáticamente si hay referencias nulas en tiempo de compilación.
if rand(2) > 0
my_string = "hello world"
end
puts my_string.upcase
Si corremos esto :
$ crystal hello_world.cr
Error in hello_world.cr:5: undefined method 'upcase' for Nil (compile-time type is (String | Nil))
puts my_string.upcase
Crystal posee un potente sistema de macro , que abarca desde la inspección básica de plantillas y AST hasta la inspección de tipos y la ejecución de programas externos arbitrarios.
class Object
def has_instance_var?(name) : Bool
{{ @type.instance_vars.map &.name.stringify }}.includes? name
end
end
person = Person.new "John", 30
person.has_instance_var?("name") #=> true
person.has_instance_var?("birthday") #=> false
Crystal usa hilos verdes, llamados fibras, para lograr concurrencia. Las fibras se comunican entre sí mediante canales, como en Go o Clojure, sin tener que recurrir a la memoria compartida o bloqueos.
channel = Channel(Int32).new
total_lines = 0
files = Dir.glob("*.txt")
files.each do |f|
spawn do
lines = File.read(f).lines.size
channel.send lines
end
end
files.size.times do
total_lines += channel.receive
end
puts total_lines
Crystal tiene una sintaxis dedicada para llamar fácilmente a bibliotecas nativas, eliminando la necesidad de volver a implementar tareas de bajo nivel.
# Fragment of the BigInt implementation that uses GMP
@[Link("gmp")]
lib LibGMP
alias Int = LibC::Int
alias ULong = LibC::ULong
struct MPZ
_mp_alloc : Int32
_mp_size : Int32
_mp_d : ULong*
end
fun init_set_str = __gmpz_init_set_str(rop : MPZ*, str : UInt8*, base : Int) : Int
fun cmp = __gmpz_cmp(op1 : MPZ*, op2 : MPZ*) : Int
end
struct BigInt < Int
def initialize(str : String, base = 10)
err = LibGMP.init_set_str(out @mpz, str, base)
raise ArgumentError.new("invalid BigInt: #{str}") if err == -1
end
def <=>(other : BigInt)
LibGMP.cmp(mpz, other)
end
end
Las bibliotecas de Crystal se empaquetan como fragmentos y se distribuyen a través de Git sin necesidad de un repositorio centralizado. Los comandos incorporados permiten que las dependencias se especifiquen fácilmente a través de un archivo YAML y se obtengan de sus respectivos repositorios.
name: my-project
version: 0.1
license: MIT
crystal: 0.21.0
dependencies:
mysql:
github: crystal-lang/crystal-mysql
version: ~> 0.3.1
Esto es solo un post de muestra. Para empezar de lleno vamos a tener que instalar el lenguaje y luego a estudiar, pero esos serán otros post.
Dejo link:
https://crystal-lang.org/
https://github.com/crystal-lang/crystal/