43 comments

[ 3.6 ms ] story [ 109 ms ] thread
Great writeup for the folks who are curious but lack the time to test Crystal.
Outside of speed benefits as compared to ruby, one of the main things going for crystal is it's ability to use all of the robust tooling that already exists. This post mentions it in passing but Crystal gets the benefit of all the existing tooling without having to build it as part of delivering the language to developers. I think that's a huge win. I also think this is one reason why Crystal has grown fairly quickly. This could largely but due to the fact that it's built upon LLVM. Regardless, the community and documentation is pretty awesome. I can't wait to see what happens for the 1.0 release.
Can you be more specific on what you mean about "existing tooling"?. I work in a Ruby shop and am very curious to try Crystal.
Crystal could be a really powerful tool for enhancing existing Ruby code.

Imagine a world where you write your code in Ruby, but farm out the expensive operations to a Ruby-like Crystal extension (similar to what is commonly done with C or Rust). I think this is possible already (just after a quick Google search[1]), just not friendly for the average Ruby dev to implement.

[1] https://www.slideshare.net/AnnaKazakova/how-to-write-ruby-ex...

Neat. Thanks for posting that. Hopefully, that process could be cleaned up and streamlined as a lot of it would be repetitive boiler plate.
This is definitely possible-- I've done even more than basic PoC (Anna's slide deck was one of my starting points in fact).

https://github.com/phoffer/crystalized_ruby

Sweet. I'm glad to see progress on this already.
This is great, thanks. It seems that it is incomplete, though. What can the community do to support further development?
When I look at Crystal, what comes to my mind is that it is what Ruby could have been if the community had taken Dylan as inspiration in regards to language design and tooling.
70x faster? If Crystal gets its own port of Ruby on Rails, oh boy.
70x faster, with the caveat that the way that Ruby code is written really does not lend itself to speed.

E.g. using method calls inside the class instead of accessing instance variables instantly springs to mind, as does the "unsorted priority queue" which is basically a horrible abuse of Array but wrapped in a class that makes it even slower by adding additional method calls for every operation.

That's not to diminish the speedup Crystal gets, because it does illustrate how slow MRI's method calls are, but it'd be interesting in seeing a comparison with an astar implementation that was actually written to be fast in Ruby.

Also would be very interesting to see a comparison with jRuby+Truffle, of course.

Crystal does the same as ruby for instance variable access, it's just that such methods are such an easy target for inlining by LLVM there's practically no performance penalty. The flexibility of gets and sets simply being method calls is very awesome and very worth it.
It sounds like more substantial semantic differences then, as in the Ruby case the challenge with making it fast is that you can't take shortcuts like that without first verifying that there are no possible calls to any code that can have side effects like making changes to the receiver - you need to be prepared to "deoptimize" the code back to doing full method calls at any point, as in the general case you have no guarantee that the code will remain a simple getter/setter.
Author of the article here. This implementation of A* was me playing around. It is definitely not optimized for either Ruby or Crystal It was merely a chunk of Ruby code that I had lying around. You are right about the unsorted queue being a hack around Array, but it was part of another experiment of using a "Fast Stack"[1] for the A* algorithm. It allowed me to swap in other Queue implementations easily.

The point of the article was merely "How much work does it take to port Ruby to Crystal" The performance differences were just fun to see, not the intent.

If I get time, maybe I'll run this through jRuby+Truffle as a comparison, that would be interesting to see.

[1] https://github.com/SteveRabin/JPSPlusWithGoalBounding

That would definitely be interesting if you run it on the same hardware.
My biggest takeaway from reading this is that Crystal is much more divergent from Ruby than I expected.
In fact being similar to or compatible with Ruby is not a language goal at all.
That's communicated very poorly, when the first thing on the website is "fast as C, slick as Ruby" followed by mentioning how similar the syntax is to Ruby.
I'm getting the impression of a running pattern of argument when talking about Crystal:

Crystalist: "Crystal is very Ruby-inspired. Welcome Ruby devs! What makes Crystal great is it's as fast as alternatives to Ruby, without sacrificing Ruby syntax and functionality! Port over your Ruby code! Crystal is Ruby on steroids!"

Rubyist: "Why does Crystal diverge from Ruby here, here, and here unnecessarily if the goal is to be similar to Ruby and allow porting more easily?"

Crystalist: "Crystal is not Ruby. Crystal has no goal of being similar to Ruby. Any similarity to other languages is purely coincidental. What's Ruby?"

Yes, it feels a bit like a bait and switch to me. I can understand that - I've been tempted to go down the same route myself... But the messaging around it is all over the place.

On one hand, when they explicitly state that the goal is not for Crystal to be as close to Ruby as possible, that makes me more sympathetic.

