00:00:16.440
My name is Kirk Haines. My day job is as a developer relations engineer for.
00:00:22.320
Parity Technologies, but I've been doing Ruby for a long time—more than 20 years. Today, we're going to talk a little bit about Crystal, and specifically, Crystal for Rubyists.
00:00:27.599
What that means is: what does Crystal look like? What is it? And how can you leverage your existing Ruby knowledge to be productive more quickly with Crystal? The first part of this will be somewhat like a talk, as I would like to give an overview of various topics.
00:00:39.420
However, it won't be a typical talk in the sense that I will hold questions till the end. If you have anything to ask, or you want to discuss something that appears on the screen or anything I say, feel free to interrupt me. Let's engage in conversation and see where this goes.
00:00:50.399
The entire slide deck, along with some code used in some of the slides, examples, and a few exercises, are all available on GitHub. You can access this through the QR code. If the QR code is too small for your camera to read, you can grab the URL here to go to it. If you want to download it to your laptop to follow along directly, you're welcome to do so.
00:01:01.680
I'll give you a moment to grab that, and then we'll move on.
00:01:08.000
While we're waiting, let me ask: who here knows what Crystal is? Quite a few of you; cool! Now, who here has actually written a line of Crystal before? Okay, cool!
00:01:18.659
It's sometimes kind of surprising to me how much Ruby code will simply compile with the Crystal compiler because the syntax is so similar. There are a lot of similarities.
00:01:31.379
If you need me to go back to that QR code, let me know. But otherwise, let's talk a little about why Crystal. We're all here because we like Ruby, and many of us have been using Ruby for a long time.
00:01:39.420
There are many benefits to Ruby, and you can make a pretty exhaustive list of them. This is just a few quick ones that many people tend to agree on: the blocks, the user-friendly syntax, and the fact that Ruby is a very versatile language. You can use it for a lot of different things.
00:01:51.480
Ruby has some interesting writing mixed with functional programming, which enhances its usability and versatility. One thing that honestly drew me to Ruby initially is dynamic typing. Most of the time, you don't really have to worry about what type the variable is; you let Ruby figure it out and tell you if you made a mistake.
00:02:07.260
Ruby also has a robust set of tools built around it, along with a strong testing ecosystem that supports developers in structuring their projects and makes them easier to work with.
00:02:25.980
However, there are some drawbacks to Ruby, and I know we can debate some of these points, but generally, if you’re trying to distribute a Ruby program or binary, it’s really difficult to do.
00:02:35.400
There have been some projects aimed at addressing this issue for quite a long time, but none have ever really taken off or dominated the space, as it’s a really tough problem to solve due to the many dependencies involved in Ruby code.
00:02:45.840
You can write applications in M Ruby, which is a language that resembles Ruby. However, it’s not directly Ruby due to some significant differences, and it will compile into an executable. But you can’t just take your Rails app and turn it into an M Ruby executable.
00:03:01.020
Ruby's performance has always been a topic of discussion. With Ruby 3, performance has significantly improved, but nobody writes Ruby to be a lightning-fast 3D rendering engine; that’s not why we use it. Its performance is relatively mediocre.
00:03:12.000
Additionally, concurrency in Ruby is interesting due to the different approaches available. You've got fibers, threads, reactors, and evented systems, which can make managing concurrency a bit of an adventure at times.
00:03:23.160
Static type checking was introduced in Ruby 3, and arguably a little before that, due to the Sorbet project. Ruby 3 includes RBS for static type checking; you can use it to determine type-related errors, but it’s more of a bolt-on solution and has its limitations.
00:03:30.960
It’s not entirely fluid to use RBS while writing code.
00:03:35.880
These are some drawbacks that Crystal addresses. Crystal is syntactically extremely similar to Ruby. If you look at this code snippet, the first example is Ruby, and the next is Crystal; the only difference is that in Crystal, when declaring an array, you need to specify the type of data it will store.
00:03:47.630
The typing information adds just a bit of extra syntax, which you can see in the last line where it specifies 'Array(Int32)'. That's the only significant difference.
00:03:58.300
Crystal is a compiled language that compiles your code into an executable built on top of LLVM. Anyone here use Rust? Well, Rust compiles down to LLVM, too, creating a shared foundation between the two.
00:04:08.400
This is just a snippet that shows that building something with Crystal results in an ELF executable on my system. The compiled binaries are also fast to execute.
00:04:19.680
In the GitHub repository available through that QR code, there's a folder called 'fib bench' that contains four implementations of a simple Fibonacci calculator. It calculates Fibonacci numbers recursively.
00:04:31.800
On my laptop, these are the timings for those implementations. You can see that Rust is a bit faster, but Crystal outperforms everything else by a substantial margin. In this case, I calculated the 42nd Fibonacci number.
00:04:40.440
If I go beyond that on my laptop, Ruby becomes exceedingly slow. Conversely, if I choose a smaller number, everything happens too quickly.
00:04:51.300
Crystal provides solutions to some challenges while retaining versatility and productivity, all with a syntax similar to Ruby.
00:05:02.160
If you don't have Crystal installed on your system and you're interested in doing so, it's pretty easy. During our session, if you'd like to play around and ask me questions, go to crystal-lang.org/install for guided installation instructions for your operating system.
00:05:12.360
If you need a moment to grab that URL, I can wait.
00:05:17.460
But remember, if you want to experiment without installation, you can use play.crystal-lang.org. It's a browser console where you can write and run code.
00:05:27.060
Next, I'll quickly summarize the differences between Ruby and Crystal at a high level, but feel free to interrupt with questions as we proceed.
00:05:36.060
While Crystal looks a lot like Ruby—which is true, given that a lot of Ruby code compiles with the Crystal compiler—it also has significant differences.
00:05:46.500
Crystal is a statically typed compiled language, lacking many of the dynamic features that Ruby possesses. For instance, there’s no eval or send in Crystal; while it’s possible to achieve similar functionalities through other mechanisms, those methods do not exist in Crystal.
00:05:57.779
Consider that it's not merely a variant of Ruby; it's a distinct language that leverages Ruby concepts extensively.
00:06:06.899
Importantly, Crystal's similarity to Ruby arises from its history: the original Crystal compilers were built with Ruby, and the goal was to create a compiled language that feels and looks like Ruby, but is compiled and fast.
00:06:21.300
To clarify the first distinction: Ruby is interpreted, while Crystal is compiled. However, an interpreter for Crystal is currently experimental.
00:06:30.060
You can actually run a large subset of your Crystal code as interpreted code.
00:06:39.180
While Crystal is dynamically typed, Ruby is dynamically type-checked, meaning the Ruby interpreter checks the types of your data at runtime.
00:06:50.820
Any mismatches become apparent only when you run your code, whereas Crystal is statically type-checked, ensuring type correctness before compiling.
00:07:00.060
Ruby does include static type-checking through RBS or Sorbet, but it is not integrated directly into the language.
00:07:09.600
Here's a quick example: in Ruby, if you try to add a string to a number, you get a type error.
00:07:14.220
Doing the same thing in Crystal will also yield an error, but it will occur at compile time, providing an explanation of what went wrong.
00:07:25.380
Also, Crystal has type inference, meaning it can often deduce the types without needing explicit declaration.
00:07:34.740
For instance, if you have an array defined with strings, Crystal can infer it’s an array of strings.
00:07:45.060
In cases where types are ambiguous, you would still be required to explicitly define the type.
00:07:54.500
For instance, in both languages, you have flexibility. If you don't declare any types, it will work similarly in both Ruby and Crystal.
00:08:06.020
Crystal, having been inspired by Ruby, retains many identical method names so that a lot of code functions similarly across both languages.
00:08:15.600
For example, the code here will work the same in either language, except when it doesn’t.
00:08:25.740
Ruby has a method called time.now, which doesn’t exist in Crystal. Instead, Crystal has time.local and time.utc.
00:08:34.440
It took me some time to realize that it didn’t work for this reason, which may confuse new users.
00:08:40.800
Similarly, in Ruby the inject method of an array is called reduce in Crystal.
00:08:50.580
Some naming changes are inspired by languages like Go, where the authors feel specific names are more appropriate.
00:09:02.520
In the context of our Fibonacci example, both languages provide succinct ways to compute Fibonacci numbers.
00:09:09.780
The Ruby code example demonstrates that Ruby will automatically cast large integers into BigInts, while in Crystal, we must specify the BigInt from the start.
00:09:20.040
Overall, both codes look very similar, but Crystal requires that extra bit of type information.
00:09:30.600
Another key difference involves concurrency. In Ruby, we have fibers, threads, and reactors, with optional event-based concurrency.
00:09:39.480
With fibers, you manage them manually through declaring them, yielding to them, and resuming. This complicates the code, especially for intricate scenarios.
00:09:50.640
To be more approachable, Ruby offers threads that you can manage via queues, which provides a particular design.
00:10:00.720
In Crystal, the concurrency model mirrors that of Go, using processes and channels which streamline interacting without managing low-level details.
00:10:08.540
This approach allows for easy communication through channels, so you send data in one direction and retrieve it from another, hiding a lot of complexity.
00:10:20.880
You quickly have a coordinated system of processes communicating through these channels, simplifying concurrency handling.
00:10:31.380
Some additional differences: Ruby libraries are referred to as gems, while Crystal libraries are called shards.
00:10:38.640
Similarly, while Ruby has a gem command, Crystal has a shard command. The low-level management of these libraries is a bit different.
00:10:48.840
In Crystal, descriptors are created in a YAML file, which differs from Ruby’s capacity to describe libraries through code.
00:10:57.000
Yet both languages still provide functionalities, allowing you to manage your libraries effectively.
00:11:05.880
Testing is another strong point for Ruby, with a robust testing culture that supports testing libraries such as RSpec and Minitest.
00:11:13.560
Crystal offers a similar built-in testing library called Spec, which closely resembles RSpec and should feel quite familiar.
00:11:22.560
There’s also an implementation of MiniTest in Crystal, effectively ported from Ruby, representing the testing methodologies well.
00:11:32.760
So when it comes to testing in regard to syntax, if you can read RSpec, you can read Crystal's tests.
00:11:42.660
To wrap it up, Crystal is not Ruby, but its syntax is closely aligned, allowing Rubyists to transition comfortably into Crystal.
00:11:55.200
At this point, I am done with my presentation, and it's your turn. We can pair program, discuss topics, or work on exercises.
00:12:04.300
One valuable approach when learning Crystal is to take Ruby code that you're familiar with and rewrite it in Crystal.
00:12:11.400
This can illuminate small differences and sometimes lead to significantly different approaches, highlighting the learning opportunities.
00:12:21.300
One suggestion is to utilize Exorcism, which provides programming tasks that teach individual concepts for various languages.
00:12:31.200
Exorcism has both Ruby and Crystal tracks, allowing you to learn and practice concepts in both languages.
00:12:41.400
Another idea is to take a Ruby program like a dice roller for role-playing games, found in the repo, and implement it in Crystal.
00:12:50.700
In the repo, you'll also find a stub of the Crystal implementation, which would make for an interesting exercise.
00:12:59.400
If you find yourself stuck, a finished version is also available for reference.
00:13:05.400
Ultimately, I'm open to whatever you are interested in discussing, whether questions or collaborative coding.
00:13:13.200
I'll be happy to help, and you can fire away with any questions!
00:13:17.000
One question asked was what features I find Crystal lacking that would lead me to choose Ruby instead.
00:13:25.600
Most projects intended for sustainability can be approached effectively with Crystal or Ruby.
00:13:33.800
When dynamic code evaluation is essential, Ruby may be preferable. Crystal does have macros, providing some flexibility, but the ease of dynamic evaluation is missing.
00:13:43.100
For small, non-critical projects that may not last, Ruby may lend itself better due to its flexibility and lightweight capabilities.
00:13:51.300
As for real-world implementations of Crystal, it’s gaining traction, particularly in web development where robust frameworks exist.
00:14:04.600
A notable project is Place OS, an infrastructure management system widely used in big companies like Cisco and hospitals.
00:14:12.360
There are even gaming development projects leveraging Crystal for its ability to integrate seamlessly with C libraries.
00:14:20.580
In the core development community, discussions are ongoing regarding implementing features borrowed from Ruby and other languages.
00:14:30.240
Crystal's evolution involves innovations like pattern matching, which are broadly discussed for potential inclusion.
00:14:38.160
Regarding class management, yes, you can reopen classes in Crystal to add new methods, similar to Ruby.
00:14:46.920
Interestingly, Crystal itself is implemented in Crystal, allowing for extensions and comprehensive modification.
00:14:55.900
Crystal's community is vibrant, fostering contributions from diverse programmers eager to develop the language further.
00:15:05.600
If you want to continue the discussion or engage in collaborative learning, we still have time!
00:15:13.600
You’re all welcome to mingle, ask further questions, or explore the topic deeper. Thank you all for being here!
00:15:23.200
It’s been a pleasure—thank you!