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 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 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.
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.
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 marginal, but that matters to me.
> 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.
Ruby is the 4th most popular language on Github: https://octoverse.github.com/
That's what you call "a bit of a small community"?
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.
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.
Why compare a survey (things that developers say) with hard pull request data (things that developers have actually done)?
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.
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
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?"
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.
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.
All of the IO in crystal is async, so even if you're IO bound, crystal is probably a lot more efficient.
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.
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