At the same time it also makes me less likely to use it anytime soon. Not out of ill will - it's an interesting project and I hope they do well - but hardly any of my Ruby code is CPU constrained, so I have little reason to switch for speed. Had they aimed as close as possible, I might have tried anyway, but every little extra difference makes it less worthwhile.

Of course that's very different for people that actually write code where speed is a major concern and that e.g. haven't been able to use Ruby for that reason.

> but hardly any of my Ruby code is CPU constrained,

All of the IO in crystal is async, so even if you're IO bound, crystal is probably a lot more efficient.

I don't know what you mean.

In Ruby, MRI multiplexes over async IO if you use sync IO primitives, and using async IO directly is not a problem.

In any case, most of my code wait on external events (clients, databases) so it's very rare for the Ruby part to be worth optimising. I spend a lot more time doing things like optimising database indexes and the like.

Of course there are plenty of areas where the balance there would be very different.

Firstly I'd like to mention that our messaging probably isn't consistent because it doesn't come from only one person. Crystal is a community and we all say slightly different things.

The message we want to get across about the Crystal is that it is very Ruby-inspired, and that Ruby devs will feel at home. Crystal is often compared to Rust and Go, and the level of abstraction you will see when writing Crystal code will feel much more at home compared to Go and especially Rust. That being said, Crystal isn't Ruby, and you'll have more success writing a project from scratch for Crystal than attempting to port any >10k LOC codebase. Crystal isn't designed to make porting Ruby easy, and it hasn't been for a while. Crystal's goal is to make you as a Ruby developer feel at home, not your code. A lot of people have ported codebases from Ruby and talked about it, but you probably see only the successes, not the failures.

In short, we want you to use Crystal not because it's faster and easy to port to, but because it's simply a better, more robust, modern language.

If the goal is not to be similar to Ruby then what makes Crystal better than Rust or Go? I can understand being compatible ith not being a specific goal.
>what makes Crystal better than Rust or Go

Rust is very much a systems programming language: no GC, no runtime, no overhead. We don't intend to compete with Rust at all.

Go however has inspired Crystal's IO system quite a bit. Crystal looked at Go and saw that CSP was working very well and copied the idea.

Here's some differences:

- Go aims for simplicity, in Crystal it's a bit lower down the priority list in favour of expressability

- Crystal has a stronger, more complex type system than Go

- Crystal has type inference

- Crystal has blocks/yield (with 0 overhead) like Ruby

- Crystal has a more "normal" package manager

I'm confused by why there's so many small things that appears to be pointless differences. E.g. "property" vs "atter_accessor". It'd seem that ease of converting Ruby code is the major selling point, and especially with things like TruffleRuby + Substrate, it seems like it's about to face more serious competition that doesn't depend on rewriting your code nearly as much.
A lot of the differences are based around choosing what is optimal, instead of what is similar to Ruby. Without context, I'd prefer `property` over `attr_accessor`.

As for the effect on porting code, it's still very easy to port code. I ported over ActiveSupport's Inflector module(s), and approximately 75% of the code was untouched, 20% was minor tweaks (i.e. single to double quotes), and 5% required actual changing. It was a rather quick process.

If curious, https://github.com/phoffer/inflector.cr

Without context, "attr_accessor" to me appears closer in meaning to what it actually means in Ruby. Maybe it's meaning in Crystal is sufficiently different to make "property" make more sense. In Ruby, after all, it literally creates accessor methods, it does not create a property.
The idea behind crystal is not to make a faster ruby, but to make a rethought ruby for the modern age: compiled, statically typed and removed of warts.

Crystal should feel familiar to ruby developers in it's syntax and stdlib, but we have absolutely no problems with throwing away ruby's ideas when they are deemed substandard.

Crystal doesn't aim to draw in as many ruby developers as possible, it aims to create the best programming language possible. It just happens to have ruby as a conceptual starting point.

I can understand that, but a lot of the difference to me seem like they make moving code over harder without providing any benefit. For me that makes it substantially less likely that I'll use it, but that's fine.
It seems like Ruby is a bit of a small community to target with this type of thing. Wouldn't Ruby developers be better served by moving on to one of the several other idealistic languages in widespread usage right now? TypeScript is getting good reviews and Python is great.

I know it seems harsh, but when I hear people talk about the "beauty" or "elegance" of Ruby, I just think of someone who started coding in the 2005-2009 era and started out with RoR, which was frequently presented as "the Mac of programming languages" around that time (and this description alone should give serious people pause).

These people got into the scene too late to remember trying to hack Perl, Ruby's own spiritual predecessor, and the pseudo-joke that it was a "write-only language". The two relics that remain from widespread Perl usage are regular expressions and Ruby.

