This post was originally published on my blog
Imagine a programming language with the ergonomic syntax of Ruby, the speed of execution of C, the concurrency model of Go, and last but not
least, a compiler that performs null checks at compile time. Sounds like
a dream? Well, this language exists, but chances are, you haven’t heard of it so far.
Crystal is all of the above, plus it has types, outstanding documentation, and a strong community, delivering a steady stream of new libraries (a.k.a “shards”). Don’t get fooled by the current version number (0.32.1). Crystal has been around for quite a few years (since 2012) and has a mature set of language features and an ecosystem of good libraries.
Where does the speed come from?
Crystal produces fast and lightweight native applications using the LLVM infrastructure. When I say fast, I mean, really fast. Take the fastest Go code you can find and chances are, the same code in Crystal will perform at least on par with it, and often quite a bit faster. Measuring Crystal’s performance against that of Ruby makes no sense.
There are no runtime frameworks or virtual machines necessary. One can just grab the compiled binary and deploy it. When compared with deploying and running a Ruby application, this feels like a whole different league.
Note that there are some caveats, which I am going to discuss in a future blog post. For now, let’s just say that building and distribution are equally as easy, as those in Rust. As of yet, nothing can beat the Go compiler speed-wise, but my experience with the Crystal tooling has been more than pleasant so far.
One of the things that make Go so interesting is its concurrency model. The idea about goroutines that communicate via channels is based on an approach dating back to the late 1970s, called Communicating Sequential Processes (CSP). Crystal uses an analogous approach. Programs run in what is known as “fibers”. The main fiber can spawn any number of concurrent fibers that send and receive data via blocking channels.
channel = Channel(Nil).new spawn do puts "Before send" channel.send(nil) puts "After send" end puts "Before receive" channel.receive puts "After receive"
Why re-invent Ruby in 2020?
The creators of Crystal obviously didn’t intend on changing the world of programming by creating a new language. They just loved Ruby and felt it sad to leave it for a more performant and type-safe alternative. Due to a series of trade-offs at the implementation level, Ruby is still slower and more memory-hungry than its competitors. Despite perfectly serving the needs of a large segment of Web users through Rails, its performance puts it at the back of the pack, when it comes to other use cases.
The point is fair and valid. As a language, Ruby has a concise and elegant syntax for writing. Once beyond the basic idioms, writing Ruby evokes pure joy. Crystal brings that joy to an even higher level through type-safety, native speed, and extremely simple concurrency model.
Don’t get me wrong, I like Go too, precisely because of its verbosity and lack of idioms. When working with others on a big project, I’d prefer more ceremony and hoops, in the name of transparency and equal code comprehension. Different languages exist to serve different purposes and be used by different groups of people. The trick is knowing when to use and when the other.
So, is Crystal worth having a look?
Absolutely! If only to know that it exists and keep an eye on it, I’d go check it out and write a few applications with it. Whether Crystal will take off in the future is a bit more difficult to say, however. As mentioned, the 99% resemblance to Ruby is nice, and so is the blazing-fast performance. Yet, I am missing the Crystal community’s drive towards more prominence. There has been a long-awaited move towards a 1.0 release, which is a crucial milestone and would surely bring in many newcomers. To my understanding, the language and its tooling are stable enough for a 1.0 release.
I understand that Crystal does not have the backing of either Google or Mozilla. Neither does it have multi-billion-dollar use-cases to put on its home page. I understand that fighting for the same space with Go, C/C++, and Rust is an unfair battle. Yet, I also believe that we’re long past the days when choosing one technology over another was a zero-sum game. All it needs is a little push.
I am hoping for the best!
Latest comments (6)
I think it great though far as I know you can't do alot with Ruby...Well you can BUT it seem Crystal may be something to learn once I learn more about coding.
TLDR; It's all preferences, software engineering in technology and language take years or more than a decade to mature, and immature language can take years to train and adopt. The problem now we have the cloud, IoT, incredible computing power in our hands. If the tools slow devs down and you can afford to take a coffee break, go ahead. If not, choose any fast language (performance/productivity) to get the jobs done for a short-term goal then migrate to performant language with careful planning, and that's not jump ship from Ruby to Crystal just because they have familiar syntax, faster performance "comes with a cost", compiling time/project size vs hardware/productivity vs code quality/bugfix.
Frankly, I choose Go because I see major problems with "opinionated" web frameworks, that is the my main reasons why Go is successful.
Definitely, Crystal and other folks will use their favourite web frameworks which in my case is nightmare for website upgrades, I like to adopt different architecture. It's different in every cases and could be delight for your products.
I guess even the Crystal core team need years to get those feature done because the community aren't expert in developing complex solutions that only software engineering knows how to, another problem with the "communication", see how Crystal and Go differ in each other.
So I move away from PHP to Go.
I'm new to coding... But " opinionated " means they have one way to do things right? I liked Ruby but as I learn more I can see some problems. Currently I'm learning Rails and Middleman. So I can be able have it as a option for work. But I just started learning Lua as my main lang for my personal growth I think it's alot better than Ruby and JS. I plan to look at GO in a year or so or should I just stop Ruby and take a look at GO now?
It can be one way but you can extend with your code or helpers (roll our own utility).
We don't advice which language you should stop, the more you learn to know the differences between each language, the better you can gain from untyped aka dynamic and typed languages. Your motivation will decide.
My experience in Go, you will need to understand each API a little more deep by reading books, history of Go issues in Github repo (important to know going on and the progress in the past few years) and Go documentations (It can be confuse but clear when you read a few times). Always experiment with your own code, take the authors' benchmark with a piece of salt (outdated benchmark)
If you have doubts or issues in general with Go usage or style, post in Go forums or reddit.
Still no true parallelism, right? That’s the main thing I was waiting for before committing a project to it. If I’m going to use a compiled language it’s really an essential feature. In a world with all these awesome new languages it really need it for me to dedicate time to it.
Yes and no. There has been some serious development towards being able to spawn fibers across multiple threads. As of 0.31.0, it is available for use by adding a special build flag: crystal-lang.org/2019/09/06/parall...
While this presents a great opportunity to tackle all the available CPU cores with no code changes, there are some caveats. There is a lot of scheduling and mutex locking happening under the hood to ensure that data is accessed in a deterministic manner. This however might come at a cost in many situations, where locking starts dominating the CPU time (as it can be seen in the benchmarks).