Crystal is a Ruby inspired compiled language, allowing it to run blazingly fast with a very low memory footprint. It uses LLVM for emitting native code, thus making use of all the optimisations built into the toolchain.
I feel like the author dismissed Nim pretty unfairly. Github stars and issues are one signal for a project status, but its hardly conclusive. Nim's development has been pretty consistent and is approaching 1.0. Ultimately, a lot of language choice is subjective, but I think anyone looking for a language in the fast-but-expressive category should at least try Nim.
Definitely. He dismissed it mostly because he doesn't like camelCase? seems like a silly reason to dismiss a language. I've been around enough different ecosystems to know that style is something you get used to. snake case, camel case, same-line curly brace, give it a few weeks and you won't really notice. It's a silly reason to dismiss a language.
True, I REALLY hate camelCase though ... hahaha But seriously, I do need to spend more time on Nim and give it a fair chance on a project :)
Ultimately, I had to choose something to commit to for a while as there are just not enough hours for me to learn multiple new languages outside of work and with my various other hobbies.
But rest assured that Nim was absolutely a front-runner and I'm happy to update the post to reflect this.
I do too, and that's exactly why you should use Nim. It is, perhaps, the only language in which the variables "camelCase", "camelcase" and "camel_case" are the same (though CamelCase isn't) -- so you don't have to follow braindead Java principles if you don't like them.
I'd consider it even worse. I like consistency in my codebases. Good luck grepping for variable, when half of the folks will use variable_name, the other half will use variableName and the last half will do variablename.
People still grep for variables in $current_millennium? I have to agree with the other comment about tooling being an important factor in language selection.
Nim includes "nimgrep", so I have good luck grepping for a variable, and it is supported in most common editors with a nim package. Nim also includes "nimsuggest", which provides intellisense - also available in most common editors.
And if you really insist, it is quite easy to write a simple program that will unify the styles for you. In practice, it's not a problem.
In this respect, Nim inherits pascal's case insensitivity, and just adds a few minor and arguably useful details (underscores are ignored, case of first letter preserved). It was never a problem for Pascal (or BASIC, or Excel, or NTFS or HFS+) and it's not a problem in Nim.
And being an early Python advocate and evangelist, I feel history is rhyming again .. ."What? You use significant spaces ? That's so stupid, and bound to make everything fail. Yes, some people still dislike significant indentation, but by and large, experience shows that it's not inferior[0] to token block delimiters, and in some ways it is superior.
And what do you do when a library you need doesn't use the same style as your code base? Let me guess: you end up adding an inconsistency into your codebase.
This is what style insensitivity is meant to fix. In reality, you are able to tell what style a code base uses almost immediately and grep accordingly.
> "camelCase", "camelcase" and "camel_case" are the same (though CamelCase isn't)
I find this horrifying and think it probably reflects deep philosophical differences between myself and the creators of Nim. Languages shouldn't make assumptions and how to interpret my typos. They should tell me about the typo and suggest a possible fix.
It's not about typos. Nim borrowed a lot from Pascal when it started life, and Pascal, like BASIC, Fortran, some LISPs, Excel, NTFS, HFS+ and many others, is case insensitive.
What you say is equivalent to "I want to be able to declare three independent variables called camelCase, camel_case and camelcase", and Nim says "no, you can't do that in the same scope" (which is a little more strict than pascal which says "you can have camel_case distinct from the other two, but those two are equivalent).
Experience shows that case sensitivity is harder to use in general[0]; "Although we resisted changing the Python implementation, our user testing data forced us to make ... Python case insensitive. Over 85% of our users made case errors and many continued to do so even after learning that case was significant." it's just that you're used to it; same with respect to int/int vs true division.
I'm feeling an almost dejavu to the early days of Python, when the standard response (which people still repeat sometimes, though rarely these days) was "what!?!? you mean spaces are significant!?!? that's horrible". But this is equivalent to saying "I want to be able to write code that behaves differently then it looks, such the C code:
if (nuclear_launch_detected)
notify_the_president();
launch_strike(STRIKE_MODE_MUTUALLY_ASSURED_DESTRUCTION);
(The like of which make iPhones and Macs susceptible to eavesdropping for a long time). Python says, "Nah, you can't do that". It's opinionated, but experience shows it works better overall.
The reasoning may not be about typos, but the egonomics are. Also, following the tradition of those other systems doesn't make it better for Nim users. The context matters a lot.
And why are case errors a big deal in case-sensitive languages if they cause "undefined" errors or, better yet, are caught by static analysis?
(To your point about Python, I still think semantic whitespace is insane -- invisible code, as you implied -- and is a major reason I avoid Python when possible.)
Nim is pretty amazing. I spent last week writing some toy programs and it reminded me of Python - in the sense that it allowed me to write working code within a few hours of picking up the language.
The “optional namespaces” thing is something which bugs me a lot though. That importing a module works similar to `from module import *` in Python. It makes code confusing to read and grasp IMO (which module does this symbol come from?). Other than that, a pretty cool language.
> The “optional namespaces” thing is something which bugs me a lot though. That importing a module works similar to `from module import *` in Python. It makes code confusing to read and grasp IMO (which module does this symbol come from?). Other than that, a pretty cool language.
This is a common complaint, but there is rarely a solution proposed alongside the complaint. Nim is significantly different from Python to warrant these semantics, but I am really open to hearing ideas of how this could be improved keeping in mind these differences (operator overloading, no classes).
A recent proposal was made here, and it looks like it will be adopted, I'd love to know what you think about it:
You're right about this point. I really should have spent more time on Nim, and I still intend to. In fact, Nim was my main choice prior to learning about Crystal.
So no offence intended at all to any Nim fans, and I hope to dive into it more thoroughly in the near future.
I agree. I am taken by surprise at the all-round strong performance of Nim. Python-like syntax, a pleasing type system, efficient compilation and packaging. I am waiting to hear more on this. As I understand it they are a small team too and their implementation is truly worth following up.
I came to Crystal from Nim. I really like Nim. But I feel that the language maintainers do not have an idea on how to grow the ecosystem. Even after all these years, Nim doesn't have any good web framework. Jester, is the only one I know of has no website of its own and is very lacking in documentation.
Hi, one of the Nim core devs here. Any ideas how we can fix that?
Crystal has a surprising amount of web frameworks with great marketing behind them. Could that just be because it's a Ruby-like language, and Rubyists are far more interested in web frameworks?
That's my theory, but I could be totally wrong. I'd love to know how we could improve here.
Perhaps it's because I created a web framework that is good enough (jester) early on and so nobody feels like stepping in with their own implementation. A website for jester would be great and it is on my to-do list, but so are many more things.
Personally, the first thing I look at when I look into a new server side language is how it does in benchmarks conpared to other similar languages (such as the TechEmpower benchmarks). I know that those types of benchmarks are flawed in a lot of ways, but performance is probably the only objective way to evaluate a language, and I’m much more likely to learn about a language if it looks like it’s fast.
From what I’ve seen for Jester/Nim, it’s not really benchmarked a lot, and it doesn’t seem particularly fast where it is benchmarked. This could perhaps be fixed by better implementations for the benchmarks or some optimization in Jester itself.
I think a strong story for performance would go a long way towards improving awareness of Nim. Crystal does very well in such tests, and I think that is one of the most appealing parts of the language. In fact, I evaluated both Nim and Crystal for server side development a while back, and quickly dismissed Nim because it didn’t seem to be all that fast. I eventually dismissed Crystal too because of the compile times and syntax, but I put a lot more time into it.
I would say that you should look at the language's theoretical performance as much as its actual performance. A lot of these benchmarks are just a result of someone putting in a lot of time tweaking things until they are perfectly suited to the specific benchmark, in real-life you will get nowhere near that. Additionally, you won't actually need to get anywhere near it. If you do, then you will have the time to tweak things and get to know the language inside out. In that case, all that will matter is the theoretical performance of that language.
So what do I mean by theoretical performance? Well, Nim is a statically typed and compiled language, it stands to reason that these attributes make it very performant indeed. Even if certain aspects of the language are not efficient right now, you can bet that it will be fairly trivial to improve their performance. For languages like Python, Ruby, etc. you are heavily limited by the dynamic typing (which restricts the amount of information you have about the code) and the fact that they are primarily interpreted languages. You will need to put far more effort into optimising them than compiled languages.
As a side note, I do intend to improve the performance of Jester as well. But I'm not the only one doing this, the mofuw framework is #24 on the TechEmpower benchmarks right now.[1]
It’s not enough to have good “theoretical” performance when other languages already have measurably good performance today. I’m not trying to say that Nim is bad or slow, but when there are a dozen similar static, compiled languages to choose from, it’s easy to dismiss one based purely on the benchmarks alone. I understand that it’s sort of an optimization game with these benchmarks, but it’s at least a form of marketing, which is something that Nim can benefit from.
Thanks for asking. I had stopped looking at newer languages long time ago and I can't tell quite how I decided to check out this Nim. Perhaps its finding your well written book, Nim in Action. Nim language has this one characteristic that means a lot to me -- to be able to learn the core concepts very quickly enough to get productive in some of the routine work (back-end system interactions, distributing compiled modules to other locations, numerical/data processing). Nim won my heart in this regard hands-down.
Well, along the lines of what is already mentioned, I stumbled on web communication aspects (I like the available template system, it performs well) and ran into glitches with the mongo or postgresql drivers as I got deeper. I am glad that Nim doesn't have a Ruby-like syntax -- Nim's current type structure/syntax is its strength, IMHO.
(I wanted to contribute some money to the team but PayPal is the only option even if the site says it can take Visa etc. PayPal is something that I avoid due to past experiences)
> Perhaps its finding your well written book, Nim in Action.
Thanks! :)
> I wanted to contribute some money to the team but PayPal is the only option even if the site says it can take Visa etc. PayPal is something that I avoid due to past experiences
There are many ways to donate to us, I guess we need to spruce up the donation page, the "Other ways to donate" is buried at the bottom: https://nim-lang.org/donate.html
As a Rubyist, I was about to jump on the Crystal train, but then server-side Swift started getting really good. Crystal is awesome, but I feel it’s not solving any problem particularly better than Swift. With Swift being compilable even on a Raspberry Pi and of course Linux and Mac, it seems like Crystal is now a solution in search of a problem. Definitely a great language, but probably destined to be relatively niche in production contexts simply because the community is so small and it’s loosely competing against the rapidly maturing Swift world.
Is server-side Swift really that good now? I’m in the market for a new statically typed language, and it was looking like Java still might be my best option...and I’m really not a huge fan of that.
I think whether it's "good" is still to be determined as it evolves. There are three "maturing" Web frameworks that are fairly popular within the Server-side Swift community: Kitura, Perfect, and most popularly Vapor. There are others too. Based on my cursory explorations, I would checkout Vapor first.
I stopped coding seriously right around the time Swift became a thing (after a decade of Obj-C, C, Ruby, Clojure, PHP, and other nightmarish things), and always thought Swift for compiled server binaries, running on linux machines would be amazing. I've followed the scene from afar, but never got the impression anything seriously caught on.
What do things look like these days that make you think server-side Swift is viable?
Vapor is the main reason. Kitura is also used, but it seems, in my opinion, that it’s not as vibrant as it was, despite IBM backing. Vapor has a pretty active community — it feels like the early days of Rails.
I have started using Vapor to write microservices where I would have used Rails-api in the past and the performance is astounding but you still get the ease of use typical of Rails. The Vapor ORM works pretty great so you get ActiveRecord style sugar but with pretty great performance.
Perfect is another server-side framework that is popular, but Vapor won me over because I feel like it was a more approachable community.
Basically Vapor feels like circa 2006 Rails in terms of momentum.
And it’s crazy fast and the toolkit seems to be evolving quickly.
I personally find general-purpose Swift surprising because I'd assumed that they'd have to make various language/runtime compromises, solely for backwards compatibility with Objective C, that it'd always be relegated as a niche, iOS-only language.
Admittedly, this is a somewhat naive assumption, but it also based on my experience of Scala/etc. languages building on top of the JVM.
Swift on Linux is not at all tied to Objective-C. In fact Swift on Linux does not even include the Objective-C runtime. So, you basically get an ahead-of-time compiled language with the same Foundation library as Swift on Mac but without any Objective-C dependency.
The Objective-C interop features of Swift are there for interaction with Apple's frameworks on their platforms.
Last I checked, not much. Apple only distributes binaries for a few versions of Ubuntu, so unless you're running Ubuntu 14.04, 16.04, or 16.10 you have to compile it yourself. I tried to get it working on Fedora a while back but eventually gave up.
The only swift IDE's I know of are the JetBrains one (AppCode, I think?) and xcode. Neither of them runs on Linux. There are a few plugins for existing IDE's but nothing that's great yet.
IBM is surprisingly into swift, so I wouldn't be surprised if Eclipse eventually gets first class support for it but it hasn't happened yet.
Backwards compatibility with Objective C hasn’t been a huge priority, though you can definitely wrap ObC with Swift pretty easily.
I definitely recommend digging into server Swift to form your own opinion. Vapor is a good, gentle starting point because the tooling to get up and running is pretty nice; it’s not a huge investment to play.
The results he got for C and C++ make no sense and I question what optimization flag was actually used if any. From the looks of it, he uses "-O" which is equivalent to "-O1" which is really not the flag you want (this optimizes for both time and code size).
*edit: with O2 I get a dramatic improvement and the C and C++ versions compile to essentially the same disassembly. Using O1 is definitely not going to produce an apples to apples comparison.
Except it is not a loop[1], but a non-tail recursive function (with dual calls), if the compiler can optimise that to a loop that is actually impressive.
Most likely function call overhead (and in the slower cases, interpreter overhead) is probably what is being measured in the best case.
[1] In that it won't be a jump and check style loop.
Quite likely: https://godbolt.org/g/xGkCyA although it really depends on the compiler (gcc is smarter here). He also seems to be benchmarking printing more than anything else (hence the difference between C and C++).
Without versions of the compilers and explained methods of measurement, the results posted on the blog are more anecdotal knowledge than any kind of benchmark.
For what it's worth, I have zero association with Crystal, but just happen feel that it appeals to me the most. You can see this on my GitHub too, all projects up until a week ago were Python.
And I chose Fibonacci as a fun little test which I even stated in the post. It should be obvious that this is not an overall indicator of performance for all use cases.
For many of us, Windows isn't our target platform so the Windows compatibility isn't a deal breaker. I understand that this is a big problem for many though and there is evidence that the Crystal team are on it; see https://github.com/crystal-lang/crystal/issues/5430.
Please don't take the post too seriously, it's not intended to be and clearly everyone will have different preferences and tastes as is the case with anything in life.
Fibonacci is an easy problem to know that you implemented the recursive form correctly (easy to check the answer), and the recursion is a very simple way to test the speed of function calls. So it's a very reproducible way to test the speed of some of the internals.
I've been dabbling with Crystal a bit lately, and have been impressed with it, especially the speed and low memory footprint. Still only developing small utility app with it at the moment [0] but eventually might look at creating production API servers with it.
It's just me, but I view the lack of OO features in Elixir as a really good thing. You still have structs and some other OOish type stuff, but the emphasis on composition and modularity has really made Elixir programs a joy to read and understand.
The lack of a single binary isn't a fully fair criticism. While technically it is true, it doesn't describe the shipping experience. You will need Erlang installed on the target machine, but using escript you basically ship a "single binary/file" and it includes everything it needs to run. It's quite elegant, and erlang is super easy to install on basically all *nix systems.
Agree with this entirely. There are so many long term issues that you avoid by building things this way.
Plus the run time gives you benefits that you're not getting in any server side language that doesn't run on the BEAM. There's BEAM and everything else...and everything else is a really crowded field.
It's definitely not just you. Elixir and other functional languages are preferred by many, including myself, for this exact reason. I simply do not see any pros to traditional OO languages and functional languages like clojure (maybe elixir too, I haven't had a chance to study it in depth) include polymorphism, one of the few good OO ideas. Maybe it's just me, but after two and a half decades of OO, I expect it to make sense and it still doesn't in any meaningful way. That's one of the many reasons functional languages are attractive.
I might've misunderstood what you referred to in this particular case, but you generally don't need to even have Erlang installed on the target machine to ship Elixir (and/or Erlang) applications. Tools like Distillery make it easy (a boolean config value) to include the ERTS with your deployment, leaving you with a single .tar.gz to move to your target environment. The only caveat here is that the build machine and target machine architectures must match.
Yep, many of my colleagues at work use Elixir in fact and they say the same. Ultimately, I started with C++ ... a long time ago (2001) ... and from day one I learned coding using an object-oriented approach.
A lot of this comes down to the fact that one has to really commit to a functional mindset and go all-in like my friends at work have. This wasn't a commitment that I was personally ready to make, especially since all the programming I do at work is in Python and OO-based, and I have limited time to code outside work :) I think that if I was coding a project full-time at work in a functional language, I'd be more inclined to use this paradigm in my own projects.
Without a doubt Elixir is a great GREAT choice and has such a mature ecosystem and tried and tested underpinning that I can understand why anyone would choose it for a project that will run in production. The guys at work have been very happy with it so far, and the language is beautiful and easy to read.
You should ship a single tarball (target system built from a release) that unpacks with everything you need, including the Erlang runtime, and run it. There is no need to install Erlang on the host and better to not use escripts unless it is a user facing cli tool.
I used to like OO, but ever since I got a taste of functional programming with Elixir, I haven’t looked back. It’s a very elegant language and an absolute joy to program in.
Typing is kind of a pain in the butt, it does buy you I would say 20% but when your paradigm is "code the happy path, let it fail if there's a screwup, you'll find it and fix it in another release, it won't bring down the server, the world will still be there", runtime typing errors aren't horrible. Dialyzer for erlang/elixir is quite nice and brings the delta even lower, if you must need type analysis.
Go's type system is atrocious, try multiplying a time interval by an user-input integer. You can't do it. That aside, Go is a fairly good programming language, and I especially like using it for CLIs since there's cross platform guarantee.
I'm not sure what to make of that statement either. It is like saying running a linter on your code makes it slower. It just doesn't make any sense.
If the author argued that annotations made the code slower… maybe. CPython exposes them on, e.g., __annotations__, so, conceivably that would slow down function creation and consume more memory, but my guess would be it would be such a tiny difference that would be vastly outweighed by the benefits of having annotations.
You're right, this was a mistake on my part. I'll correct this in the post. I have used mypy further since the post was written and it is indeed quite helpful, particularly in --strict mode.
I'm often curious as to what people are doing that makes them really think they need to venture outside their chosen scripting language. I use Ruby thinking I'll 'drop to Rust/Crystal' whenever I need to do something "serious", but that need never seems to manifest. Whatever I code in Ruby seems to just do the job and I can solve perf issues with asynchronous constructs like a jobs server, or something like caching.
At this point I'm really starting to wonder if Ruby really is the One True Language and everyone's going to be using it in 100 years. Like how PG thought Arc would be the hundred-year language.
Does static typing really offer that much more over dynamic? I'm not at all convinced that it does, when you get right down to it. Once Ruby gets a built-in typing system, we'll get to answer that question.
I do believe that Ruby will eventually solve its perf problem and once it does, its pleasing syntax and semantics will just draw everyone back to it the same way it did the first time.
I hear you, and I too love Ruby, and I too have yet to actually need the performance benefits of Crystal. But man, you don't realize how awesome static typing is until you actually start using it. There are whole classes of bugs that just get nixed before the program even runs. It makes you think more about how to structure things, how you're passing arguments, how you use variables, etc.
Now maybe you're really really really good w/ Ruby and you don't make those mistakes anymore, but for an "advanced beginner" like myself, it's really helpful.
Yeah, I'm not saying it's not useful, and I can't wait to introduce static typing into my own programs and get those benefits. But every time I step away from Ruby I end up missing it more than the other language gives me. And this is after I figure out how the other language does what I'm trying to do.
To me typing is something you don't want until you really want it, until then it's just boilerplate. That "class of bugs that just get nixed" isn't something that starts happening, once you're skilled anyway, until a certain point in the evolution of your application.
There's a lot of code that I add to my Ruby classes that involves type-checking, and it would be nice to lean on a dedicated system for handling type abstractions rather than doing it ad-hoc every time I have to do it. For that reason, I'm greatly looking forward to Ruby's upcoming type system.
I've been coding since I was 9 years old, made my first web page at 15, I'm 34 now, having been a pro web dev for 5 years. I'm no greybeard, but I'm definitely not a beginner. And I stand by my assertion. Programming languages come and go. I've been watching it happen for over a decade. Ruby's the one language that transcends the normal reasons why they do that.
Other languages fit hardware or chosen domains better or worse, those are the reasons why you'd choose one or the other. Ruby's the only language that fits the mind better.
People have been saying that about Ruby for years, but what I look for is whether Ruby stops solving problems better than other languages do.
My own shop has recently made the decision to replatform onto Node, for no real reason that I can discover. Just seemed to be a "oh let's all go learn the new hotness over here and toss away our existing architecture in order to do it. When something I wanted I found out was unmaintained in Ruby, I almost went along whole-heartedly with this new direction. But I've found something even more fundamental that's unmaintained in Node that's got me back in the "just use Ruby, it works and I know it really well" camp.
Faddish behavior on the parts of developers doesn't really concern me. I was never concerned that all my RDBMS knowledge would get tossed into the shitter when Mongo hit the scene. A steady decline doesn't bother me. COBOL has been declining for 30 years, and you can still make a fine living supporting COBOL codebases.
No, devs can do whatever they want, there's always going to be that pragmatic group of engineers that will use Ruby because it's still the best at what it does.
You live in a bubble. Look up some numbers. From an empirical standpoint ruby is dying. Of course your anecdotal experience trumps all the numbers so my point is invalid.
I've seen plenty of numbers, and I see it being talked about less some places, more others. I don't see any evidence that it is dying. I see evidence there's less hype surrounding Rails, which is great, as I don't like Rails. In any case it is irrelevant, as what matters to my use of Ruby is that my "bubble" keeps expanding and paying more, and producing more software that I benefit from. If it's "dying" outside of that, then that's not a problem.
This idea of languages "dying" to me indicates bubbles of your own - if there's one thing we've seen over most of the history of software it is that programming languages have remained incredibly persistent for decades even after they stop being used in new development, and we're certainly nowhere near that point for Ruby.
That's how I feel about Python. It also feels like it has a unique mental ergonomics.
We're both super biased in that regard; everyone has a language they prefer to think in. Usually a dynamic, malleable one.
Who thought perl would die?
That said, I'm going to agree with sibling comments and give Python one big, big, advantage over Ruby: it's made inroads into a ton more domains such as numerical computing, duct tape programming, bioinformatics, ml/ai etc. It's installed by default in nearly every *nix flavor, mac OS included.
> Ruby's the only language that fits the mind better.
Look, I really like Ruby, too, but the idea that it is the one language that “fits the mind better” and is, for that reason, immune to the normal ebb and flow of language popularity is both amazingly parochial in the first case and empirically false in the last case.
What brought me to that conclusion was my rejection of Scheme. I learned Scheme first, through HtDP, which absolutely blew my mind. I wanted to use Scheme for everything, but instead made the pragmatic choice to learn Ruby so that I could more easily find a job, and just use HtDP concepts in my Ruby programs.
Well after awhile I realized I didn't miss Scheme. Like, at all. I had to really think hard about why. The first insight I had was that, well, syntax really does matter, and the paren-soup just isn't aesthetic.
The second thing I realized was that Ruby's object model is just far more intuitive than any other way of dealing with objects. It's just, well, elegant. Everything's an object, everything has a class. This is what Crystal misses. And it can't because of its static nature, types can't be a class. A certain kind of reflection is impossible.
And this is where static vs. dynamic comes in. Static forces you to write boilerplate. Dynamic lets you write it when you need it. You want dynamic until you want static. It's just that simple. No one is inherently better, they're just better suited to different situations. You want to flow from one to the other, not get handcuffed. This makes dynamic inherently better, because you can build a static type checker on top of a dynamic language, but to put dynamic typing inside a static language is just always going to be a kludge.
If I can get pleasing syntax, an elegant object model, and gradual typing in a language that's also faster than Ruby, I'd jump on it. But every other language makes compromises on these points for one reason or another. Of all three, it seems the object model is the most difficult to implement, but it's one I rely on to get me out of jams. I don't often need metaprogramming, but when I do, it saves me a lot of time. And I've never run into anything else like it save in the Lisps.
If I didn't have Ruby, I'd be using a Lisp. Having metaprogramming available, even if you're not using it, gives a real sense of safety, not against silly bugs, but against the much bigger possibility, of making poor abstractions. In Ruby, once I've realized I've made a bad abstraction, I can take the working code and metaprogram it, keeping behavior working, until it's using the semantics I need from it. This makes me far more confident to just knock up systems as quickly as possible, safe in the understanding that I can turn any semantics into any other semantics when I need to. You can fix the propensity to make type errors in a dynamic language with discipline, but you can't fix the propensity to make wrong abstractions with any amount or kind of discipline that I've ever been able to see.
But I'm also surprised just how much syntax impacts my desire to actually write code. There's something about Ruby's code block delimiters that are more pleasing than either whitespace or bracket delimiters. I don't mind bracket delimiters if the whole block is on one line. But to force me to use brackets for multi-line code blocks, the so-called C syntax, well I don't find it half as aesthetically pleasing as Ruby. Is it just personal preference? Perhaps. But I think a hundred years is going to really clarify everything and languages will lose their utility advantages over each other and so all that's left will be aesthetics. And I think Ruby just has everybody beat in this area.
You point to some interesting aesthetic reasons you prefer Ruby, but aesthetics are highly personal and subjective and simply cannot justify the generalizations you made upthread.
Also:
> Static forces you to write boilerplate.
Not very much, inherently, just most static languages have poor (or no) inference, which forces you to write boilerplate (and often poor type systems, which make some otherwise correct approaches impossible, forcing you to code around the type system on top of writing boilerplate.)
Haskell is kind of eye opening in this regard, in terms of a statically tired language where these problems are minimized compared to most popular static languages.
You are a beginner. Ruby is a dying language that hit it's high point and died and now is at it's at a low point and not going anywhere. It's time has passed like php and now it's used mostly for devops scripting as the technical debt the language accumulates is generally too high even for web apps.
Python, C++, C, Java and javascript are the languages with staying power that came and never went. If you were in the industry that long you'd know that most of the languages I mentioned have serious issues and problems and that the languages staying power has nothing to do with how they fit the "mind" or how good they are.
If you weren't a beginner you'd also note that ruby, like python and like javascript has serious issues when it comes to writing long lasting, reliable code. To code something as reliable and complex as an operating system in ruby would lead to huge amounts of technical debt. As a ruby or python code base grows in complexity it becomes more and more unmaintainable... It would be a mistake to write super complex systems in python or ruby because such systems benefit highly from type checking. Your comments indicate to me that it doesn't matter how long you've been programming... you lack the experience to understand this concept. Ruby is better for scripting then it is for writing applications.
What I have learned over the years is that programming is more about combatting our own faulty human nature, our own propensity to make mistakes. Ironically, the more expressive a language is, the more it gives, us the opportunity to express this fault. Power comes from restriction. Type checking is one such restriction.
You are offering up your lived experience as wisdom without any rationale as to why I should accept your conclusions over my own. Just an endless cavalcade of "you are a beginner and you lack experience." As such it's falling on deaf ears.
I don't have the time to explain the logic behind my wisdom. I can only show you the door as my conclusions are avenues you obviously haven't explored. It's up to you whether you want to take the blue pill or the red pill.
As someone who does a great deal of mysticism and dealt with a great number of wannabe teachers, I can easily tell the difference between those who are coming from a position of true knowledge and those who are just protecting fragile ego. Guess which category I have you in.
My guess is you have me in the category of someone protecting a fragile ego. I assure you I am not. The choice is yours. If you want to see the light I recommend that you look into Haskell and spend a non trivial amount of time learning that language. Otherwise I could care less.
I came to Ruby from 20 years of working in statically typed languages, and I think it largely boils down to how you're used to working. E.g. you need test either way, and properly written tests reveal most of the same typing issues static typing does.
I'd enjoy static typing if I didn't have to sacrifice the flexibility of Ruby, but so far I've yet to see a system with good-enough type inference to make up for the extra ceremony. I hope that will eventually change, but what I've seen of Crystal is not it.
Former Ruby developer here. I believe we will look back at this period where we eschewed static typing as a historical mistake.
Back in the 2000s I was using mostly statically typed languages (Java, C/C++, ObjectPascal), and compared to those, Ruby and Rails seemed like incredible productivity boosters. But we quickly found that the lack of typing led to all sorts of issues. For one, you need really comprehensive tests to determine whether a change breaks anything. Refactoring becomes not just a chore, but genuinely psychologically stressful as you begin to worry about things breaking in production. And they frequently do. Duck typing is elegant, but it only works so far as you know the range of types to expect. I very quickly got tired of checking the validity of arguments in code and doing coercion such as Array(maybe_array_or_maybe_not). And the nils, ugh. I never created so many bugs as when I was writing Ruby code (though JavaScript is a close second).
A language with a rich type system (Haskell, Swift and Rust come to mind) can eliminate entire classes of bugs. Not just by letting you validate the types of arguments and return values, but by letting you describe your program logic in terms of types. It's often said that Haskell programs rarely have bugs once they compile, and while there are no guarantees, it's often true.
Give a statically typed language a try for a while, and you will probably change your mind. I don't know about Crystal, but Go is a decent entry-level language. (Many former Ruby devs seem to enjoy Go quite a bit.)
I'm looking forward to Ruby's upcoming type system. But for now I have no problems leaning on discipline for handling the problems dynamic typing introduces.
> Refactoring becomes not just a chore, but genuinely psychologically stressful as you begin to worry about things breaking in production. And they frequently do.
Beautifully put. The ability refactor confidently is so underrated. It's one of the places where a little bit of verbosity (i.e. Java) pays huge dividends.
> Duck typing is elegant, but it only works so far as you know the range of types to expect.
Go shines particularly well here. In Java code bases, interfaces occasionally accumulate too many methods or interfaces of interfaces start to get unwieldy. I like Go's approach of letting the function declare the relevant subinterface it really needs.
I think part of the beauty of static type systems, for refactoring guiding, is that most (if not all) issues arise at the time of change, when the change is fresh in your mind, locality of reference if you will.
I recently refactored my fork of the linenoise library (written in C) from char to wchar_t. C being statically typed made it easy to find all the places that need to be updated if some declaration is changed from the one type to the other. The editor gathers the compiler errors and takes you to all of them. The result was broken though. For instance, in some places I replaced strcspn (complemented span) with wcsspn instead of wcscspn. It has exactly the same signature. This was caught by testing all the edit operations, and a very careful diff review.
Type checking only works when you make a mistake which breaks a type signature. You can call entirely the wrong function with the right type signature. You can call sin instead of cos, or forget to take a log of something. You an swap the arguments to a subtraction: both are floats. Think of all the numeric code in which lots of variables, arguments, array elements and so on are all of the same type. Or string code in which there are numerous strings. Or OOP code where you have two or more objects in the same scope of exactly the same class, which can get mixed up.
The idea that you do not need a comprehensive test suite because you have static types is horribly wrong.
In my opinion, "1" + 1 should throw an error, the compiler shouldn't try to interpret what you meant. Dynamic typing opens you up to all sorts of bugs that don't happen with static.
That being said, I don't think dynamic typing is going anywhere, and with experience it's not that difficult to anticipate the problems that come with dynamic typing.
It really isn't all that difficult. Coercion works fine for the case you cited, and especially Ruby has specific idiomatic coercion methods with the semantics you'd want. Ruby does in fact throw a TypeError when you call "1" + 1. The issue is that static typing purists want that error to be thrown at compile time.
I don't see that as necessary. Either you have good discipline regarding types where you need it or you don't. And discipline in your coding extends to way more than just type errors. So anything encouraging to develop your discipline is a good thing.
I think what it comes down to is, not having dynamic typing available to me when I want it is going to be more painful overall than not having a type system when I want it. I look at all the static languages today and I see so much validation of this idea that it's not even funny.
> Either you have good discipline regarding types where you need it or you don't. And discipline in your coding extends to way more than just type errors. So anything encouraging to develop your discipline is a good thing.
I think this is maybe the crux of the difference of opinion between static and dynamic afficianados.
I don't want to have to be disciplined. I want to be able to offload as much of the thinking as I possibly can onto my tools. The reason this is necessary is that I'm human, and I only have a human level capacity to not screw things up. If everything is the responsibility of the programmer, then we are limited in our ability to build large complex systems, to the ability of the programmer to manage this complexity. The only way to transcend this human limitation is to put measures in place to prevent things from falling over when humans turn out to be human after all.
Those measures you want are tests. You need them just as much with statically typed systems, but it's often easier to tell yourself you don't. If you compare static code with poor test coverage with dynamic code with poor test coverage, the dynamic code is probably more likely to fail with a runtime error of some sort, but in my experience they're about as likely to fail to produce the intended result. Once you add proper tests, most type errors in the dynamic code tends to get caught without specifically testing for it.
I used to make this argument too, until I actually spent some time writing Ruby, and none of my fears came to pass.
You don’t really need tests for everything.
If you make the invalid state unrepresentable in the type system then, guess what? You don’t need to test for its validity and more importantly you are guaranteed that if it compiles it can’t ever reach an invalid state.
This renders a whole class of tests unnecessary.
While that is true, you still need to test to ensure that your representation matches reality, and in practice when you do that in systems written in dynamic languages you tend to cover most type issues implicitly.
For that matter it's not that hard to write code to statically validate that arguments to a given method are checked against a set of types and that this set does not include a representation of invalid values. (E.g. I can "forcibly" wrap any method with checks). The reason the various libraries to do that haven't gained much traction is that they've rarely paid for themselves in reduced effort compared to higher level tests.
I'm all for more static validation, but I just don't think we have suitable tooling yet to do it at a level that provides sufficient benefit.
You are mixing weak and dynamic typing together.
Weak, as in JavaScript, PHP, does allow "1"+1 stuff and should be burned with fire.
Dynamic strong typing, as in Python, Ruby, does not allow such stuff (though can not be catched at compile time)
It completely depends on your goals. If your primary goal is to build a solid, reasonably scalable web app in a short amount of time, ruby and rails simply cannot be beat.
But if you’re trying to push the envelope somehow on performance, concurrency, safety, number-crunching, or system design, or you need a portable binary, then it makes sense to choose a language that has tools and abstractions better suited for those tasks.
Ruby's poor at portability, but that's a solvable problem. For everything else, Ruby's got advantages. It really can't be beat regarding safety. Performance can be fixed with native extensions, which ironically are a large source of the portability problems. It's not as good at concurrency as say, Erlang, but it's got the primitives you need and they are first-class parts of the language. Number crunching is just an application and Ruby excels at application building. Just don't ask for a native interface, lol. Shoes is great and all, but it's just a baby.
I think it's a toss up between Python and Ruby, but my bet is on Python.
Python is simple by design. It has optional typing (as of 3.6), beautiful async constructs (ala ES6), nice integration with C/assembly (in CPython), comprehensive open-source software ecosystem, and many strong alternative interpreters.
Ruby feels like it's playing catch-up in every area except metaprogramming... and, while I really enjoyed metaprogramming as an experienced engineer, I'm kinda glad Python lacks that complexity.
> I think it's a toss up between Python and Ruby, but my bet is on Python
What on earth could make you people think Ruby is even a contender? Do you ever look at ANY language usage stats?
If there is a toss-up in dynamic languages the toss-up is between Python and JavaScript and with JavaScript's dominance in the front-end and Python's in data science it's likely to be a turf divide rather than a toss-up.
That doesn't really matter to my arguments. I've used front-end and back-end web dev merely as examples of main drivers of each technology. What matters is that growth of Ruby and related technologies in recent years has been negligible (it has been in free-fall for the last few when considering relative figures actually), and the singular instance of it's major growth was during the 37Signals/Rails era ergo web dev.
> Does static typing really offer that much more over dynamic?
Yes, but it comes with a heavy trade-off if you have an insufficiently expressive type system and/or an excessive need for explicit incantations to the type checker.
As a user of Common Lisp that is lately learning Ruby, i am amazed at how weak the type system is and how many stuff that would immediately cause a compiler error in Lisp (like asking values from class members that don't exist) simply pass silently with no error (not even at runtime) in Ruby.
Since every call is a method, and a method belongs to an object, the type of this object is significant. Base Ruby language gives you no way to declare that object X shall be of class C.
So, well, there are dynamic languages and there are dynamic languages.
Crystal looks great in many ways, but it's hard to go all-in with a new language that lacks parallel processing. Go, Elixir, and Rust all have great concurrency stories, and their adoption has a lot to do with that.
It is a gorgeous language, though, with a very easy to read syntax. I'd love using it if it had something like goroutines, which would look great with its block syntax. Good luck to the team working on it; I hope it's a contender.
This seems a bit confused. You complain about parallelism, but then raise other languages for their concurrency stories. Concurrency is not dependent on parallelism and indeed Crystal do have a nice concurrency story with fibers and channels that perform pretty well.
It's like a language was picked first and then the blog written backwards to come to the conclusion. So there's some languages in bullets and subjective pieces that are reasons not to use them. I can do that with Crystal too...it doesn't even support one of the most popular OS's natively. I mean, the author says C++ is a better language than Go, that Google is the ultimate reason for success, and that Go takes us back to C. That doesn't even make any sense. "doesn't seem to click to me...generally didn't feel...feel the language is rough" etc. How about just use the best language for the problem, instead of choosing the language before the project. As I've mentioned on many of these language-comparison posts (more like tweets) these days, just ignore them and remain wise to your problem space. They are very juvenile.
In my view, programming language choice is cultural yet is always framed as something objective. It is even possible to "use the best language for the problem"?
Even if it were possible to evaluate all current alternatives, we lack knowledge of the future and therefore can't reliably include important factors such as ability to hire into the team.
> It is even possible to "use the best language for the problem"?
Not perfectly because "best" is subjective. My advice is to let the problem and goals help you dictate (yes, even on hobby projects and even if one of the goals is trying said language). In fact, if you are a hobbyist evaluating languages, you should try them all out with reasonable projects where you can instead of write a post saying how you are moving from a single one to another single one.
> In my view, programming language choice is cultural yet is always framed as something objective.
I agree, and think that the culture around a programming language is one of the most important attributes, so we should not be afraid to talk about human factors like cultural fit. Your choice of programming language is usually limited to a short list of the ones that have the tools and libraries to support what you are doing, but IMO it's perfectly reasonable to choose a particular language because you and your team like the culture. If you decide to use a programming language in production, you might have to live with it for a long time.
I really like this[1] talk from DHH on the subject, where he talks about the misconception of many programmers that we are doing science rather than something creative. While laced with hyperbolic statements it is at the very least thought provoking on some of the things that we do as developers.
"In my view, programming language choice is cultural yet is always framed as something objective."
I think that's an objectively false statement.
There are many objective metrics by which a programming language may be evaluated. Conciseness, clarity, suitability for realtime applications, and efficiency come to mind.
"It is even possible to "use the best language for the problem"?"
It's certainly possible to use a suitable language for the problem. Some problems are more forgiving than others, of course...
I will say that the idea of a "general purpose" programming language, suitable for most tasks, is a good one. The current multitude of languages, while fun and good for exploring new ideas, is taking a lot of brainpower away from actually producing working systems. Also, I'll claim that there's no reason that most programs shouldn't be written in an efficient language, and in fact there may be a push for that in the name of datacenter efficiency.
It's sad that the most written programming language today is Javascript.
> It make senses to half the users of this site. The other half, well, I guess their jobs depend on it not making sense.
Not sure what you mean here, but comparing Go and C negatively (even though quite unrelated) whilst praising C++ makes little sense. Even if you frame it in the way the author did that C++ has classes and C and Go doesn't, Go's lack of classes is no more primitive than any other modern lang w/out classes. And that doesn't even get into arguments on conflating OO and classes. These pro/con discussions always devolve into this mess and can be picked apart, that's why they are rarely worth having at such a high level.
> I should add that I have no interest in Crystal
I have interest in all of them.
> It’s just obvious that Go enjoys more success than it technically merits.
You said more success, the post said Google backing is what "ultimately resulted in its success". Those aren't the same thing. I doubt anyone would disagree that it helps, but I doubt anyone reasonable would agree it is the sole reason why.
It's not like D or Kotlin Native or Swift or others got a fair shake here. These just aren't good posts and I struggle to find any benefit in them.
The “Go is successful because of Google” is really wearing thin. For this to have any credibility we would have had to see the same effect on any of Angular, Polymer, Dart, Flutter, GWT and whatever else Google put their weight behind that we’ve already forgotten.
Of all those things, Google only really put their weight behind Angular, and Angular 1 was incredibly popular for a while. I still frequently see it in the job postings of other companies.
I doubt Go is only successful because of Google, but a large corporate sponsor seems to make or break most languages.
Angular is widely successful in the enterprise, being the JavaScript framework mostly adopted by Java and .NET developers.
Dart hardly had any major Google backing, it looked like a way to keep some well known VM researchers busy, which were rescued by the AdWords team before the project kind of folded.
Flutter looks like some of those developers trying to find a killer application for Dart, while being allowed some air time on Google's conferences, while Google management is full speed on Android and Web stacks.
Polymer has never about the framework, rather a way to push WebComponents as sane way to do web development, which up to HTML Templates they have been quite successful regarding adoption across browsers.
Not only all that you mentioned, but picking a language isn't like it was 25 years ago.
Some hypothetical "best language in the world" is irrelevant without the tooling and ecosystem around it. "BLITW" still sucks if might as well write the code in Notepad because the editor/IDE integration sucks. "BLITW" sucks if the community consists of 8 people on github.
I hear of Crystal a couple/3 years ago, and it sounds neat on paper - a statically-typed, fast Ruby. Cool, but it's completely meaningless to me because it doesn't fit into any ecosystem that me or most developers care about.
Absolutely, as an anecdote: I keep coming back to Java for non-trivial projects not because of the language itself at all, but because of Maven Central, Gradle and the rest of the very mature CI ecosystem with Java.
In practical terms, you're right, of course, but also...
> "BLITW" still sucks if might as well write the code in Notepad because the editor/IDE integration sucks.
We have better editors than notepad that work with any language, and there's plenty of people getting work done with fairly barebones editor setups making no use of language integration at all.
> "BLITW" sucks if the community consists of 8 people on github.
While adoption and library availability are clearly huge factors, they're not necessarily absolute requirements. There are plenty of good (and surely also many bad) reasons why many real-world codebases are practically isolated from the wider community despite being written in a widely adopted language.
If some language was clearly the best in the world, or even just demonstrably superior in a way that is meaningful to whatever your requirements are, it can be a totally reasonable decision to choose that language for your project even though you won't be able to reach to github for a lot of conveniences, you'll have to write code in stock vim and you'll have to invest some extra time to get new contributors up to speed.
I don't know if Crystal is that language, I'm not even in a great hurry to try it to find out, but I feel like if I waited until a language had reached Go levels of mindshare before taking it seriously I'd probably be missing out.
While your grievances are valid, I feel like you're missing the point. Or perhaps you think of programming than he does. It is certainly true that in a situation where all you want to do is get a task done, then what you should really think about is the best tool for completing the task (sometimes its a spreadsheet but programmers will often go for a little python instead). But in the case where your just programming for the sake of programming. Where programming is the ends and the problem you're solving is the means, this is where the nit-picky language comparisons blogs I think start to happen and I think its great.
You make a fair point and I totally respect your opinion.
I was ultimately looking for a versatile language that I could use for my personal projects outside of work and thus I was indeed trying to find a single language that could do everything I wanted. Up until this point, that language has been Python.
Go is clearly sufficient for many very successful and amazing projects (many of which I use daily, like Hugo, Terraform, Docker .etc), so developers can still produce excellent tools with its limitations. But in saying that, the language is not for me, and that's okay; if it works for someone else, then that's okay too. Go does lack various features that many developers want, including me.
Fun fact, the blog post was generated by Hugo ... which is written in Go :)
With regards to Nim, yes, my experience with Nim is limited and I am still hoping to learn it further and do a more thorough evaluation. Hopefully I'll spend a good amount of time with Nim in the future to give it more of a fair go.
> Go [...], so developers can still produce excellent tools with its limitations.
I really found "still" to be funny because I think for many Go devs (including me) the simplicity and lack of features especially enables us to create more easily.
It's the opposite of standing in front of giant fridge shelves in the supermarket with 100+ kinds of yoghurt where you have a hard time deciding. You only have a few choices so you just go ahead and pick one/just do it.
I'm not sure what your point is.. is it: "More features are better"?
I started programming a few years later than you.. first on Atari ST (Basic) then later in DOS (Pascal). I often wish myself back to these systems when I see today's bloated stacks of crap (obviously this does not apply to everything).
I don't think this is relevant for the original discussion though..
Useless to those that didn't understood how to take advantage of them.
They can be used as indexes, range validation, access control in variant records to simulate sum types.
Enumerations are so useless that majority of modern languages have direct support for them.
Yes, it did allow your contrived example, which seldom occurred in practice because proficient Pascal programmers only used pointers when other type safe alternatives weren't possible.
>I really found "still" to be funny because I think for many Go devs (including me) the simplicity and lack of features especially enables us to create more easily.
Yeah man, it must be so fun doing large-scale construction work with just a hammer and a shovel; so easy to use, so easy to learn. Who needs caterpillars, pneumatic drills and such.
Last time I checked, Brainfuck is easier to learn than Go (more simplicity!!!, and runs in even more platforms.
The Amish manage to build large barns entirely like this in much less time than it would take the average construction firm. It depends heavily on what you're building on if you actually need a lot of those tools.
Just like if you're building a small tool to wrap another you might just choose to use bash over Java, it all comes down to what you need most commonly vs what would "be nice to have".
Your reply seems a little emotional.. I wonder why. Nobody is forcing Go on you. You can do all large-scale construction work with greater tools like Lisp or Haskell as it is commonly done.
I don't agree that Go has only "a hammer and a shovel". It has at least a saw in its toolbox too.
On a more serious note.. fun is highly subjective and the brainfuck / simplicity argument is just useless.
I personally recommend choosing the language after you know the personal project you'll be working on. For instance, I hate Go's lack of expressiveness but ended up choosing it for a personal project due to the strength of its crypto libraries. Also, if you can spare the time, creating full blown, open projects in languages can help your well-roundedness. My comment was meant to be less about Go and more about dismissing languages outright. I'm hoping the next post is about how awesome Crystal is sans unfamiliarity of other options.
>I mean, the author says C++ is a better language than Go, that Google is the ultimate reason for success, and that Go takes us back to C. That doesn't even make any sense.
It makes perfect sense. In fact that's what the Go developers themselves found out -- that C++ programmers, who they thought they would be attracted to Go, passed it over, and instead Go gained dynamic language converts.
Agreed. Would make Go much more suited to the kind of stuff I do -- although it still has several drawbacks as a language (warts and idiosyncratic decisions that are not really based on any utility), it hits a good spot of convenience and popularity (which means ecosystem growth) for certain tasks.
Personally, I'm actually a long time C++ programmer (and loving it, at the time!), who abandoned it and run away full steam with Go (loving it even more). So, always when I hear the above claim, I wonder: am I, like, "the only one"? A curious specimen? Or is there more of us, just maybe we don't speak up?
>I wonder: am I, like, "the only one"? A curious specimen
Considering that Go doesn't even do well (and has horrible library support) for most of the stuff C++ is used for (GUI apps, 3D, AAA games, systems programming, high performance scientific calculations, etc), probably yes.
Now, if you did network servers with C++, probably Go is a better/easier/smaller surface fit.
I worked as a C++ developer for three years and switched to Go development this year. I used to love making a "generic" solution to a given problem using templates in C++. Now I find myself without even a decent data structure in the Go standard library. Have you seen the way priority queues are implemented? Just a terrible design choice.
Author said it takes us back to C and you are saying it makes perfect sense that it gained dynamic language converts? By your argument, it is passed over by C programmers too making the original statement also not make sense when framed that way. Or maybe you meant only the first part made perfect sense?
I think the best lens to view this blog post through is shown in the quote far down in the article:
> I plan to only use this language in my personal projects
I think this is more a blog post about what language the author finds most interesting and exciting, not the language the author is suggesting people use for work.
Precisely, at work we use Python and C++, but I wanted to learn a new language in my own time for fun :)
I also tried to highlight its weaknesses in the Caveats section. The language is young and often has breaking changes which would not be suitable for production at this time, particularly in larger organisations.
However, I think the language shows great promise and will appeal to a lot of people as it matures. I'm certainly enjoying it so far! :)
Hey guys, thanks for reading my blog post and posting it on Hacker News. :)
It was just an informal brain dump for me and nothing too serious, so please don't take anything to heart. And indeed, I have only spent a limited amount of time with the other languages on my list. I still intend to keep a close eye on them all as time goes on.
I'll try to respond to various comments :)
Update: Hacker News is rate limiting me, sorry folks. I'll try again to post some replies in a little while.
Thanks for posting! The crowd can get harsh and maybe not everyone realizes that making it onto the HN front page briefly != "This is proven research and you should all listen to me right now". Blogging can be about learning and brain dumping and, IMO, you should carry on doing so.
Thanks a lot for the encouragement, it means a lot :)
It is tough to read criticism but it's always a good opportunity to learn. The comment about mypy for example was correct and I'm pretty sure I'll be trying it out on my next Python project. I've updated the blog post with minor amendments and corrections based on the feedback here.
Indeed this was my first time on HN (which took me by surprise) :)
Newline is not equivalent to semicolon (or your last example would fail), but Ruby treats a newline as terminating an expression if in a production in the grammar where terminating the expression is valid.
In terms of "void", Ruby has no such thing - every expression has a value, though that value can be nil (and somewhat confusingly "( )" is an expression that evaluates to nil).
So your first example is two expressions, and evaluates to 7 when the whole thing is evaluated, not 3 - if you evaluate it in irb etc. you might see 3 because the first expressions is itself complete, and so will cause output.
Your second example is a list of the expressions "1 + 2" and "3+4", which evaluates to 7, because as for the first example, the last expression evaluated is what will be returned outside of a read-eval loop like in irb.
The last example is a single expression because "1 + 2 +" is a syntax error on its own.
I can understand you find it quirky, but you generally only need to consider that if you want to break up an expression you need to ensure it does not stand on its own.
Re "void" I'm referring to rubocop warnings like "Operator + used in void context."
Here's another oddity; irb behaves differently for some expressions.
not_defined = "#{not_defined}"
=> ""
:-/
Anyway, the parens things bothers me the most. In most (all?) other languages, putting parens around a multiline expression would make it one atomic expression.
Yeah, I understands it's confusing. The Ruby grammar does have some dark corners like that where the side effect of trying to make it possible to make things as free of punctuation as possible causes weirdness elsewhere.
Putting parens around it does make it one atomic expression though, it's just that in effect the "operators" are ;/lf, and these "pseudo-operators" return the value of the last sub-expression, and binds tighter than parens,
I can't actually remember seeing any one relying on grouping expressions with (), though, which is probably just as well.
(I'm sure someone will now come up with an "essential" use of it)
You get the JVM ecosystem with a modern syntax.
It's a higher investment then Nim/Crystal but also has higher payoff due to existing libraries and peak performance of the JVM.
I'm not going to list all the ways Kotlin is superior to Clojure for real development but suffice to say the two aren't really comparable when you have a team of programmers with heterogenous backgrounds.
However I do want to note that Kotlin having great IDEA integration is not lock-in. You can (and I sometimes do) code Kotlin + gradle with a pretty vanilla vim setup.
Clojure has one big advantage and it's also it's biggest weakness. It's a Lisp. I love Lisp's but I would never want to use one in a professional setting.
You can use Lisp in professional settings. Lisp has been used successfully in teams from 2 to 100 people with source-code bases of upto 10 million lines. The usual things apply: a good team, a good development environment, tests, documentatiom, etc.
From a recovering OO developer: one of the things I find funniest now is that OO is constantly treated as a plus in these “why I picked” posts, while I’ve long concluded that the cost of this easy polymorphism is way too high.
I would love to see Crystal take off but it seems like some decent funding/backing and then some time to settle from there will be needed. I seriously hope that can happen; but, who knows.
I think this thread has no shortage of criticisms, but too many are uninformed. The blog post doesn't mention these important things:
Package management (from [0]): "Crystal libraries are packed as Shards, and distributed via Git without needing a centralised repository. Built in commands allow dependencies to be easily specified through a YAML file and fetched from their respective repositories."
Concurrency (from [0]): "Crystal uses green threads, called fibers, to achieve concurrency. Fibers communicate with each other using channels, as in Go or Clojure, without having to turn to shared memory or locks."
Will this join the ranks of Julia, Rust, Go and the others?
I'm skeptical because the last few years I've seen these trends come and go on HN. They do nothing but scatter my focus. I've learned to ignore them now though.
199 comments
[ 3.0 ms ] story [ 245 ms ] threadWebsite: https://crystal-lang.org/
Github: https://github.com/crystal-lang/crystal
Ultimately, I had to choose something to commit to for a while as there are just not enough hours for me to learn multiple new languages outside of work and with my various other hobbies.
But rest assured that Nim was absolutely a front-runner and I'm happy to update the post to reflect this.
I do too, and that's exactly why you should use Nim. It is, perhaps, the only language in which the variables "camelCase", "camelcase" and "camel_case" are the same (though CamelCase isn't) -- so you don't have to follow braindead Java principles if you don't like them.
And if you really insist, it is quite easy to write a simple program that will unify the styles for you. In practice, it's not a problem.
In this respect, Nim inherits pascal's case insensitivity, and just adds a few minor and arguably useful details (underscores are ignored, case of first letter preserved). It was never a problem for Pascal (or BASIC, or Excel, or NTFS or HFS+) and it's not a problem in Nim.
And being an early Python advocate and evangelist, I feel history is rhyming again .. ."What? You use significant spaces ? That's so stupid, and bound to make everything fail. Yes, some people still dislike significant indentation, but by and large, experience shows that it's not inferior[0] to token block delimiters, and in some ways it is superior.
[0] as long as tabs are a syntax error ....
This is what style insensitivity is meant to fix. In reality, you are able to tell what style a code base uses almost immediately and grep accordingly.
I find this horrifying and think it probably reflects deep philosophical differences between myself and the creators of Nim. Languages shouldn't make assumptions and how to interpret my typos. They should tell me about the typo and suggest a possible fix.
What you say is equivalent to "I want to be able to declare three independent variables called camelCase, camel_case and camelcase", and Nim says "no, you can't do that in the same scope" (which is a little more strict than pascal which says "you can have camel_case distinct from the other two, but those two are equivalent).
Experience shows that case sensitivity is harder to use in general[0]; "Although we resisted changing the Python implementation, our user testing data forced us to make ... Python case insensitive. Over 85% of our users made case errors and many continued to do so even after learning that case was significant." it's just that you're used to it; same with respect to int/int vs true division.
I'm feeling an almost dejavu to the early days of Python, when the standard response (which people still repeat sometimes, though rarely these days) was "what!?!? you mean spaces are significant!?!? that's horrible". But this is equivalent to saying "I want to be able to write code that behaves differently then it looks, such the C code:
(The like of which make iPhones and Macs susceptible to eavesdropping for a long time). Python says, "Nah, you can't do that". It's opinionated, but experience shows it works better overall.[0] page 5 of http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.908... - all of it is a fantastic read.
And why are case errors a big deal in case-sensitive languages if they cause "undefined" errors or, better yet, are caught by static analysis?
(To your point about Python, I still think semantic whitespace is insane -- invisible code, as you implied -- and is a major reason I avoid Python when possible.)
The “optional namespaces” thing is something which bugs me a lot though. That importing a module works similar to `from module import *` in Python. It makes code confusing to read and grasp IMO (which module does this symbol come from?). Other than that, a pretty cool language.
This is a common complaint, but there is rarely a solution proposed alongside the complaint. Nim is significantly different from Python to warrant these semantics, but I am really open to hearing ideas of how this could be improved keeping in mind these differences (operator overloading, no classes).
A recent proposal was made here, and it looks like it will be adopted, I'd love to know what you think about it:
https://forum.nim-lang.org/t/3783
So no offence intended at all to any Nim fans, and I hope to dive into it more thoroughly in the near future.
Crystal has a surprising amount of web frameworks with great marketing behind them. Could that just be because it's a Ruby-like language, and Rubyists are far more interested in web frameworks?
That's my theory, but I could be totally wrong. I'd love to know how we could improve here.
Perhaps it's because I created a web framework that is good enough (jester) early on and so nobody feels like stepping in with their own implementation. A website for jester would be great and it is on my to-do list, but so are many more things.
From what I’ve seen for Jester/Nim, it’s not really benchmarked a lot, and it doesn’t seem particularly fast where it is benchmarked. This could perhaps be fixed by better implementations for the benchmarks or some optimization in Jester itself.
I think a strong story for performance would go a long way towards improving awareness of Nim. Crystal does very well in such tests, and I think that is one of the most appealing parts of the language. In fact, I evaluated both Nim and Crystal for server side development a while back, and quickly dismissed Nim because it didn’t seem to be all that fast. I eventually dismissed Crystal too because of the compile times and syntax, but I put a lot more time into it.
So what do I mean by theoretical performance? Well, Nim is a statically typed and compiled language, it stands to reason that these attributes make it very performant indeed. Even if certain aspects of the language are not efficient right now, you can bet that it will be fairly trivial to improve their performance. For languages like Python, Ruby, etc. you are heavily limited by the dynamic typing (which restricts the amount of information you have about the code) and the fact that they are primarily interpreted languages. You will need to put far more effort into optimising them than compiled languages.
As a side note, I do intend to improve the performance of Jester as well. But I'm not the only one doing this, the mofuw framework is #24 on the TechEmpower benchmarks right now.[1]
1 - https://twitter.com/nim_lang/status/1004849910699712513
If the speed of an HTTP framework impacts your application you have an architecture problem.
Nim CPU, memory and compile time performance are excellent in most benchmark.
https://github.com/nim-lang/nimble
Well, along the lines of what is already mentioned, I stumbled on web communication aspects (I like the available template system, it performs well) and ran into glitches with the mongo or postgresql drivers as I got deeper. I am glad that Nim doesn't have a Ruby-like syntax -- Nim's current type structure/syntax is its strength, IMHO.
(I wanted to contribute some money to the team but PayPal is the only option even if the site says it can take Visa etc. PayPal is something that I avoid due to past experiences)
Thanks! :)
> I wanted to contribute some money to the team but PayPal is the only option even if the site says it can take Visa etc. PayPal is something that I avoid due to past experiences
There are many ways to donate to us, I guess we need to spruce up the donation page, the "Other ways to donate" is buried at the bottom: https://nim-lang.org/donate.html
also pure Java with latest goodies (type inference, functional libs) may not be that bad choice nowdays.
https://github.com/apple/swift/blob/master/docs/ABIStability...
What do things look like these days that make you think server-side Swift is viable?
I have started using Vapor to write microservices where I would have used Rails-api in the past and the performance is astounding but you still get the ease of use typical of Rails. The Vapor ORM works pretty great so you get ActiveRecord style sugar but with pretty great performance.
Perfect is another server-side framework that is popular, but Vapor won me over because I feel like it was a more approachable community.
Basically Vapor feels like circa 2006 Rails in terms of momentum.
And it’s crazy fast and the toolkit seems to be evolving quickly.
Admittedly, this is a somewhat naive assumption, but it also based on my experience of Scala/etc. languages building on top of the JVM.
Any input/data on that opinion?
The Objective-C interop features of Swift are there for interaction with Apple's frameworks on their platforms.
The only swift IDE's I know of are the JetBrains one (AppCode, I think?) and xcode. Neither of them runs on Linux. There are a few plugins for existing IDE's but nothing that's great yet.
IBM is surprisingly into swift, so I wouldn't be surprised if Eclipse eventually gets first class support for it but it hasn't happened yet.
I definitely recommend digging into server Swift to form your own opinion. Vapor is a good, gentle starting point because the tooling to get up and running is pretty nice; it’s not a huge investment to play.
*edit: with O2 I get a dramatic improvement and the C and C++ versions compile to essentially the same disassembly. Using O1 is definitely not going to produce an apples to apples comparison.
fots ~ $ gcc -O -o fib fib.c
fots ~ $ time ./fib
433494437
real 0m0.749s
user 0m0.743s
sys 0m0.003s
fots ~ $ gcc -O3 -o fib fib.c
fots ~ $ time ./fib
433494437
real 0m0.747s
user 0m0.742s
sys 0m0.003s
fots ~ $ gcc -O2 -o fib fib.c
fots ~ $ time ./fib
433494437
real 0m0.741s
user 0m0.737s
sys 0m0.003s
Clearly this is just a little mathematical algorithm and more real-world problems would likely produce a more dramatic difference.
What sort of differences did you see on your end?
Most likely function call overhead (and in the slower cases, interpreter overhead) is probably what is being measured in the best case.
[1] In that it won't be a jump and check style loop.
Quite likely: https://godbolt.org/g/xGkCyA although it really depends on the compiler (gcc is smarter here). He also seems to be benchmarking printing more than anything else (hence the difference between C and C++).
Without versions of the compilers and explained methods of measurement, the results posted on the blog are more anecdotal knowledge than any kind of benchmark.
Also this entire article seems to be content marketing for crystal.
And, oh, btw, crystal isn't windows compatible.
And I chose Fibonacci as a fun little test which I even stated in the post. It should be obvious that this is not an overall indicator of performance for all use cases.
For many of us, Windows isn't our target platform so the Windows compatibility isn't a deal breaker. I understand that this is a big problem for many though and there is evidence that the Crystal team are on it; see https://github.com/crystal-lang/crystal/issues/5430.
Please don't take the post too seriously, it's not intended to be and clearly everyone will have different preferences and tastes as is the case with anything in life.
It blows up the stack* and doesn't exercise much else.
(In a typical naive implementation in a procedural style as demonstrated here)
[0] - http://devan.blaze.com.au/blog/2017/10/28/racing-along-build...
The lack of a single binary isn't a fully fair criticism. While technically it is true, it doesn't describe the shipping experience. You will need Erlang installed on the target machine, but using escript you basically ship a "single binary/file" and it includes everything it needs to run. It's quite elegant, and erlang is super easy to install on basically all *nix systems.
Plus the run time gives you benefits that you're not getting in any server side language that doesn't run on the BEAM. There's BEAM and everything else...and everything else is a really crowded field.
A lot of this comes down to the fact that one has to really commit to a functional mindset and go all-in like my friends at work have. This wasn't a commitment that I was personally ready to make, especially since all the programming I do at work is in Python and OO-based, and I have limited time to code outside work :) I think that if I was coding a project full-time at work in a functional language, I'd be more inclined to use this paradigm in my own projects.
Without a doubt Elixir is a great GREAT choice and has such a mature ecosystem and tried and tested underpinning that I can understand why anyone would choose it for a project that will run in production. The guys at work have been very happy with it so far, and the language is beautiful and easy to read.
Go's type system is atrocious, try multiplying a time interval by an user-input integer. You can't do it. That aside, Go is a fairly good programming language, and I especially like using it for CLIs since there's cross platform guarantee.
time.Second * time.Duration(userInputInt)
https://en.wikipedia.org/wiki/Dimensional_analysis
For the record, at least two languages, F# (which is statically typed) and Julia (which is strongly typed) do this 100% correctly
If the author argued that annotations made the code slower… maybe. CPython exposes them on, e.g., __annotations__, so, conceivably that would slow down function creation and consume more memory, but my guess would be it would be such a tiny difference that would be vastly outweighed by the benefits of having annotations.
At this point I'm really starting to wonder if Ruby really is the One True Language and everyone's going to be using it in 100 years. Like how PG thought Arc would be the hundred-year language.
Does static typing really offer that much more over dynamic? I'm not at all convinced that it does, when you get right down to it. Once Ruby gets a built-in typing system, we'll get to answer that question.
I do believe that Ruby will eventually solve its perf problem and once it does, its pleasing syntax and semantics will just draw everyone back to it the same way it did the first time.
Now maybe you're really really really good w/ Ruby and you don't make those mistakes anymore, but for an "advanced beginner" like myself, it's really helpful.
To me typing is something you don't want until you really want it, until then it's just boilerplate. That "class of bugs that just get nixed" isn't something that starts happening, once you're skilled anyway, until a certain point in the evolution of your application.
There's a lot of code that I add to my Ruby classes that involves type-checking, and it would be nice to lean on a dedicated system for handling type abstractions rather than doing it ad-hoc every time I have to do it. For that reason, I'm greatly looking forward to Ruby's upcoming type system.
Other languages fit hardware or chosen domains better or worse, those are the reasons why you'd choose one or the other. Ruby's the only language that fits the mind better.
I do professional work in Ruby currently, but Crystal is just so much more pleasant to work with.
My own shop has recently made the decision to replatform onto Node, for no real reason that I can discover. Just seemed to be a "oh let's all go learn the new hotness over here and toss away our existing architecture in order to do it. When something I wanted I found out was unmaintained in Ruby, I almost went along whole-heartedly with this new direction. But I've found something even more fundamental that's unmaintained in Node that's got me back in the "just use Ruby, it works and I know it really well" camp.
Faddish behavior on the parts of developers doesn't really concern me. I was never concerned that all my RDBMS knowledge would get tossed into the shitter when Mongo hit the scene. A steady decline doesn't bother me. COBOL has been declining for 30 years, and you can still make a fine living supporting COBOL codebases.
No, devs can do whatever they want, there's always going to be that pragmatic group of engineers that will use Ruby because it's still the best at what it does.
So if Ruby is "on a steady decline" someone forgot to tell my customers and employers.
This idea of languages "dying" to me indicates bubbles of your own - if there's one thing we've seen over most of the history of software it is that programming languages have remained incredibly persistent for decades even after they stop being used in new development, and we're certainly nowhere near that point for Ruby.
COBOL programmers are in hot demand because there are so few left that even the few positions where they are needed outnumbers them.
Look at objective numbers on language popularity, job boards, etc... You'll see that Ruby has pretty much vanished.
We're both super biased in that regard; everyone has a language they prefer to think in. Usually a dynamic, malleable one.
Who thought perl would die?
That said, I'm going to agree with sibling comments and give Python one big, big, advantage over Ruby: it's made inroads into a ton more domains such as numerical computing, duct tape programming, bioinformatics, ml/ai etc. It's installed by default in nearly every *nix flavor, mac OS included.
Look, I really like Ruby, too, but the idea that it is the one language that “fits the mind better” and is, for that reason, immune to the normal ebb and flow of language popularity is both amazingly parochial in the first case and empirically false in the last case.
Well after awhile I realized I didn't miss Scheme. Like, at all. I had to really think hard about why. The first insight I had was that, well, syntax really does matter, and the paren-soup just isn't aesthetic.
The second thing I realized was that Ruby's object model is just far more intuitive than any other way of dealing with objects. It's just, well, elegant. Everything's an object, everything has a class. This is what Crystal misses. And it can't because of its static nature, types can't be a class. A certain kind of reflection is impossible.
And this is where static vs. dynamic comes in. Static forces you to write boilerplate. Dynamic lets you write it when you need it. You want dynamic until you want static. It's just that simple. No one is inherently better, they're just better suited to different situations. You want to flow from one to the other, not get handcuffed. This makes dynamic inherently better, because you can build a static type checker on top of a dynamic language, but to put dynamic typing inside a static language is just always going to be a kludge.
If I can get pleasing syntax, an elegant object model, and gradual typing in a language that's also faster than Ruby, I'd jump on it. But every other language makes compromises on these points for one reason or another. Of all three, it seems the object model is the most difficult to implement, but it's one I rely on to get me out of jams. I don't often need metaprogramming, but when I do, it saves me a lot of time. And I've never run into anything else like it save in the Lisps.
If I didn't have Ruby, I'd be using a Lisp. Having metaprogramming available, even if you're not using it, gives a real sense of safety, not against silly bugs, but against the much bigger possibility, of making poor abstractions. In Ruby, once I've realized I've made a bad abstraction, I can take the working code and metaprogram it, keeping behavior working, until it's using the semantics I need from it. This makes me far more confident to just knock up systems as quickly as possible, safe in the understanding that I can turn any semantics into any other semantics when I need to. You can fix the propensity to make type errors in a dynamic language with discipline, but you can't fix the propensity to make wrong abstractions with any amount or kind of discipline that I've ever been able to see.
But I'm also surprised just how much syntax impacts my desire to actually write code. There's something about Ruby's code block delimiters that are more pleasing than either whitespace or bracket delimiters. I don't mind bracket delimiters if the whole block is on one line. But to force me to use brackets for multi-line code blocks, the so-called C syntax, well I don't find it half as aesthetically pleasing as Ruby. Is it just personal preference? Perhaps. But I think a hundred years is going to really clarify everything and languages will lose their utility advantages over each other and so all that's left will be aesthetics. And I think Ruby just has everybody beat in this area.
Also:
> Static forces you to write boilerplate.
Not very much, inherently, just most static languages have poor (or no) inference, which forces you to write boilerplate (and often poor type systems, which make some otherwise correct approaches impossible, forcing you to code around the type system on top of writing boilerplate.)
Haskell is kind of eye opening in this regard, in terms of a statically tired language where these problems are minimized compared to most popular static languages.
Python, C++, C, Java and javascript are the languages with staying power that came and never went. If you were in the industry that long you'd know that most of the languages I mentioned have serious issues and problems and that the languages staying power has nothing to do with how they fit the "mind" or how good they are.
If you weren't a beginner you'd also note that ruby, like python and like javascript has serious issues when it comes to writing long lasting, reliable code. To code something as reliable and complex as an operating system in ruby would lead to huge amounts of technical debt. As a ruby or python code base grows in complexity it becomes more and more unmaintainable... It would be a mistake to write super complex systems in python or ruby because such systems benefit highly from type checking. Your comments indicate to me that it doesn't matter how long you've been programming... you lack the experience to understand this concept. Ruby is better for scripting then it is for writing applications.
What I have learned over the years is that programming is more about combatting our own faulty human nature, our own propensity to make mistakes. Ironically, the more expressive a language is, the more it gives, us the opportunity to express this fault. Power comes from restriction. Type checking is one such restriction.
I'd enjoy static typing if I didn't have to sacrifice the flexibility of Ruby, but so far I've yet to see a system with good-enough type inference to make up for the extra ceremony. I hope that will eventually change, but what I've seen of Crystal is not it.
Back in the 2000s I was using mostly statically typed languages (Java, C/C++, ObjectPascal), and compared to those, Ruby and Rails seemed like incredible productivity boosters. But we quickly found that the lack of typing led to all sorts of issues. For one, you need really comprehensive tests to determine whether a change breaks anything. Refactoring becomes not just a chore, but genuinely psychologically stressful as you begin to worry about things breaking in production. And they frequently do. Duck typing is elegant, but it only works so far as you know the range of types to expect. I very quickly got tired of checking the validity of arguments in code and doing coercion such as Array(maybe_array_or_maybe_not). And the nils, ugh. I never created so many bugs as when I was writing Ruby code (though JavaScript is a close second).
A language with a rich type system (Haskell, Swift and Rust come to mind) can eliminate entire classes of bugs. Not just by letting you validate the types of arguments and return values, but by letting you describe your program logic in terms of types. It's often said that Haskell programs rarely have bugs once they compile, and while there are no guarantees, it's often true.
Give a statically typed language a try for a while, and you will probably change your mind. I don't know about Crystal, but Go is a decent entry-level language. (Many former Ruby devs seem to enjoy Go quite a bit.)
Beautifully put. The ability refactor confidently is so underrated. It's one of the places where a little bit of verbosity (i.e. Java) pays huge dividends.
> Duck typing is elegant, but it only works so far as you know the range of types to expect.
Go shines particularly well here. In Java code bases, interfaces occasionally accumulate too many methods or interfaces of interfaces start to get unwieldy. I like Go's approach of letting the function declare the relevant subinterface it really needs.
Type checking only works when you make a mistake which breaks a type signature. You can call entirely the wrong function with the right type signature. You can call sin instead of cos, or forget to take a log of something. You an swap the arguments to a subtraction: both are floats. Think of all the numeric code in which lots of variables, arguments, array elements and so on are all of the same type. Or string code in which there are numerous strings. Or OOP code where you have two or more objects in the same scope of exactly the same class, which can get mixed up.
The idea that you do not need a comprehensive test suite because you have static types is horribly wrong.
That being said, I don't think dynamic typing is going anywhere, and with experience it's not that difficult to anticipate the problems that come with dynamic typing.
I don't see that as necessary. Either you have good discipline regarding types where you need it or you don't. And discipline in your coding extends to way more than just type errors. So anything encouraging to develop your discipline is a good thing.
I think what it comes down to is, not having dynamic typing available to me when I want it is going to be more painful overall than not having a type system when I want it. I look at all the static languages today and I see so much validation of this idea that it's not even funny.
I think this is maybe the crux of the difference of opinion between static and dynamic afficianados.
I don't want to have to be disciplined. I want to be able to offload as much of the thinking as I possibly can onto my tools. The reason this is necessary is that I'm human, and I only have a human level capacity to not screw things up. If everything is the responsibility of the programmer, then we are limited in our ability to build large complex systems, to the ability of the programmer to manage this complexity. The only way to transcend this human limitation is to put measures in place to prevent things from falling over when humans turn out to be human after all.
I used to make this argument too, until I actually spent some time writing Ruby, and none of my fears came to pass.
For that matter it's not that hard to write code to statically validate that arguments to a given method are checked against a set of types and that this set does not include a representation of invalid values. (E.g. I can "forcibly" wrap any method with checks). The reason the various libraries to do that haven't gained much traction is that they've rarely paid for themselves in reduced effort compared to higher level tests.
I'm all for more static validation, but I just don't think we have suitable tooling yet to do it at a level that provides sufficient benefit.
But if you’re trying to push the envelope somehow on performance, concurrency, safety, number-crunching, or system design, or you need a portable binary, then it makes sense to choose a language that has tools and abstractions better suited for those tasks.
Python is simple by design. It has optional typing (as of 3.6), beautiful async constructs (ala ES6), nice integration with C/assembly (in CPython), comprehensive open-source software ecosystem, and many strong alternative interpreters.
Ruby feels like it's playing catch-up in every area except metaprogramming... and, while I really enjoyed metaprogramming as an experienced engineer, I'm kinda glad Python lacks that complexity.
What on earth could make you people think Ruby is even a contender? Do you ever look at ANY language usage stats?
If there is a toss-up in dynamic languages the toss-up is between Python and JavaScript and with JavaScript's dominance in the front-end and Python's in data science it's likely to be a turf divide rather than a toss-up.
Yes, but it comes with a heavy trade-off if you have an insufficiently expressive type system and/or an excessive need for explicit incantations to the type checker.
Since every call is a method, and a method belongs to an object, the type of this object is significant. Base Ruby language gives you no way to declare that object X shall be of class C.
So, well, there are dynamic languages and there are dynamic languages.
It is a gorgeous language, though, with a very easy to read syntax. I'd love using it if it had something like goroutines, which would look great with its block syntax. Good luck to the team working on it; I hope it's a contender.
Crystal already has a great concurrency model, it’s just not parallel yet.
Even if it were possible to evaluate all current alternatives, we lack knowledge of the future and therefore can't reliably include important factors such as ability to hire into the team.
Not perfectly because "best" is subjective. My advice is to let the problem and goals help you dictate (yes, even on hobby projects and even if one of the goals is trying said language). In fact, if you are a hobbyist evaluating languages, you should try them all out with reasonable projects where you can instead of write a post saying how you are moving from a single one to another single one.
I agree, and think that the culture around a programming language is one of the most important attributes, so we should not be afraid to talk about human factors like cultural fit. Your choice of programming language is usually limited to a short list of the ones that have the tools and libraries to support what you are doing, but IMO it's perfectly reasonable to choose a particular language because you and your team like the culture. If you decide to use a programming language in production, you might have to live with it for a long time.
1: https://www.youtube.com/watch?v=9LfmrkyP81M
I think that's an objectively false statement.
There are many objective metrics by which a programming language may be evaluated. Conciseness, clarity, suitability for realtime applications, and efficiency come to mind.
"It is even possible to "use the best language for the problem"?"
It's certainly possible to use a suitable language for the problem. Some problems are more forgiving than others, of course...
I will say that the idea of a "general purpose" programming language, suitable for most tasks, is a good one. The current multitude of languages, while fun and good for exploring new ideas, is taking a lot of brainpower away from actually producing working systems. Also, I'll claim that there's no reason that most programs shouldn't be written in an efficient language, and in fact there may be a push for that in the name of datacenter efficiency.
It's sad that the most written programming language today is Javascript.
It make senses to half the users of this site. The other half, well, I guess their jobs depend on it not making sense.
I should add that I have no interest in Crystal. It’s just obvious that Go enjoys more success than it technically merits.
Not sure what you mean here, but comparing Go and C negatively (even though quite unrelated) whilst praising C++ makes little sense. Even if you frame it in the way the author did that C++ has classes and C and Go doesn't, Go's lack of classes is no more primitive than any other modern lang w/out classes. And that doesn't even get into arguments on conflating OO and classes. These pro/con discussions always devolve into this mess and can be picked apart, that's why they are rarely worth having at such a high level.
> I should add that I have no interest in Crystal
I have interest in all of them.
> It’s just obvious that Go enjoys more success than it technically merits.
You said more success, the post said Google backing is what "ultimately resulted in its success". Those aren't the same thing. I doubt anyone would disagree that it helps, but I doubt anyone reasonable would agree it is the sole reason why.
It's not like D or Kotlin Native or Swift or others got a fair shake here. These just aren't good posts and I struggle to find any benefit in them.
I doubt Go is only successful because of Google, but a large corporate sponsor seems to make or break most languages.
Dart hardly had any major Google backing, it looked like a way to keep some well known VM researchers busy, which were rescued by the AdWords team before the project kind of folded.
Flutter looks like some of those developers trying to find a killer application for Dart, while being allowed some air time on Google's conferences, while Google management is full speed on Android and Web stacks.
Polymer has never about the framework, rather a way to push WebComponents as sane way to do web development, which up to HTML Templates they have been quite successful regarding adoption across browsers.
Some hypothetical "best language in the world" is irrelevant without the tooling and ecosystem around it. "BLITW" still sucks if might as well write the code in Notepad because the editor/IDE integration sucks. "BLITW" sucks if the community consists of 8 people on github.
I hear of Crystal a couple/3 years ago, and it sounds neat on paper - a statically-typed, fast Ruby. Cool, but it's completely meaningless to me because it doesn't fit into any ecosystem that me or most developers care about.
> "BLITW" still sucks if might as well write the code in Notepad because the editor/IDE integration sucks.
We have better editors than notepad that work with any language, and there's plenty of people getting work done with fairly barebones editor setups making no use of language integration at all.
> "BLITW" sucks if the community consists of 8 people on github.
While adoption and library availability are clearly huge factors, they're not necessarily absolute requirements. There are plenty of good (and surely also many bad) reasons why many real-world codebases are practically isolated from the wider community despite being written in a widely adopted language.
If some language was clearly the best in the world, or even just demonstrably superior in a way that is meaningful to whatever your requirements are, it can be a totally reasonable decision to choose that language for your project even though you won't be able to reach to github for a lot of conveniences, you'll have to write code in stock vim and you'll have to invest some extra time to get new contributors up to speed.
I don't know if Crystal is that language, I'm not even in a great hurry to try it to find out, but I feel like if I waited until a language had reached Go levels of mindshare before taking it seriously I'd probably be missing out.
I was ultimately looking for a versatile language that I could use for my personal projects outside of work and thus I was indeed trying to find a single language that could do everything I wanted. Up until this point, that language has been Python.
Go is clearly sufficient for many very successful and amazing projects (many of which I use daily, like Hugo, Terraform, Docker .etc), so developers can still produce excellent tools with its limitations. But in saying that, the language is not for me, and that's okay; if it works for someone else, then that's okay too. Go does lack various features that many developers want, including me.
Fun fact, the blog post was generated by Hugo ... which is written in Go :)
With regards to Nim, yes, my experience with Nim is limited and I am still hoping to learn it further and do a more thorough evaluation. Hopefully I'll spend a good amount of time with Nim in the future to give it more of a fair go.
I really found "still" to be funny because I think for many Go devs (including me) the simplicity and lack of features especially enables us to create more easily.
It's the opposite of standing in front of giant fridge shelves in the supermarket with 100+ kinds of yoghurt where you have a hard time deciding. You only have a few choices so you just go ahead and pick one/just do it.
Forgive my bad analogy.
But when it came to Go, I personally found myself battling the language as a result, rather than being more productive with it.
Ultimately if it makes you more productive, then that's awesome and that's all that matters.
So naturally I used many programming languages with Go's limited set of features, which doesn't mean I want to return to those days.
I started programming a few years later than you.. first on Atari ST (Basic) then later in DOS (Pascal). I often wish myself back to these systems when I see today's bloated stacks of crap (obviously this does not apply to everything).
I don't think this is relevant for the original discussion though..
Even the last version of Turbo Pascal for MS-DOS (7.0) was more feature rich, ignoring the lack of GC for a moment.
Ah, and Turbo Pascal 5.5 was compiling around 34 000 lines/minute in computers whose CPUs were maxed at about 30 MHZ, http://edn.embarcadero.com/article/20803
Regarding nil safety, did Pascal allow something along the line of the following?
They can be used as indexes, range validation, access control in variant records to simulate sum types.
Enumerations are so useless that majority of modern languages have direct support for them.
Yes, it did allow your contrived example, which seldom occurred in practice because proficient Pascal programmers only used pointers when other type safe alternatives weren't possible.
Yeah man, it must be so fun doing large-scale construction work with just a hammer and a shovel; so easy to use, so easy to learn. Who needs caterpillars, pneumatic drills and such.
Last time I checked, Brainfuck is easier to learn than Go (more simplicity!!!, and runs in even more platforms.
Just like if you're building a small tool to wrap another you might just choose to use bash over Java, it all comes down to what you need most commonly vs what would "be nice to have".
>build large barns entirely
Not the same 'large-scale' construction work I had in mind.
I don't agree that Go has only "a hammer and a shovel". It has at least a saw in its toolbox too.
On a more serious note.. fun is highly subjective and the brainfuck / simplicity argument is just useless.
It makes perfect sense. In fact that's what the Go developers themselves found out -- that C++ programmers, who they thought they would be attracted to Go, passed it over, and instead Go gained dynamic language converts.
Considering that Go doesn't even do well (and has horrible library support) for most of the stuff C++ is used for (GUI apps, 3D, AAA games, systems programming, high performance scientific calculations, etc), probably yes.
Now, if you did network servers with C++, probably Go is a better/easier/smaller surface fit.
> I plan to only use this language in my personal projects
I think this is more a blog post about what language the author finds most interesting and exciting, not the language the author is suggesting people use for work.
I also tried to highlight its weaknesses in the Caveats section. The language is young and often has breaking changes which would not be suitable for production at this time, particularly in larger organisations.
However, I think the language shows great promise and will appeal to a lot of people as it matures. I'm certainly enjoying it so far! :)
It was just an informal brain dump for me and nothing too serious, so please don't take anything to heart. And indeed, I have only spent a limited amount of time with the other languages on my list. I still intend to keep a close eye on them all as time goes on.
I'll try to respond to various comments :)
Update: Hacker News is rate limiting me, sorry folks. I'll try again to post some replies in a little while.
It is tough to read criticism but it's always a good opportunity to learn. The comment about mypy for example was correct and I'm pretty sure I'll be trying it out on my next Python project. I've updated the blog post with minor amendments and corrections based on the feedback here.
Indeed this was my first time on HN (which took me by surprise) :)
e.g. These three expressions have three different values:
3, 7 and 10 respectively. Because newline is equivalent to semicolon and Ruby allows void expressions.I just tested Crystal and it does the same.
In terms of "void", Ruby has no such thing - every expression has a value, though that value can be nil (and somewhat confusingly "( )" is an expression that evaluates to nil).
So your first example is two expressions, and evaluates to 7 when the whole thing is evaluated, not 3 - if you evaluate it in irb etc. you might see 3 because the first expressions is itself complete, and so will cause output.
Your second example is a list of the expressions "1 + 2" and "3+4", which evaluates to 7, because as for the first example, the last expression evaluated is what will be returned outside of a read-eval loop like in irb.
The last example is a single expression because "1 + 2 +" is a syntax error on its own.
I can understand you find it quirky, but you generally only need to consider that if you want to break up an expression you need to ensure it does not stand on its own.
Re "void" I'm referring to rubocop warnings like "Operator + used in void context."
Here's another oddity; irb behaves differently for some expressions.
:-/Anyway, the parens things bothers me the most. In most (all?) other languages, putting parens around a multiline expression would make it one atomic expression.
Putting parens around it does make it one atomic expression though, it's just that in effect the "operators" are ;/lf, and these "pseudo-operators" return the value of the last sub-expression, and binds tighter than parens,
I can't actually remember seeing any one relying on grouping expressions with (), though, which is probably just as well.
(I'm sure someone will now come up with an "essential" use of it)
Crystal is going to be an insane language in a year's time.
You get the JVM ecosystem with a modern syntax. It's a higher investment then Nim/Crystal but also has higher payoff due to existing libraries and peak performance of the JVM.
However I do want to note that Kotlin having great IDEA integration is not lock-in. You can (and I sometimes do) code Kotlin + gradle with a pretty vanilla vim setup.
Clojure has one big advantage and it's also it's biggest weakness. It's a Lisp. I love Lisp's but I would never want to use one in a professional setting.
Am I reading this correct? it took CPython 128 seconds for a simple Fibonacci test? Can anybody explain to me why this is so slow?
Package management (from [0]): "Crystal libraries are packed as Shards, and distributed via Git without needing a centralised repository. Built in commands allow dependencies to be easily specified through a YAML file and fetched from their respective repositories."
Concurrency (from [0]): "Crystal uses green threads, called fibers, to achieve concurrency. Fibers communicate with each other using channels, as in Go or Clojure, without having to turn to shared memory or locks."
[0] https://crystal-lang.org/
Will this join the ranks of Julia, Rust, Go and the others?
I'm skeptical because the last few years I've seen these trends come and go on HN. They do nothing but scatter my focus. I've learned to ignore them now though.
1. Amount of things I've to learn to completely utilized 100% features of the language.
2. Availability of well supported packages for stuff like elastic search, stripe, postgres etc...
3. Ease of making a function asynchronous. I love how go routines make it trivial and hated pythons way.
4. IDE and debugger: I am using goland now, and it is magical.
GO has provided me everything, finally i can focus on building my product.