RubyKaigi 2015

Introducing the Crystal Programming Language

http://rubykaigi.org/2015/presentations/leinweber

Developer happiness is what brought me to Ruby in the first place. And of all the new compiled languages, Crystal is the only one that shares this value. The syntax and idioms are entirely Ruby inspired.

Although Crystal looks very similar to Ruby, there are big differences between the two. Crystal is statically typed and dispatched. While there are no runtime dynamic features, the compile-time macros solve many of the same problems.

In this session, we’ll take a close look at these differences as well as the similarities, and what Ruby developers can learn from this exciting language.

RubyKaigi 2015

00:00:00 Hello everyone, I'm going to talk a little bit about the Crystal programming language. Before we really get started, let me share a little bit about my background. I've been doing Ruby for maybe ten years now. So, if there are any Ruby contributors or committers in the audience, thank you very much! Without Ruby, I probably would not be a programmer.
00:00:10 In college, I was engaged in something different, but attending the second RailsConf and meeting the people there significantly impacted my career path.
00:00:39 Now, regarding Crystal, I've been using it for a little while now. It’s a programming language that is very similar to Ruby, and I even wrote a PostgreSQL driver in Crystal. I have also been contributing somewhat to the language, the standard library, and the compiler, with most of my commits being to the standard library.
00:00:51 In this talk, we will cover what Crystal is, how it's similar to Ruby, how it's different, and why I find it exciting. I tend to avoid new technologies; I really like PostgreSQL which has been around for over 20 years, and Ruby has also been around for quite a while. It's rather unusual for me to like Crystal since it's so new.
00:01:06 So, what is Crystal? It’s a programming language that shares a syntax and semantics with Ruby but operates as a compiled language, utilizing LLVM to handle all of the heavy lifting of compilation and optimization. In Crystal, all types are completely static, and all method dispatch is also static. This means there's no runtime dynamism or metaprogramming, but the type system is very user-friendly and doesn’t feel like a hindrance.
00:01:37 Using Crystal still feels very much like using Ruby. Additionally, because it has a very nice macro system, I can efficiently push my typical Ruby metaprogramming tasks to the compile step without feeling like I’m losing the flexibility Ruby provides.
00:02:05 The resulting programs in Crystal tend to be very fast, mainly due to the advancements made by the LLVM team. Another aspect of Crystal that I find particularly interesting is how easy it is to link against C libraries. We will explore that later.
00:02:47 To give you a quick timeline of how Crystal has progressed: the first public commit was in 2012, which included a number of foundational components such as the lexer and the parser. By 2013, Crystal became self-hosted, meaning the entire standard library, compiler, and parser were rewritten in Crystal itself. Initially, the language started out as Ruby that generated LLVM instructions, but it evolved into a standalone language.
00:03:15 Later, they added the Boehm garbage collector, which is a conservative garbage collector. While it's doing an acceptable job, I expect it might be replaced in the future. In 2014, Crystal had its first official release, and earlier this year, there was a substantial update that transitioned all I/O to be event-driven, significantly improving performance for web services.
00:03:43 Currently, we are on version 0.91, and things are looking pretty stable and promising. Now, let’s explore the similarities between Crystal and Ruby, as everyone here is likely a Ruby developer, so much of this will seem very familiar.
00:04:12 Here we have various features in Crystal that align closely with Ruby: we have range syntax, methods in the standard library for converting ranges to arrays, and similar methods for sorting and filtering collections, among others. The code works in both Ruby and Crystal identically.
00:04:45 Crystal adopts the same style of object-oriented programming as Ruby; you have classes, initializers, and implicit return values from methods, eliminating the need for an explicit 'return' keyword.
00:05:06 Furthermore, classes are open, meaning you can reopen them and redefine methods. This is particularly beneficial when tinkering with the standard library, as it allows you to modify aspects of it directly, without incurring any performance penalties.
00:05:42 For instance, I experimented with the hash table implementation, adjusting its internals to increase the number of slots and optimize performance.
00:06:05 In general, Crystal supports modules, allowing you to extend and include standard libraries in a manner very similar to Ruby.
00:06:32 Its syntax closely mirrors Ruby, maintaining familiar idioms. This enables you to express constructs like "do something unless" or use ? methods to indicate boolean responses, similar to Ruby.
00:07:00 Crystal includes an integrated testing library that resembles RSpec, complete with runners to execute tests, which enhances the overall development experience.
00:07:24 One of the most interesting realizations I had while working with Crystal was that, despite its superficial similarities to Ruby, I could transfer all of my knowledge about structuring Ruby programs directly into Crystal.
00:07:58 Understanding where to place code, how to organize files, and breaking classes into manageable sections became effortless in Crystal, thanks to its familiarity.
00:08:56 However, while Crystal seems similar to Ruby, it is much more than just a compiled version of Ruby. There are significant differences—some subtle and some more pronounced.
00:09:37 For example, in the standard library, we have started to eliminate aliases. In Ruby, you could refer to the size of an array in various ways like size, count, or length, but in Crystal, we have standardized it to just size. Similarly, for mapping functions, we only maintain the map method, without the collect alias.
00:10:10 Another notable difference is how character strings and immutable strings are handled, as Crystal requires double quotes for strings while single quotes are reserved for characters.
00:10:43 Additionally, string manipulation leads to the creation of new strings rather than modifying existing ones, contrasting Ruby's handling.
00:11:03 In Crystal, instead of using accessor methods, we define getters and setters through properties, making for an elegant solution that retains similar functionality.
00:11:39 In the initialize method, there's a common pattern to assign arguments directly to instance variables by prefixing them with an @ sign, which automatically declares and sets the variables.
00:12:12 String interpolation in Crystal is intuitive, and it is optimized under the hood to enhance performance.
00:12:49 The compiler knows the instance variables and their types even without upfront declarations, ensuring that results are efficient and straightforward.
00:13:16 A medium-level difference in Crystal is how symbols work. While Ruby uses symbol-to-proc, Crystal utilizes a period instead of a colon, following a more concise approach.
00:13:48 When you want to string methods together, it results in cleaner code without breaking into lengthy blocks.
00:14:15 The most significant difference between Crystal and Ruby lies within the type system. To illustrate, if I define a method that multiplies an argument by 2, passing in both an integer and a string will generate two separate versions of the method.
00:14:52 This illustrates how, even though I don’t explicitly specify any types, Crystal can infer method behaviors based on argument types. This can lead to situations where the return type is a union of the different possible types, such as string and integer, based on input conditions.
00:15:31 In cases where the program expects a specific type, such as integer, there are methods to cast values at runtime, dropping other types from the union.
00:16:00 To ensure performance, the compiler generates methods according to the types expected, preventing unnecessary computation or reflection that might exist in other languages.
00:16:44 Crystal also allows defining abstract classes and methods. By marking a class as abstract, you prevent its instantiation but require subclasses to implement specific methods, promoting structured and clear design.
00:17:24 The macro system lets you achieve many of the features from dynamic languages while maintaining compile-time optimizations. For instance, a macro can be used to define getters elegantly, and such defined methods incur no performance penalty.
00:18:08 One of the interesting capabilities of the macro system is to execute shell commands during the build process, allowing you to incorporate external data directly into the compiled program.
00:18:43 For instance, you could run a command to fetch the current date and time, thereby embedding dynamic information directly in the executable.
00:19:02 Returning to the ease of linking against C libraries, this aspect simplifies the process of creating functions that require interaction with external systems. I find that the brief lines of code neatly accomplish complex tasks.
00:19:43 For example, my PostgreSQL driver configuration in Crystal requires minimal setup, allowing me to execute a query and print the result efficiently.
00:20:17 Crystal has made linking against libraries like libPQ straightforward, enabling seamless integration with your local database.
00:21:02 Analyzing regular expressions, Crystal facilitates compiling them nicely, which is a crucial function that eliminates the need for manual type management.
00:21:47 The compiler's steps also allow for automatic performance tracking, ensuring smooth execution through efficient parsing and optimization steps.
00:22:25 When compiling with the release flag, you enable numerous LLVM optimizations, drastically improving executable performance. Benchmarks demonstrate substantial performance gains in JSON parsing and overall execution times.
00:23:12 Given Crystal compiles directly to LLVM, debugging tools provide precise information regarding your methods, unlike Ruby which often obscures method names behind VM operations.
00:24:03 Installing Crystal is straightforward, especially on OS X through Homebrew, while other platforms may vary in requirements.
00:24:50 I could cover many other features, such as the hierarchy tool and features akin to Go's concurrency model, though currently, it supports concurrency without parallelism. However, this will be expanded in future releases.
00:25:24 The built-in package manager facilitates dependency resolution, integrating seamlessly with GitHub projects.
00:26:02 I am open to any questions you might have after the talk, but thank you very much for your time!
00:26:26 Does anyone have questions?
00:26:30 Are there any web frameworks for Crystal, and when do you expect version 1.0 to be released?
00:26:46 There are two known web frameworks; one is called Moonshine, more akin to Sinatra, and the other is Amethyst, which resembles Ruby on Rails. Both frameworks are still developing as the entire ecosystem is quite young. As for version 1.0, I'm uncertain when it will arrive.
00:27:52 The core contributors are refining the compiler to enhance the performance of larger programs. As these updates are implemented, we’ll see better speed in the future.