Hacker News new | past | comments | ask | show | jobs | submit login
[dupe] Crystal Language That Aims at C Performance with Ruby Syntax Releases 1.0 (infoq.com)
111 points by joseluisq 16 days ago | hide | past | favorite | 52 comments



Previous discussion (10 days ago): https://news.ycombinator.com/item?id=26545082


I'm seeing a lot of complaints about Crystal's slow compile speed.

But isn't Rust's compile speed also slow too and it's still being used by many engineers?

Even then after 1.0 for Rust, I haven't seen any compile speed improvements in that space lately.


In my experience Compilation speed is an excellent bikeshed that lots of developers complain about if they're evaluating a language. It's an easy thing to say "Well the compilation speed" as a reason to discount a language, but in reality Compilation speed (barring like, truly incredible times for basic things) is a simple Pro/Con in a massive sea of pros and cons.


You can also go further and decide what in said 'sea' is more or less important.

Compilation speed greatly effects your ability to iterate in your development process. Depending on your skill level, for most programmers this can be MASSIVE (its literally your development frame rate). Also depends on domain too, for example, something with a ton of IO/sideeffect needs more iterative development than say an algo.

Sure there are ultra high experience devs who can make a thousand line edit, send the build and have it run perfectly 4 hours later. Even in that case you need to consider the cost of coding extra defensively to make sure it's right the first time.


> Compilation speed greatly effects your ability to iterate in your development process. Depending on your skill level, for most programmers this can be MASSIVE

Compilation speed is not the only factor in ability to iterate. This argument is the exact bikeshed argument that gets made all the time. Even if your compilation is insanely fast, your build pipeline might be insanely slow. Compilation speed alone isn't enough to really make any value judgements at all, is my entire point.

> Sure there are ultra high experience devs who can make a thousand line edit, send the build and have it run perfectly 4 hours later. Even in that case you need to consider the cost of coding extra defensively to make sure it's right the first time.

My last job used Ruby on Rails, a language that is touted to have extremely fast iteration speed. That company also chose to have a build process run all tests (unit + system), such that a "build" took 3+ hours. To say, "Ruby on Rails has fast iteration speed and doesn't require a compile step" ignores so much context about what's actually happening, the statement is effectively useless.


Ruby on rails has nothing to do with fast iteration speed. It's incredibly slow and doesn't care a little about the horrible dev experience. I used it professionally for 12 years.


I don't think you're using bike shed in the right context, but let's not go down that rabbithole.

I specifically did evaluate Crystal some time ago, having a set of properties that seemed to hit a sweet spot. I gave it a fair go working on several projects with some of the popular Crystal web frameworks. I went in with full enthusiasm. In the end, only the most basic framework, Kemal (Lightning Fast, Super Simple web framework. Inspired by Sinatra) was tolerable. Definitely not a Rails/Ruby replacement. After that, I favored Phoenix/Elixir for such projects.


> I don't think you're using bike shed in the right context, but let's not go down that rabbithole.

Glad you found that worthwhile to bring up but not extrapolate on :)

> specifically did evaluate Crystal some time ago, having a set of properties that seemed to hit a sweet spot. I gave it a fair go working on several projects with some of the popular Crystal web frameworks. I went in with full enthusiasm. In the end, only the most basic framework, Kemal (Lightning Fast, Super Simple web framework. Inspired by Sinatra) was tolerable. Definitely not a Rails/Ruby replacement. After that, I favored Phoenix/Elixir for such projects.

Great! Glad you found something that worked out for you! I'm noticing you didn't bring up compilation time in your complaints about Crystal specifically, which seems like a worthwhile thing to point out given we're discussing Crystal compilation times.

Regardless, in the spirit of my other recent post, I'm glad you found a tool/language that you enjoy (Phoenix/Elixir)!


Sorry I wasn't clear. I first tried to use a more featured framework, Lucky or Amber but only Kemal compiled fast enough. I'm pretty sure they all would have executed the application fine.

I have nothing against Crystal. In fact I still think it's great, just not for the kinds of things (e.g. web dev) that I would do in languages like Ruby, Go, or Java. Similarly, Pony is a fantastic language (Rust done right IMO) but I don't have a use for what it/Rust delivers in my typical projects. In short, I think Crystal could benefit from better/clearer positioning, as the digressing discussions in these comments show.


In my experience, over the past 2 years there's been quite a good speed up in compile times in Rust, but that's just for my case on an older laptop. On my desktop, there's never been an issue.

