Moving from Ruby to Rust
deliveroo.engineering
deliveroo.engineering
Unfortunately, Python always wins, and it's also never not an option, since it runs on everything I care to develop on :(
if you can't do this quickly and easily, consider your career kaput when you hit 40
Over the years, I've done commercial work in M68 asm, Awk, shell script, Pascal, C, C++, PHP, Javascript, WordBasic, Java, Ruby, and I've used about a dozen other languages on a hobby basis or out of a wish to learn.
But at the same time, I don't randomly switch languages for no good reason. I see the attitude of thinking it is easier to switch as a large part of the problem. Yes, there are cases where a switch is worthwhile. But all to often I see people describing how and why they switch in ways that makes it very clear that they didn't grasp the architectural reasons for why their original solution was broken.
The poster-child for that being Twitter, where they went from a Rails-setup that just violated pretty much every basic principle of proper architecture for scaling a messaging platform (I've written quite a bit about this, but the short of it is that their problem had been solved for decades: federate behind the scenes), and blamed it on Ruby and Rails.
It's perfectly possible they benefited from their language changes, but the main thing their language change gave them was that it forced them to re-design their system from scratch. And that is a common story. It may well be that blaming a certain platform is sometimes necessary to provide "political cover" to justify a large rewrite, but to me, large scale language changes often suggest covering up design flaws.
To bring things back to the article:
In this case it's certainly possible Rust is a good choice for them, especially as they had past experience with it and used it in some parts of the system already, but here, to me, this sentence already implies a design problem (lack of concurrency):
> The computations themselves are quick, but the problem is that we need to do a lot of them: for each order, we need to go over all available riders to determine which assignment would be the best.
Personally, my first step would have been to run the calculations in parallel. Maybe they'd still also want to switch it to Rust, but unless they stop adding riders, they've just deferred the real problem unless they took the opportunity of the switch to Rust to also parallelise the calculations.
Another issue here implies another area where a substantial portion of their time is a result of their design rather than language choice:
> This means 0.6 second is a Ruby/DB overhead of loading data and sending assignments to riders.
Why is there DB load here? There is simply no way that they are dealing with so many riders and locations in any given region that they can not hold an up-to-date view in-memory in the dispatcher (yes, they'll need to record it as well). A lot of developers these days are scared of loading things into memory, but you can often scale systems to 10x or 100x capacity by being willing to maintain in-memory state. Often you'll even end up with simpler systems.
This is not to suggest they're wrong to pick Rust or wrong to choose to switch, because that also depends on what they're experienced with and what works for them, but it's to point out that being quick to go for switching languages is often a result of different viewpoints rather than need. And sometimes lack of experience.
A programming language that compiles down into target programming languages.
Reminds me of Haxe.
Scala, Kotlin, and Java can all interop with each other, but at the end of the day much of the libraries get rewritten between the languages.
I would love to see that expand to have an LLVM/C target; the GC complicates that but it could be done.
I'm not sure if a solution to this exists yet. It seems like it's up to the dependency to adopt mypy as well?
There is monkeytype which can infer the types from test runs and insert them into source, so its quite easy to add annotations.
I’ve tooled around in rust a bit. I like it much more than go, but all-the-ops-things are go, so I feel that’s where I need to put my play time.
About 3 months ago I started setting aside an hour every morning before work specifically to only work in go.
It was the only way I could learn it because on the job I would just lean on the languages I knew I could develop fast in.
Even an example of an echo server doesn't look that appealing: https://dev.realworldocaml.org/concurrent-programming.html#i... But, perhaps that is just unfamiliarity on my part. Rust was heavily influenced by some of OCaml's choices, but they chose to make the syntax more familiar and approachable to people coming from the mainstream programming world, although it does have its own quirks.
With Go and Rust as options, I'm not sure why someone would pick OCaml in 2019. In 2014, when that article was written, Go and Rust were both much less mature. I hear ReasonML/OCaml could be interesting for frontend work, but frontend is not my specialty.
Honestly, as easy as it is to hate on the npm ecosystem, Node.js can run circles around Python in performance, and TypeScript offers a pretty nice type system. If someone just wants a "better Python" for web-related stuff, TypeScript on the backend might be a good option, although I personally lean towards Rust and Go, depending on the project.
You definitely would if you already have millions of LoC in OCaml.. like Jane Street does.
For a random person, I would agree. I tried it myself for a few personal projects (I know Rust/Python/C++/Haskell reasonably well) and couldn't get myself to like it, subjectively.
Re: database drivers–which one are you looking for? MSSQL ( https://discuss.ocaml.org/t/ann-first-release-of-mssql/3242 )? Or Postgres ( http://mmottl.github.io/postgresql-ocaml/ )? Or SQLite ( https://github.com/mmottl/sqlite3-ocaml )?
Re: web frameworks–Eliom ( https://ocsigen.org/eliom/6.6/manual/intro ) is one of the most powerful isomorphic web frameworks. Or do you want to spin up a quick JSON API server with Cohttp ( https://github.com/mirage/ocaml-cohttp )? Or dig into a high-performance, lower-level server ( https://github.com/inhabitedtype/httpaf )?
Or you want a Kafka client ( https://opam.ocaml.org/packages/kafka/ )?
Or maybe you can just take advantage of BuckleScript's high-fidelity approach to transpiling OCaml to JavaScript, and write some bindings to take advantage of basically everything in the npm ecosystem?
Sure, not every OCaml library is battle-tested, but I think that's not a good reason to immediately discount it. I didn't tell StavrosK to immediately commit to and rewrite everything in OCaml, I said he might find it interesting. Even with Go, Rust, and TypeScript as options, because:
- Not everyone is satisfied with Go's type system or its model of error handling, or its low ceiling for abstraction.
- Not everyone is satisfied with Rust's overall newness and potential compiler and library bugs, its lack of GC and the subsequent having to deal with borrow checking, or its slow compile times.
- Not everyone is satisfied with trying to model the dynamic complexity of JavaScript in a new, explicitly unsound type system. And it's no secret that the BuckleScript compiler can run rings around tsc for compile speed (not even mentioning the more powerful and battle-tested OCaml language).
These are only a few things, and only discussing IO bound tasks. Once you start doing CPU intensive stuff, the problems are just made worse, especially if you want to spin off background jobs to work on things after finishing a request.
I know that a library of some kind has been written for each thing that I mentioned, but that doesn't make them ergonomic or reliable. The last time that I researched this, everyone discussing their experiences trying to use Postgres from OCaml had nothing good to say.
The TechEmpower benchmarks don't even include a single entry with OCaml, simply because no one has submitted one, which speaks volumes about the size and maturity of the state of writing a web server in OCaml.
For business critical functions like your database driver and your web server libraries, being battle tested is very important.
The Rust compiler is plenty mature, it's built on LLVM, and has had years of real world use by a growing number of companies. The Rust community places more emphasis on stability than any other I've been part of.
But, the async story and web server stories are not currently mature, which is why I'm happy to use Go for those things. Actix is as close to mature as those things get in Rust right now, and it's not up to my standards yet.
For someone to be so upset with all three of those languages on those counts that they decide to shoulder the burdens OCaml brings... that would be surprising. I had already pointed out that OCaml on the web has become a niche thanks to ReasonML (where BuckleScript is the compiler), especially since the web is predominantly single core.
"Explicitly unsound" is pretty funny to me. TypeScript has a really strong type system. To say otherwise as a negative thing at this point is to be purely pedantic in the most academic of ways, in my opinion.
Discounting every OCaml library as not being 'ergonomic or reliable', really smacks of goalpost-moving. Every OCaml library needs to be immaculately designed and battle-tested? It's not even worth looking at otherwise? This is a weirdly high bar. No one even thinks like this about TypeScript, which by the way has library typings that are full of next-to-useless `any` and `function` types.
Agreed, the TechEmpower benchmarks don't include an OCaml entry, but (a) they're only relevant if you care about writing HTTP servers in OCaml; (b) they're only relevant if you care about benchmarks for HTTP servers in OCaml; and (c) the lack of a benchmark in itself doesn't prove anything about writing HTTP servers in OCaml.
The Rust compiler is an amazing effort, but it would be a mistake to equate its maturity level to the OCaml compiler, which has been an ongoing effort for more than two decades now. Frankly I find it strange that someone who immediately attack and dismiss OCaml when it's even suggested as worth checking out–and then accuse someone of being 'upset' with their suggested languages for writing a response.
"actual runtime errors" can and do happen even in Haskell and Ada. Unit and integration tests are important, no matter the language. TypeScript's type system is a huge step up from Python's, and it's better than Go's in many ways. TypeScript's biggest weakness for me is probably that it runs on Node.js, which is single-core.
As I have previously expressed, the major benefit to TypeScript is that it performs much better than Python while offering a strong type system and a strong ecosystem. The main things OCaml seems to offer are a stronger type system and better performance, when compared to Python. OCaml's type system might be marginally better than TypeScript's, but the Pareto principle might suggest that the extra 20% isn't worth the 80% more effort it will require to make up for OCaml's ecosystem. As I've also pointed out that I strongly prefer multi-core systems, you'll notice that I stated up front that I lean towards Rust and Go, not TypeScript. I just think TypeScript is a great fit for the OP, who seems to have been looking for a faster, safer Python (since they're so interested in Rust) with a drop in library for every task (so they can have it done in an hour). The most you have disagreed there is by saying that TypeScript's type system is slightly unsound. Okay. So, you can choose libraries which have really sound types so you can't easily misuse the library, but likely the libraries contain incorrect behaviors. Alternatively, you can choose libraries that are battle-tested by tons of major companies, but their types might not prevent you from every last possible misuse of the library. Either way, you need to write tests for your code to make sure the results are correct. In fact, you might need to write a lot of otherwise common libraries because OCaml is so niche. I don't see how OCaml wins there for the OP's use case, but I'm sure someone finds that trade off preferable.
> Discounting every OCaml library as not being 'ergonomic or reliable', really smacks of goalpost-moving
It's really not, because I made it clear up-front that I was asking about good and/or battle-tested libraries, not just a list of first hits on google. But it is easy to fall back on the defensive by making it sound like I was shifting things around. I literally asked "how good" are the web frameworks, "how many good" database drivers are there, questions which elicit discussion, not just links. Not "are there web frameworks" and "are there database drivers". I tried to be very clear about this up front.
> No one even thinks like this about TypeScript, which by the way has library typings that are full of next-to-useless `any` and `function` types.
I don't agree with your assessment here, since that really just seems like a strawman argument. `any` is a useful tool when used correctly; how else would you build a custom container like a Vec or a HashMap? It would be annoying to have a container that should be fully generic that can only hold some restricted set of types because the type system isn't powerful enough to allow it. However, it would be truly pointless for someone to build a nice TypeScript library using mainly functions that receive and return `any`, so it doesn't follow logically that experienced people would do that. Why wouldn't they just use JavaScript? This idea doesn't pass the smell test. Do you have any evidence for it? In point of fact, people write TypeScript definitions even for JavaScript libraries! This allows people to provide a nice interface into the JS code, so they don't have to see `any` everywhere they look. Why would they care more about the types in JS libraries, which are only approximate, if they're leaving all of their own code without type checking? TypeScript definitions for JS are only approximate, of course, but that's the real world. They're still helpful, just like documentation for a REST endpoint. When you make a REST call to an API, you aren't guaranteed that everything will work as documented, it might reject valid inputs, it might accept erroneous inputs, it might return values of the wrong types... TypeScript definitions for plain JavaScript libraries give you an opportunity to create a wall around your TypeScript code where the unsafety is easier to contain, but there will always be some level of unsafety in the real world. Eliminating 80% of it is a great start. The last 20% is not as easy as the first 20%, and the cost should be weighed against the benefit.
> and then accuse someone of being 'upset' with their suggested languages
I don't think you understood what I had written. I was saying that it's very unlikely that someone would look at all three of Go, Rust, and TypeScript and decide that the specific problems you mentioned are such dealbreakers that they would choose OCaml. I wasn't talking about you or me being upset, I was talking about any third party analyzing the trade-offs, but you seem to have taken it as some kind of attack against you? It definitely wasn't.
I don't hate OCaml. I have followed it for years, hoping it will progress in ways that I find important. Even years ago, multicore was right around the corner: https://news.ycombinator.com/item?id=9582980 but it's still not here, and it's still not in the foreseeable future.
> The Rust compiler is an amazing effort, but it would be a mistake to equate its maturity level to the OCaml compiler
Does it matter that OCaml's compiler has been under development for "more than two decades" if the amount of development is less than has happened on the Rust compiler in half the time? Rust, Go, and TypeScript have had staggering amounts of money and developer-hours dumped into both their compilers and ecosystems over the past few years, while OCaml's have barely moved at all, as far as I've been able to tell.
You can look at the numbers for the compilers:
https://github.com/rust-lang/rust/graphs/contributors?from=2...
https://github.com/ocaml/ocaml/graphs/contributors?from=1995...
The uptick on OCaml seems to correspond to Facebook becoming interested, but on every metric (including total number of contributors, total number of commits, total additions, whatever), the Rust compiler has had a lot more developer-hours of attention than the OCaml compiler, which could be argued makes it more mature than the OCaml compiler... and this is just the Rust compiler frontend itself, which doesn't include the unbelievable amount of time and money that has been sunk into LLVM by Apple and others, which directly benefits Rust.
Let's just say that I don't agree with your conclusion about their relative maturity.
Let me reiterate: I do not hate OCaml. If anything, I'm annoyed with its stagnancy. It has so much potential, and I wish that potential would be realized. ReasonML is the best thing to happen to OCaml in the past 10 years, but that project has been so tightly focused on its objectives that it hasn't bolstered much of the surrounding ecosystem that would be desired for server-side initiatives.
I don't see how this comment thread can become productive, so I'm probably going to bow out now.
- a simple HTTP proxy that saves requests matching some criteria to inspect and debug them later;
- implementing Stripe webhooks for invoicing;
- a simple HTTP handler that forwards client-side JavaScript errors to syslog;
- just-in-time generation and HTTP streaming of backups as .zip files (our customers must be able to get back their data);
- a gateway between MySQL/PostgreSQL and client-side JS charting library to produce reports;
- etc.
As you can see, it's quite standard, and all over the place :-)
It's all just trade-offs.
No one ever implemented a serious compiler/OS/3D game in Ruby.
e.g. with Python you can find libraries (and decent tutorials/examples) for: a small or big web framework, computer-vision, data-science / reproducible science, machine-learning, natural language processing, web-scraping or website testing.
(Source: using Python/C++ at work, contributed a lot to pybind11)
Getting a group of devs to commit to >6mo learning Rust could kickstart a real change. There needs to be critical mass.
You can email me if you want to explore Rust for your work or interests. I have a Python background, too, and have open sourced work.
Because at the beginning you want to optimize for developer productivity and then when (if!) you get to a certain size, you can easily move to a solution that emphasizes machine productivity (aka performance).
When you get to maintenance mode this effect becomes even more pronounced. Because it's much easier to not break something in a nicely typed codebase.
There's some languages that kind of bridge this gap between having a lot of compile time safety and still being easy to write. I'm thinking of F#, OCaml that have a lot of the same type safety, and barely need more type annotations than Python. They're not as fast as Rust, but also they don't necessitate thinking on the extra layer of ownership (which can cost you time).
People always think of the hours it takes to develop some feature and forget the days it takes to debug it.
Devs need to stop thinking of it in such binary terms. You can get things out fast without pushing out crap. You can write organized code, built so it can be optimized if it ever needs to be, without it taking too much overhead. You don't need to swing the pendulum all the way to one side or the other.
I'm traveling in Uruguay. I get:
Error 1009 Ray ID: 4a945b112e23c577 • 2019-02-15 02:31:00 UTC Access denied What happened? The owner of this website (deliveroo.engineering) has banned the country or region your IP address is in (UY) from accessing this website.
https://github.com/julialang/julia/issues/558#issuecomment-4...
Then I realized that 90% of my mental gymnastics with indices got simplified. Explaining indexing to newbies is now immediate where before it took a slide, several examples, and a clever picture. Slicing is also more natural:
"1:3 picks out index 1, 2 and 3, which are the first, second and third element of the array."
Instead of the python version of
"0:4 picks out index 0, 1 and 2, which are the first, second and third element of the array."
I don't think that's right? It should pick out four things, not three.
Of course, you could argue that getting that wrong proves your point! I personally still prefer 0-indexing, but I definitely agree with you that having an exclusive upper bound is confusing.
0:3 picks out index 0, 1, 2.
So 1:3 picks out the second and third element, which are indexed by 1 and 2 respectively.
My guess is that what one prefers probably depends entirely on the data structures one works with most....
In general, much of what's chosen for language design is influenced to some degree by convention. This is a valid design choice, because you're maximizing use of existing domain knowledge of your audience.
In this specific case, I would argue that since in many languages where an array isn't a small shim over memory management (Ruby, Python, Perl, JS, etc) where easing user friendliness is at a premium over performance, 1 based array indexing would make better sense... if most people adopting those languages weren't already fairly well acquainted with 0 based indexing from CS programs or exposure to other languages (and it wasn't a simple concept to understand). Since many new users are familiar with it, and it is easy to understand, it's simple to just go with what some percentage of people already know, so convention wins out.
http://wiki.c2.com/?WhyNumberingShouldStartAtZero
What I find most persuasive is that 0 based indexing brings measurement into accord with enumeration.
Being able to easily port code between languages (and math articles) is important, when there's no clear winner, I like consistency.
In mathematics 1...N is a perfectly good notation. Julia expresses the same idea with 1:N. This is consistent with spoken language (1 denotes the 1st element). Consistency, if anything, would not come down in favor of the software engineering choice here.
0-based indexing won in programming because it is simply more to purpose in programming. We rarely operate on ranges, but we operate on offsets all the time.
And 0-based wasn't solely "C won so 0 won". We had 1-based languages for a LONG time, and, if they were sufficiently superior, they should have displaced C. They did not.
In addition, in proper programming languages you don't count--you iterate, fold, accumulate, etc.--and avoid the index altogether because it is error-prone.
1-based indexing causes all kinds of havoc in circular ranges. In particular when you try to access things in a circular manner (very common in programming--uncommon in mathematics), it causes grief.
// 1 based
new_index = index % N + 1
new_index = (index - 1) % N // Careful: the parentheses are REQUIRED
new_index = (new_index == 0 ? N : new_index)
// 0 based
new_index = (index + 1) % N
new_index = (index - 1) % N
Range discussion from Dijkstra in 1982: https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/E...
I still prefer 0 based indexing (for example for calculating the size of an array), but the worst thing is inconsistency between languages. 0 won, that's it.
Python:
>>> -1 % 20
19
C: printf("%d\n", (-1 % 20));
-1
Even worse, it still fails even on unsigned: printf("%d\n", ((unsigned int)0 - (unsigned int)1) % 20);
15
So you still need to add N: printf("%d\n", ((unsigned int)0 - (unsigned int)1 + 20) % 20);
19
Thanks for the reminder of humility.(Side Note: For those reading this, the C operator isn't "broken", per se. There are three properties that modulo can adhere to but two of the three are mutually exclusive.)
I would disagree with that assertion. Maybe it was true historically, but just look at how often ranges are used today - the fact that many languages have an abstraction for them in the core library is a testament to that.
I would also argue that having ranges (and underlying iterators) as opaque abstractions is preferable to conflating them with indices. Then you can have your cake and eat it too - the elements are counted naturally, but if you have an iterator to the first element, you can deal with 0-based offsets just as naturally.
The Dijkstra discussion is only aesthetic preference, nothing more.
Edit:
In Julia the examples would also idiomatically be written in terms of the provided mod1 function:
new_index = mod1(old_index + 1, N)
new_index = mod1(old_index - 1, N)Possibly, but then 1-based indexing certainly isn't enough of a positive to overcome the other stuff. And that's evidence, too.
> The Dijkstra discussion is only aesthetic preference, nothing more.
Dijkstra's comment says that people using the other 3 conventions were committing more errors--that's data.
> In Julia the examples would also idiomatically be written in terms of the provided mod1 function:
Agreed. The proper way is to encapsulate that behind a function so you don't have to think about it.
However, if you have to unpack that and repack it all the time (for example, Lua calling C), then you can't just encapsulate and forget about it.
Edit: I think I screwed up that analogy.
It might be easier. How would you run your function on the GPU in rust?
I guess I'm looking at it from a DevOps standpoint but those types of questions can (should!) inform the decisions you make about your code. Mixing in multiple languages (most likely) increases the footprint of your infrastructure and shouldn't be ignored. This is the same whether you use Rust, or NodeJS, or Python.
This distinction is important.
It has a lot of similarity, but it's not the same.
There is simply no way of knowing enough to optimize when compiling a python script comparing to rust for example.
Language depth has a cost though in terms of raw productivity, that is why there are languages like matlab that are there simply for prototyping and nobody in their right mind would use it for production purposes
JIT with type specialization can do exactly that. It's all about whether the runtime cost is worth it.
This is one of the classic papers on type specialization in JIT: http://www.cs.williams.edu/~freund/cs434/gal-trace.pdf
* Strings cannot be single-quoted in Crystal. Single quotes are used for character literals, like C.
* The two languages differ substantially in how keyword arguments are specified. In Crystal, any argument can be specified by name as well as position.
* In Crystal a 'rocket-style' dict literal (i.e. `{ "foo" => "bar" }`) is a different type (Hash) from a 'keyword-style' dict literal (`{ foo: "bar" }`, a NamedTuple).
* Hashes are typed (inferred at the time of creation). You can't use keys and values of different types than what was in the hash when you created it. You _always_ have to specify a type for empty hashes, which means that any Ruby code that does `x = {}` and then stuffs things into `x` has to be rewritten.
* NamedTuples raise an error if you try to read or write a nonexistent key. Hashes raise an error if you try to read a nonexistent key.
* Crystal does not have singleton classes (`class << self`). The Module class doesn't exist. You can't execute code in class definitions (like constant initializations). Generally speaking, a lot of the very dynamic Smalltalk-y features Ruby devs take for granted are not present.
* `private`/`protected`/`public` are keywords, not methods, and they must be applied to each method individually (`private def...`).
There's a lot else. Now, a lot of these changes are good and fix issues that Ruby can't because of the need for backwards compatibility. This isn't a criticism of the language. The fact remains that Crystal's superficial similarity to Ruby hides a lot of substantial differences (a problem Elixir suffered from for a while as well). Translating simple code by hand is not difficult, but rewriting a larger project would be a huge undertaking.
Depends on what method you use to read it. If you use [], what you describe is true, but if you use the nilable variant, []?, it is not. But yes, having to handle and think of nilability is certainly a big change that will affect a lot of code.
Crystal, in fact, has a runtime, that runtime has a GC, and the language FAQ notes that removing the GC would be impossible without complete redesign of the language.
Given that, I wish we saw more of these sorts of stories. I have my own tales along similar lines for multiple tools in my own company. In my case Ruby/Python/Bash vs Go/Rust. This keeps coming up so I question your thesis here that these things aren’t comparables.
There are many paths to do this - each with trade offs.
EDIT: as some people explained below, this is certainly another trade-off. My experience is based on a case where the team was made of non-talented engineers and many of them stick to the same language in their whole career path.
Besides it's crippled as a language due to never allowing anything to be null, so there isn't any powerful metaprogramming you can do with it. That is a big turn off for me. Otherwise Crystal would be such a nice sweet spot IMO .
The problem with Crystal is more with the small community than the concept itself which is pretty good IMO.
I'm definitely a fan of Crystal of though as a project and would really like to see a bigger community and more libraries etc.
The real reason they don't do it is because they can't. It's inherently unsafe. In order to always be sure something is never null you have to be aware of what all it's inputs are so you can reason about it. That's not possible with runtime metaprogramming techniques.
I dunno I guess I just think it's an odd choice. Don't get me wrong, it's a neat experiment and I value it. I'm just slightly miffed that that particular experiment had to mixed in with what amounts to a statically typed language with the beauty and simplicity of Ruby but the friendliness and discoverability of static typing.
Better Windows support could make wonders.
To get the level of safety they have gone for they have to disallow anything that could potentially blow up.
Sometimes I think these they secretly wanted to play around with Rust so they they make an excuse for it.
or javascript, that is procedural first rather than asynchronous?
it really bugs me that there isn't one quite like it, i'm just dying for something like that.
What’s your issue with symbols in particular? They seem pretty harmless to me.
I know it was in place early on for memory / performance reasons but as of Ruby 2.2, there are zero-performance gains using symbols over strings. Unfortunately it's too late to deprecate them since it's a widely adopted practice.
When I teach Ruby, I try to evangelize how simple Ruby is but always hits the breaks whenever I have to explain Symbols.
And ultimately, no matter how much I try to ignore, I just can't stand how this looks:
opts = { adapter: :mysql}
It looks like a double wall of some sort which is fine for those who are used to it but not for those beginning. (Especially those coming from other languages like Python, PHP, and JS)
Symbols also cause occasional havoc when using 3rd-party libraries because they all have different preference of when to use it and when not to.
So IMO, there are no benefit of Symbols and it just creates confusion more than anything. And that is really the point I am making. I have a hard time reasoning with those PHP/Python folks why Symbol exists and it shouldn't really be that way.
> as of Ruby 2.2, there are zero-performance gains using symbols over strings
This is verifiably false. Run this on a newer Ruby and you will see symbols are faster:
``` require 'benchmark'
hashes = [] 1_000_000.times { hashes << { some_key_name: 1, 'some_key_name' => 2 }} Benchmark.bmbm do |x| x.report { hashes.map{|h| h[:some_key_name]} } x.report { hashes.map{|h| h['some_key_name']} } end ```
But that isn't the reason symbols are useful. They signify intent as a constrained set of alternatives. Strings can take on any value, symbols should be limited to a set of things you know. Strings can be modified in-place, symbols are immutable.
`opts = { :adapter => :mysql }` is perfectly valid for scenarios where you are using symbol values. But the shorthand syntax for symbol keys was added later, and I agree is a bit ugly.
If you are generating symbols from input or from strings then they lose some value.
It is easy to explain the existence of symbols in Ruby especially if you are giving proper merit to the Smalltalk lineage. Erlang also has symbols for a lot of the same reasons and most would agree they are very useful there.
As others have pointed out - this is demonstrably false.
# frozen_string_literal: true
a = ('fo' + 'o').to_sym
:foo == a
b = ('fo' + 'o').freeze
'foo' == b
The second comparison is a 1.5x slower than the former. This is because if a string comparison fails on identity, it then has to check characters. Symbols are always interned so can always stop as the identity comparison.But I actually just like them as they convey intent - a symbol is a string I know about as the programmer. A string is a string that is runtime data.
e.g. you would typically do { id: 1, name: "aboutruby" } where id and name are symbols, instead of { "id" => 1, "name" => "aboutruby" } with strings.
But really I don't see the point of removing the symbols.
You would need to get used to doing some things manually which are automatic in Ruby.
Now: Rust is trendy, deliveroo picks Rust.
huh
If the gains presented in the article are alluring, this is only the tip of the iceberg.
Question is How a programming language becomes a bottleneck ? Also my understanding ( correct me if i am wrong here) Rust is more of a systems programming with low level access. Just trying to be curious with performance issues pointed out to a programming language ?
This might not be the reason for the author, but for me I understood Ruby limitation with ruby global interpreter lock. For smaller applications I knew this wouldnt be an issue, but when my applications began slowing down I would check the processes and understand that my Rails application are operating only on one single thread. Then I access if I should keep try optimizing or if something like Elixir is a better solution. Same process with JS
I am not saying they made the wrong choice; it seems like what they chose worked for their use case. It could have been the case that 2.6 didn't work for their needs, but I think it's still worth an investigation.
Also, lots of Ruby developers are coming to Clojure world.
Don't be an asshole, don't geofence people for no real clear reason
I'm also curious about the type of your initiatives, are they really local? Programming stuff isn't limited to the US[1].
[1] https://insights.stackoverflow.com/survey/2018/#methodology (only 25% of the stack overflow 2018 survey responses were from North America in general)