Meanwhile, several other languages that are similar to Ruby in age and/or style have active communities and enjoy an increasing trend of innovation and market penetration. Even languages like Groovy, which have failed to gain a large independent following, continue to benefit from both technical and communal innovation on their underlying runtime platforms.

I don't think I've met many people who looked at Ruby in a time when the hype train wasn't going full steam ahead and came away with the evaluation that it was "elegant" or "beautiful". In fact, many reformed "Rubyists" whom I know are switching to other platforms, and RoR jobs are getting increasingly scarce (supplanted by the next large-scale server-side fad, node.js). Not many people seem to be using Ruby for new projects anymore.

Could you elaborate on why you chose Ruby as a reference point?

> I know it seems harsh, but when I hear people talk about the "beauty" or "elegance" of Ruby, I just think of someone who started coding in the 2005-2009 era and started out with RoR

I started programming in 1981, I detest Rails, and I picked Ruby for its beauty and elegance. I'm a language geek first and foremost; the syntax and presentation of a language is extremely important for my happiness when working with it, and nothing has so far gotten close to Ruby in that respect, and I've worked in more languages than most developers can name.

TypeScript and Python both looks awful to me. Neither are languages I'll work in given a choice. I don't think you'll find many Rubyists who'd consider them viable alternatives - those who have evaluated both and come down on the Ruby side tends to have strong opinions on the matter in my experience.

> In fact, many reformed "Rubyists" whom I know are switching to other platforms, and RoR jobs are getting increasingly scarce (supplanted by the next large-scale server-side fad, node.js). Not many people seem to be using Ruby for new projects anymore.

My experience is the exact opposite. It's easier than ever for me to find work doing Ruby even while avoiding Rails. I'm too expensive to do Rails even I liked it. Yet I regularly find devops consulting gigs and the like where people are happy to find someone with Ruby skills.

If RoR jobs are indeed getting scarce, I suspect that's more an effect of the number of Ruby developers reaching the kind of saturation that PHP developers did years ago.

But these things are also highly dependent on where you look. I rarely come across people asking for node.js for example. Presumably because my network is tilted towards Rubyists.

Can you discuss some of the linguistic edges that you find in Ruby? Personally, I don't understand the attraction. It would help if you could articulate. I've always struggled to see the real merit that Ruby brought to the table.

Usually such explanations are things like "Look at all the esoteric symbols I can pack together to accomplish something on two lines, instead of the readable way that would've used six lines!" IMO, it's better to use a few extra bytes for line breaks, or for explicit wrapping of things like method arguments, and have your code more accessible.

Unless you're engaging in the above-referenced symbolic soup, Python and Ruby code usually end up looking pretty similar. I don't know how you can say that one "looks awful" v. the other.

> Can you discuss some of the linguistic edges that you find in Ruby?

Ruby is close to Smalltalk, but with an Algol-family syntax that goes to painstaking lengths to make visual clutter optional while being familiar.

There's nothing really new in Ruby in terms of semantics. What Ruby did was fuse a number of language concepts into something that reads well. Syntax is the primary linguistic edge of Ruby.

We get the dynamism of Smalltak, in a more familiar packaging, that then goes to extremes to try to let you strip out ceremony.

This to me contributes to compact but readable code. Outside of golfing, the Ruby community values readability very highly, and syntax is a big part of that.

A typical example is the block sytax, which seems trivial on the surface, given that it is just a very thin veneer over the lambda syntax. To give a (very) contrived example:

Ruby's "full length" lambda syntax:

    def foo l
      print "Hello "
      l.call
    end

    foo ->{puts "World"}
The block syntax:

    def bar
      print "Hello "
      yield
    end

    bar { puts "World" }
The first thing to note is that the full length syntax has become very compact too, and the difference on the surface looks rather pointless (though it used to be bigger), but reducing the visual clutter makes the block syntax acceptable in a lot of circumstances where lambdas would otherwise "look ugly". E.g. in Ruby there is "timeout", which is a method that takes a number of seconds, and a block, letting you write "timeout 5 { call_something }". You could do implement one with lambda's too, but you'd end up with "timeout 5,-> { call_something }" at the bare minimum, and in instances where () around the argument list becomes necessary, you end up with even more clutter, while the block syntax avoids it.

This probably seems very minor, and in a way it is, but in my experience when visual clutter disappears people think about code differently and use constructs more or less sparingly. E.g. you can do most of the semi-functional stuff you do casually in Ruby in C++ too, but the extra ceremony and clutter quickly puts people off. Cutting down on the clutter matters.

Another example is the DSL functionality which in Ruby is often done by defining context classes with methods, or by injecting methods in the meta-class of the class you're defining.

In particularly defining methods on the meta-class to be executed during the definition of a class. E.g. as a example from Sequel:

    class Movie < Sequel::Model
      plugin :validation_helpers

      ...
    end
"plugin" here is a method on the meta-class of Sequel::Model that pulls in the relevant methods of the specified plugin by running this code while defining the class. Being able to basically define a DSL to mutate the class while it is being defined leads to code where boilerplate very quickly ends up extracted into libraries in ways that tends to produce a lot of extra clutter in other languages.

> Unless you're engaging in the above-referenced symbolic soup, Python and Ruby code usually end up looking pretty similar. I don't know how you can say that one "looks awful" v. the other.

I agree it looks relatively similar, which is exactly why I believe most of those of us who have chosen Ruby tends to have very strong opinions about why Ruby works for us. For me the most immediate one is that I refuse to work with languages where significant indentation levels is a big thing. I both really want the visual indication, and really hate working with significant indentation (including things like YAML)

Part of the reason why I feel comfortable making that choice is exactly that the benefit of picking Python over Ruby to me is slim enough that I can afford to make that decision over issues that otherwise would be margin...

> It seems like Ruby is a bit of a small community to target

Ruby is the 4th most popular language on Github: https://octoverse.github.com/

That's what you call "a bit of a small community"?

Yes? Compare with the StackOverflow jobs survey, where Ruby doesn't appear in the top 10 languages used by any type of professional: https://stackoverflow.com/insights/survey/2016#most-popular-... . To be fair, it does appear in slot 9 out of 10 in the general "Most Popular Technologies" tab for 2016.

I'm not trying to say Ruby is a niche language that no one has ever heard of, but it seems like a community on the decline to me. Since, IMO, Ruby doesn't really offer anything special and has always been more style than substance, and since there's clearly already an exodus out of Ruby and into other technologies like TypeScript and Python, showing that Ruby doesn't have staying power, it just seems weird to start a new thing based on something in that type of predicament.

I'm not saying it's bad to start something based on Ruby if that's what you want to do, I just don't get it.

In my experience, StackOverflow rarely to ever comes up when I am looking for solutions to Ruby issues, while I often visit it for other things.

That might very well be a better explanation for why it doesn't appear high on the list for Stackoverflow. I'm not saying it's wrong. I'm saying there's no reason to assume StackOverflow's audience is unbiased and representative. It doesn't rate on my top 10 list of places to go looking for solutions to Ruby issues.

> and since there's clearly already an exodus out of Ruby and into other technologies like TypeScript and Python

I haven't seen anything of that supposed exodus. The few Rubyists I know that have stopped using Ruby have moved on to things like Elixir, not TypeScript or Python. I find that an extremely odd claim to make.

TypeScript to me is a total non-entity - I don't know anyone doing TypeScript anywhere. Not saying it's not popular, just that wherever it is popular is entirly outside of the sphere I work in. Python I come across, but again as a demonstration of how little our personal anecdotes mean: I see far more people starting Ruby projects than Python projects, and most of the places I come across Python, it is grudingly when working with third party code. At the same time I'm fully aware that there are niches where Python is far better represented than Ruby, but they don't often intersect with what I do outside of machine learning projects.

> Compare with the StackOverflow jobs survey

Why compare a survey (things that developers say) with hard pull request data (things that developers have actually done)?

Because hard pull requests don't necessarily mean wider adoption. It gets down to which projects are represented on GitHub v. other platforms and those projects' source management philosophies.

GitHub is (or was, at some point) written in Rails and attracted the Ruby community early. Rails is developed on GitHub, as are many other major Ruby projects, including the Ruby language itself.

Python is hosted on its own Mercurial repository (though it is shifting to GitHub later this year) and that community never had the tribal draw to move its development from things like mailing lists into GitHub. Patches are still handled on the Python bug tracker, etc.

As for individual project source management, some projects will have all contributors with their private fork and have them make individual pull requests as part of the code review process, some will give a core of contributors direct access to make raw pushes, and so on.

Because of not every project uses GitHub and because GitHub's unmanaged pull request object is not a reliable unit of measurement, it's better to trust a survey that directly reflects real-world observances than to make extrapolations based on an unreliable metric.

The exact same argument applies to stackoverflow as well.
> [Apache] Groovy, which have failed to gain a large independent following

> Not many people seem to be using Ruby for new projects anymore

Based on these 2 trends, you can imagine how badly Grails has been faring lately. Its version 3.0 was released with breaking changes 2 yrs ago, but most sites still use version 2. Besides not starting new projects in Grails, sites aren't bothering to put in the smallish amount of work to convert to version 3.