Long compile times suck, but Crystal and Rust have never put me off because of that. I can wait another few seconds.


I mean, I agree when build times take more than a minute, I don't care about seconds. Have you used languages that take less than a few seconds (in total) to compile?

Also in my experience Crystal compiles simple projects faster than Rust and somewhat comparable to Julia, but much slower than (e.g.) C or Zig, which I think is fine for a language with higher level features. Maybe I haven't done anything big enough with Crystal yet to see the compilation times though?

And of course, I expect it will get better over time, there are things that can be done like parallelization and cached incremental compilation results (like Cargo or Gradle do)


Rust has an 'excuse' for compile speed, in that, the compiler is ostensibly doing 'more work'.


I'm not sure what you're implying by this, because the Crystal compiler is doing a lot of work as well. The global type inference is the primary reason for Crystal's compiler speeds, and it's why it's not likely to substantially improve. It's not slow for the sake of being slow.


Java does type inference in a number of places and javac is not slow.


Java doesn't do type inference at the level of Crystal. It's not the presence of type inference, it's the fact that almost everything in a Crystal program can be inferred.


javac produces Java bytecode, not LLVM IR.

javac exists since at least 15 years, Crystal "only" 6 years.

Maybe things will get better with time?


What work would that be?


? The borrow checker which is literally the reason Rust exists.


Borrow checking is almost always very cheap, and lifetime are erased before codegen which is the really slow part.


  def fibonacci(n : UInt64)
    return 1_u64 if n <= 1
    fib(n - 1) + fib(n - 2)
  end
 
  puts fib(46)
Am I reading this wrong or should that start with `def fib(n : UInt64)`?


This could be a killer feature - smart inferred function name.


As a joke in college, I came up with the idea of a language that used fuzzy-matching to find the variable/function name with the closest match to the identifier used if an exact match wasn't found. This has the "fun" property where as long as a single variable is in scope, there are no undefined variable errors :)


This seems like a super fun idea


Until someone adds a method called fib (staying with the example of the thread) doing something completely different.


Dynamic method swapout during recursion! Who doesn't want that feature?


You're absolutely right.



Do I need to know Ruby in order to better understand Crystal? I'm interested in learning Crystal, but the community is quite small and the learning resources, sparse. Ruby on the other hand has a massive presence in the form of tutorials, books and blog posts. I have some minor experience with Python, Java and PHP.


No you don't, seeing as Ruby compatibility is a non-goal to begin with.

If you want a fast language that is mature and has a big community with lots of documentation and resources, I'd go with Rust.

I am a Ruby developer myself and I was interested in Crystal because of what I perceived to be an advantage for not having to relearn a language. But trying building something with Crystal revealed to me that syntax is about the smallest part of a language. Granted, Crystal shares a lot of the core libraries but even so there are differences in that it is typed, you have to compile, debugging a running program is completely different, etc. If I am going to have to learn about those differences, I'd rather learn a language that has the same advantages and more in the form of the aforementioned resources and the fact that it has been accepted by many as a well built language with lots of support for it. Hence my recommendation for learning Rust.


Go is another obvious choice if you're looking for a fast compiled language to learn as a complement to a slower interpreted one.

I'm not a big fan personally, but it has tons of mindshare and there's a large active community around it.


> If you want a fast language that is mature and has a big community with lots of documentation and resources, I'd go with Rust.

I'm sure that when Rust had their 1.0 release 6 years ago, there was little to no documentation and a small immature community at the time. We had the same people saying that it isn't mature and the same fans using it in production since pre-1.0. This is also the case with Crystal.

Fast forward today, Rust itself has matured, but unfortunately the crates ecosystem is still immature.

Each time I see a crate on crates.io, the version is below 1.0 and it is reflected on the "work in progress" disclaimer warning of unsafety guarantees in the mountains of other dependencies it uses, which makes me think twice about importing it; especially if it isn't pure Rust. I would expect better quality crates in the Rust ecosystem especially 6 years on from 1.0, but today, this is still not the case. I have the same expectation with Crystal's ecosystem, as it is now 1.0.

Suppose you are using Ruby in a system (Not using Rails) for dispatching events and then calculating how long these events take with tens of thousands of users and you then realise that the language itself was the bottleneck. Yes, I'm talking about Deliveroo: [0]. Yet for them maintaining two languages and using Ruby FFI and rewriting it in Rust somehow sounds much more better than adapting it to Crystal. (since there were those who also used Rust in production in pre-1.0)

