I really like Crystal, but the lack of any large corporate sponsors or large production systems using it (that I’m aware of) means I would probably never choose it for anything besides toy projects.
But does Crystal have either of those? It's also a statically typed, compiled language. Rust would require a complete rewrite of the code, while Crystal would only be partial.
Crystal has meaningfully different syntax from Ruby in some important places:
* Strings cannot be single-quoted in Crystal. Single quotes are used for character literals, like C.
* The two languages differ substantially in how keyword arguments are specified. In Crystal, any argument can be specified by name as well as position.
* In Crystal a 'rocket-style' dict literal (i.e. `{ "foo" => "bar" }`) is a different type (Hash) from a 'keyword-style' dict literal (`{ foo: "bar" }`, a NamedTuple).
* Hashes are typed (inferred at the time of creation). You can't use keys and values of different types than what was in the hash when you created it. You _always_ have to specify a type for empty hashes, which means that any Ruby code that does `x = {}` and then stuffs things into `x` has to be rewritten.
* NamedTuples raise an error if you try to read or write a nonexistent key. Hashes raise an error if you try to read a nonexistent key.
* Crystal does not have singleton classes (`class << self`). The Module class doesn't exist. You can't execute code in class definitions (like constant initializations). Generally speaking, a lot of the very dynamic Smalltalk-y features Ruby devs take for granted are not present.
* `private`/`protected`/`public` are keywords, not methods, and they must be applied to each method individually (`private def...`).
There's a lot else. Now, a lot of these changes are good and fix issues that Ruby can't because of the need for backwards compatibility. This isn't a criticism of the language. The fact remains that Crystal's superficial similarity to Ruby hides a lot of substantial differences (a problem Elixir suffered from for a while as well). Translating simple code by hand is not difficult, but rewriting a larger project would be a huge undertaking.
> Hashes raise an error if you try to read a nonexistent key.
Depends on what method you use to read it. If you use [], what you describe is true, but if you use the nilable variant, []?, it is not. But yes, having to handle and think of nilability is certainly a big change that will affect a lot of code.
Having a runtime and GC is not unusual for a statically-typed, compiled language.
Crystal, in fact, has a runtime, that runtime has a GC, and the language FAQ notes that removing the GC would be impossible without complete redesign of the language.
I'd be worried of a false sense of similarity. Recently there was an article about crystal, some comments said Ruby was ~one inspiration and not the main goal. You could spend more time fighting your old habits with something that doesn't translate 1 to 1.
I spent some time working on a Crystal project and the superficial similarities to Ruby were more confusing than anything. Crystal isn't just "Ruby but fast and statically typed". They are quite different languages.