The Crystal Programming Language
crystal-lang.org
crystal-lang.org
https://news.ycombinator.com/item?id=9669166 (3 years ago)
https://news.ycombinator.com/item?id=10014178 (3 years ago)
https://news.ycombinator.com/item?id=10803635 (2.5 years ago)
https://news.ycombinator.com/item?id=15574714 (5 months ago)
Crystal is now %100 funded for a full-time developer working on core - https://twitter.com/CrystalLanguage/status/98229223882167500...
Crystal Automated Release towards 1.0 - https://crystal-lang.org/2018/03/09/crystal-automated-releas...
A summary of why vs. why not - https://medium.com/@DuroSoft/why-crystal-is-the-most-promisi...
Web Frameworks Status:
Rails inspired (with Influence from Phoenix):
Amber - https://github.com/amberframework/amber
Lucky - https://github.com/luckyframework/lucky
Both look healthy in terms of community and updates but Amber seems to have a slight edge.
Sinatra inspired:
Kemal - https://github.com/kemalcr/kemal
Your data comes out of the JSON structure wrapped in a functor, and you can only access it in ways that deal with missing data.
It’s hypothetically possible to recreate this approach in Python, but I don’t think it would be Pythonic.
The functor approach doesn't involve any type casting, and null pointer exceptions are impossible.
int JsonValue::getAsInt(int defaultIfError);
Or, in Go:
func (JsonValue*) AsInt() (int64, error)
Or are you just talking about it returning the value as a Rust-style Result sum type?
Its not idiomatic in most mainstream languages. Except, that's how most JSON libraries which validate against a static structure are implemented, they just abstract the reflection away via some interface.
Yes, I didn't mean to imply that I was providing an exhaustive list of languages where this approach could be implemented. I merely mentioned Python because it had been brought up several times in the thread.
> Grab the item in the map at that key -> check that it exists -> check that the type is what you expect.
I'd argue with that phrasing. You don't check for the key, nor do you check the type. That would imply something like an if-statement to ensure the presence of a key, and switching over a type. In such a system, you could forget to check for null, or make some other mistake that causes the program to fail at run time.
The functor approach does not rely on the developer checking anything. It is 100% type safe, enforced by the type system, cannot crash at run time, and does not require you to provide a data type to extract the data into.
https://fsharp.github.io/FSharp.Data/
https://medium.com/@maximcus/magic-of-f-type-providers-225b1...
(1) Expect it to conform to a contract. Marshal and unmarshal it to and from a backing data structure that represents that contract. Perhaps with some tolerance for missing or unexpected values.
(2) Have no expectations of a contract. Parse the JSON string into a blob-tree of your programming language's "any" type. Just kinda yolo-wing-it with tree traversal, and hope that your language syntax is very null-tolerant. Try to overlook the fact that ultimately you DO have an expectation of contract after all (!)... it's just scattered through your tree-traversal logic, rather than consolidated in a data structure.
I think pretty much all modern widely-used languages do a decent enough job with approach #1. While approach #2 is pretty much equally awful with all languages.
Also, there's a sort of intermediate step, a dynamic language with schema validation, for which I wrote a modestly well-used (within the overall schema validation gem market) gem a while ago. Then you can validate at the point of translation, without being beholden to a concrete data type (POJO, data class, case class, etc.) that has to be updated whenever the wire format changes.
"Readability" and "simplicity" are except for trivial or outlandish cases subjective.
For example, I rather enjoy reading code using Rust's serde crate: the code is quite readable and comes with all the benefits of Rust's static type system and safety.
Some are far more awful than others. Python for example has no issue here at all, json types map nicely into its basic data types, while most statically typed languages make json handling terribly verbose and make it feel like it doesn't belong there. And while there usually is some contract, there are many api providers that don't provide schema, make frequent changes or explicitely expect you to deal with "some random json here" part of the data.
Then I found ruby and loved how simple it was to not worry about a type system.
Then I found out how infuriating it was to not have types.
Now I’m older and appreciate having types.
Cool story, bro.
Crystal looks cool!
Basically, a lot of Perl's object-orientation weirdness derives from it all being exposed to you. It's an excellent learning experience if you ever want to know what it means to be a "class" or an instance thereof, since "methods" are just ordinary subroutines that expect your object (or class, for constructors) as the first argument, and class instances are just ordinary scalar/array/hash objects blessed with a package name. Nothing hidden or abstracted away. Simple and flexible enough to fit into the TMTOWTDI philosophy.
The only thing that I have against crystal is that my compiled binary didn't work on all other machines I tried it on. Even the practically identical macbook of a friend of mine. Looking around on their wiki pages and in the issues on github didn't give me any real solutions. So right now, as the version numbering suggests, it isn't ready for production.
It is anyway the trend we are getting back to, after we have learned our lesson how threads and plugins can bring whole processes down, while being good vehicles for security exploits.
Why is this inherently easier to you with threads rather than forks? Many very successful apps use a forking model and do what you say, so I’m genuinely curious on your reasoning here.
This is reflected in the Erlang way of doing things (since there's no such thing as "shared memory", at least not directly); a process needing data from the DB sends a message to the DB connector process, which runs the query via one of a set of pooled connections and sends the result back as another message to the requesting process.
If you like the idea of a fast, compiled, statically-typed, Ruby-like programming language, you can support Crystal development here (NOTE: I'm not affiliated with the Crystal project in any way. I'm just a happy consumer): https://crystal-lang.org/sponsors/
There are still bugs, but if it compiles itself and the compiled version still passes all the tests, how bad can the bug be?
It takes out of the table the typical argument that the language is not serious enough because it is written in C or something.
The usual old time joke "my compiler compiles your language".
Otherwise any general purpose language, should be able to be used for all kinds of application, including compilers.
But yeah, there's a little vanity too.
1) How do you think most compiled languages were created back in their early days?
2) Crystal isn’t really that young of a language
3) even many non-compiled languages are run on an interpreter written in the language they implement these days.
because for most apps, you will be bottlenecked by the database server. it is the slowest hanging fruit on the tech stack, be it postgres , mysql, or mongo. so unless you are working on number crunching tasks that do not involve any db queries, i fail to see the benefit of a language like Crystal.
i wait for the day until the day Crystal becomes a 100% drop in replacement ready for Ruby apps.
until then, Sinatra is more than fast enough for most things.
i mean it doesnt get any lighter than this.
require ‘sinatra’
get ‘/‘ do
“hello”
endyou should check out https://github.com/jaequery/jasis
its a dockerized Sinatra app with all the bells and whistles and see how light it is yourself.
thats why i recommend Sinatra for performance conscious devs, as its a fast and minimal framework. and you get to load only what you need. check the github.com/jaequery/jasis github project and peek at the Gemfile / boot.rb to see all that it loads for a full fledged mvc app. its pretty explicit and lean if you ask me.
if are talking about server resource then you probably referring to the web server. for which we have ‘puma’ and it is also incredibly light and fast. much lighter than a php stack running Apache and mod_php for sure.
but i see you compared to Go to which we have no comparison Go will run circles around Ruby. but Go is not really a well suited environment for web applications yet so ill just leave it at that.
Sinatra may be lighter than Rails resource wise, but it is still not in any way light compared to a compiled binary. The difference is pretty staggering in practice.
If you take e.g. Alpine Linux as a base image, then build almost everything as a single step in a shell script, removing useless intermediate files, you get a pretty small image. If you take e.g. a normal Debian image and build it so that every step adds a layer, you end up with a large image.
For me it's a Ruby like language with static typing. For my typical use cases I don't really need the extra performance, but those two things are enough to make me interested.
Is there anything to suggest Crystal is primarily intended for use writing those kinds of applications? If we're talking about all of software development, most programs probably don't talk to that sort of database server at all.
I don't say this to knock Ruby. I love Ruby and think Matz is an outstanding human being. I'm just pointing out that while the database server can be a bottleneck, to be sure, there are still plenty of benefits to using faster languages to accomplish database-centric tasks.