If this was in C, C++ or Java then [0] would make sense. Ruby to Rust and still using both languages after the rewrite doesn't make sense when I can just 'adapt it' to Crystal in 5 mins and it just works. Even Elixir makes much more sense.

[0] https://deliveroo.engineering/2019/02/14/moving-from-ruby-to...


D is another choice. It has good C compatibility and C-like syntax. It's not hot, but it's old, and thus more likely to survive


"The ability to run the Crystal runtime on multiple cores is on the roadmap, together with ARM support, and availability on Windows. Building fully statically linked executables is currently only supported on Alpine Linux."

Once Crystal addresses above shortcomings- it'll be a lot more interesting.


> Do I need to know Ruby in order to better understand Crystal?

No you don't, it's inspired by Ruby but it's not a carbon copy.

> but the community is quite small and the learning resources, sparse

That's one of the main issues of Crystal, the community is very small and language adoption is still very low.


Yay finally! Crystal is awesome, with the exception of compile times


Is there a possibility that Crystal could be used on MCUs? What would be its advantages over Micropython, C/C++/Rust or Zig?


Crystal has a GC, and also compiles to LLVM IR, so it's a little heavier than what you might want for MCUs. Circuitpython, C-*, Zig, Nim and other co would all be more appropriate choices, generally speaking.

I'd love to see some effort taken to bring Crystal lower and closer to metal but I don't think there's that much desire in the community for it, and there's not enough corp resources to just throw man-hours at whatever the community wants right now. Manas seems to have a little trouble keeping people around the Crystal core team, though I'm not exactly sure why.

It'd be great to have a Crystal that could spit out C or Zig code instead of LLVM IR. That'd be awesome.


The discussion I've seen surrounding this from core maintainers is that embedded Crystal is not a (medium-term, at least) goal. While you can technically turn off the garbage collector, it's not currently a practical solution.


Nim seems like it would do well, since you can just compile to C code.


Nearly all languages worth considering can compile to either GCC or LLVM one way or the other, the thing I find that makes the difference for microcontroller use now is (to be worth using over C) the ability to abstract over the peripherals quickly (There is a project that I think parses the peripheral datasheet at compile time in D, even), preferably zero cost.


What's the niche for Crystal? It seems like Go is the performant and easy, while Rust is the safe, ultra performant but hard. Elixir solves the problem thst Rails is solving in a better way, so it's hard to identify a niche at this point.


To me, Ruby syntax/semantics look like an incoherent mishmash of bad practices/design choices; I wonder why so many people seem to love it to the point of thinking replicating its features is somehow an advantage. I genuinely don't understand.


I think Ruby can have some nice parts to reading it. e.g.

    10.times do
      puts “Hello”
    end
or

    send_email if user.unconfirmed?
Compared to ES6 as an example:

    Array.from(Array(10)).forEach((_, _i) => {
      console.log(“Hello”);
    });

Ooph, not the strongest showing by comparison. There isn’t a huge issue with it, but it is having to use a lot more indirection to express the main idea. Languages like Python get closer to that expressiveness as well, but I think Ruby goes even farther in the direction of expressive choice.

I don’t write Ruby anymore. But there were some nice things that I miss sometimes when using other languages. Sometimes I want to express a very simple idea that, while still readable, gets wrapped in brackets, parens, variable declarations, and type declarations to a point where it looks more intimidating and unapproachable than it actually is.


You can get a bit nicer with something like

    [...new Array(1000)].foreach(() => console.log('Hello'))
But yes, ruby is much nicer.


Don't allocate an array when you just need a for loop.


The console.log was just an example. This is just getting a range of numbers.

Right, what's wrong with just

for (var i = 0; i < 1000; i++) {

    console.log("Hello world");

}


Nothing per se, but more declarative code is often nicer to look at than imperative code.

In the for loop example, you need to name and explicitly initialize a variable, you need to explicitly write down the comparison, and you need to explicitly increment the variable.

In the Ruby example, the plumbing is hidden from view, and you can just tell the runtime how often you'd like the thing to happen.

On a tangential note, in Raku (the language formerly known as Perl6), you could have written that as

    say("Hello world") xx 10;
That's pretty hard to beat, imo.


fwiw, most folks would just use Lodash[0]:

  import times from 'lodash.times'
[0] https://lodash.com/docs/4.17.15#times


And that shows one of the main problems with JavaScript. People in my team have spent countless hours removing lodash dependencies from the codebase.


Why? It's imho a must have lib. JS feels incomplete without it.


Your criticism would be more constructive if it included specific examples.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: