I didn't know Perl had implemented this trick too.
The paper[1] cited in the Ruby bug ticket was published very recently. When I first read the Ruby bug ticket, I immediately wondered how they sidestepped the memory use problem. The paper's abstract seems to suggest there is some technique for doing so, as it rebuffs the idea of doing "full" memoization. Alas, I do not have access the paper. (Which is fucking ridiculous.)
OK, now that I have access to the paper, it does very briefly acknowledge RE2:
> while caching is used to accelerate backtracking in Perl and a rare path in RE2.
Although I wouldn't call it rare. It's probably used every time one wants capturing groups and the regex isn't one pass (pretty common) and the input isn't too big (like, say, a line in a log file).
The actual part of the paper that contains the key contribution (memoization but with less space) is fairly dense and I don't have the time right now to look more closely. But it looks like it might be applicable to RE2, Go's regexp package and Rust's regex crate. All three already use already use bounded backtracking (i.e., "full caching"), but if the space usage could be cut back, then it would increase the opportunity of using the bounded backtracker. Namely, all three put a bound on `size(regex) * size(haystack)`. If the search needs something bigger than that bound, then the backtracker isn't used. But if memory usage were instead much less than `size(regex) * size(haystack)`, then the backtracker could be used more often. (Which is a good thing since it's generally faster than a full Thompson NFA simulation.)
A disaster so far. We tried using Sorbet for a component and we hit ab edgecase where we had to completely remove it. There is a lot of undocumented stuff, conflict between the right tooling and specifically for Sorbet, the lack of structural typing for a language like Ruby (you know, duck typing), makes it very unsuitable, nowhere near Typescript.
When we tested, there was barely an experimental type checker for RBS, that was 1 year ago.
Overall, we tried, had to bail out and stick to YARD. Horrible experience.
Perhaps the official release info is of more interest. This blog post is quite 'inspired' by it. It does mention the source but I do not see the added value of the blog post over the official release info:
While the original Wasm PR description is a useful historical snapshot of the cross-build instructions, the copy in the official documentation is being updated over time: https://github.com/ruby/ruby/blob/master/wasm/README.md
Ruby is my favorite language, and often it is a joy to use because of its combined attributes of brevity, expressive power, and feature consistency.
It's disappointing that there are so many more jobs for another popular language - one that lacks the elegance and consistency but which has a larger ecosystem.
As far as I know, the only well known reason for a company to choose Ruby is if they want Rails (and obviously if the founding team already knows/likes Ruby). But that other language also has a popular (and comparatively clumsy) web framework plus well known modules for all the fantasy capabilities that startups dream of... you know, the AI/ML "not sure how we will use it but we know it will be great, and it's good for marketing".
Sadly, I don't expect this situation to reverse in the future. Maybe like blockchain, once the AI/ML fantasy hype dies down the other comparatively-unpleasant language will lose general appeal and Ruby will gain more attention.
Edit - also, the domain squatters "rubylang.org" should lose their domain. There is no legitimate excuse for having this domain which redirects to a general garbage site.
upvoted for perfectly concise description of that language.
it is even more sad knowing that high quality alternatives for the most popular libraries exist, but inertia is simply too high.
@work I've tried to introduce Ruby to my colleagues that are very bad at programming, but good at science. They ditched it with reasons like "I don't like it" or "it's too slow" without even measuring (it is not! Shopify would have died by now). I'm still using it without them knowing and it's the reason why I'm 10x faster than everybody else to build solutions.
The other language it's the only one they "learned" at uni and keep using it for everything, even when it's the worst possible choice, management doesn't care and doesn't know the difference.
software engineering is still not engineering, unfortunately.
the "too slow argument" is normally based on old internet opinions and benchmarks.. ruby today is pretty fast. In the company that I work, we do a lot of system programming using ruby, web development, etc.. It came to substitute perl around 2005, and we still using it successfully today. When we need something really, really fast, specially including parallel processing and etc, we just use jruby.
did you benchmark Jruby or TruffleRuby? Did you compile c-ruby with jemalloc? Normally the "ruby is slow" argument, is based on not being involved with ruby and solving real problems with it. Some people will just LOL this argument even harder if you add development time and code maintenance costs on that equation.
Also premature optimisation. I did image manipulation and statistical analysis of images using predominantly Ruby for my MSc thesis work 15 years ago, and it took rewriting a couple of dozen lines of code with RubyInline (to use C) to remove the bottlenecks. Using pure Ruby to prototype and rewriting just the maths heavy code to C when I knew it worked and knew where the bottlenecks were saved me massive amounts of time. I've done map rendering in Ruby for similar reasons - outside of specific niches, it's rare for the speed of Ruby to be an issue.
I recall several discussions of it at the time, and I don't think it's so much that they weren't able to, as that they'd made lots of disastrous architecture decisions (building it around a monolithic database etc.) that required a rewrite, and whomever doing it used it as an opportunity to blame it on Rails as an excuse to switch to their preferred stack.
After all, sharding message distribution via federation (even if you hide the federation behind a veneer of a global userid -> shard mapping) was a well understood long before Twitter even launched (e-mail... reflectors...), so it was a rather embarrassing architectural decision to not even try to account for it. Heck, I co-founded a webmail provider in '99, and one of the first things we did was implement ways to map user ids to a distributed set of backends and support for migrating accounts between backends, because we knew it'd be necessary to be able to shard smtp servers, frontends, and storage separately. That wasn't in Ruby, but the architectural pattern is so obvious.
The language change may or may not have made sense for them at the time (after all Ruby was much slower then, and they by then had the size where a rewrite of core parts to cut hosting costs might have been worth it), but that they blamed their architectural failures on Rails was a cheap shot.
Normally such decisions come from "Senior developers", which are experts in other domains than ruby on rails. How often you see them wanting to write raw sql in rails, "because its faster" and/or "much easier".. this summarizes a lot that problem https://daedtech.com/how-developers-stop-learning-rise-of-th...
> did you benchmark Jruby or TruffleRuby? Did you compile c-ruby with jemalloc?
Jruby a little faster than CRuby (it used to be more significantly faster, but CRuby has seen more recent performance increase); TruffleRuby is, OTOH, not slow like other implementations.
> Normally the "ruby is slow" argument, is based on not being involved with ruby and solving real problems with it.
Ruby is abstractly my preferred language, and I’ve done a fair amount in it, though I don't get to use it as much in anger because of issues other than its speed (ending up using another slow language as my main day to day.)
> Some people will just LOL this argument even harder if you add development time and code maintenance costs on that equation.
That’s just equivocation; time and cost to market is an orthogonal concern to execution speed, not a component of it; yes, Ruby has a decent code-writing experience, especially for small systems.
> That’s just equivocation; time and cost to market is an orthogonal concern to execution speed, not a component of it; yes, Ruby has a decent code-writing experience, especially for small systems.
Probably you meant rails here. I don't see why ruby should be a problem for something not small, moreover, you should first define what a small system is, specially if you count the LOC of all the gems that you use..
To think I'd live to see the day the JVM is regarded as "really, really fast".
Ruby is not "pretty fast". The hardware you run it on is insanely, mind bogglingly, out of this world fast and so people don't notice the way that they used to.
...which is fine, you don't always need to be fast. Just be wary of misattribution.
The java based ruby, removes the GIL, which provides us real multithreading.
Truffleruby is "A high performance implementation of the Ruby programming language, built on GraalVM." If you prefer there is even a rust based ruby https://github.com/artichoke/artichoke
again, IMO, the microbenchmark, doesn't matter. What matters is the problem domain, whole stack and the whole "speed", including development, deployment and etc, and for some domains, ruby is the best and fast choice.
How is "I don't like it" not a good reason for not using something? Ruby in science is the path of most resistance; if your work isn't already hard enough, here's a way to make it harder. That's because everyone is using Python. Think of it like writing scientific papers in English even though you like Esperanto better. Everyone uses English, so you have to too. That's Python's current state.
> How is "I don't like it" not a good reason for not using something?
Don't ask me...
> Ruby in science is the path of most resistance; if your work isn't already hard enough
It actually isn't that hard, honestly.
Very few people do cutting edge work that requires analyzing massive amounts of data and, from my experience, other languages are not much better.
They still rely on C (or Rust) bindings, because they aren't adequate per se for the task.
> That's because everyone is using Python
Yep, the aforementioned inertia.
But, IMO, as a programming languages nerd, some syntax are worse than others and I have to review many Python programs that conceptually read like someone speaking a foreign language without knowing the rules, like "I go make shoppings". That code wasn't "created" but simply copy/pasted from somewhere else and then adapted because some concepts don't require understanding, just tinkering.
Python it's not easier than Ruby, shooting yourself in the foot with Python it's easier than in Ruby and yet, here we are.
At least in the diatribe C vs Rust, C is actually simpler than Rust as a language and programmers have to learn fewer concepts, even though Rust is better as a language/ecosystem overall.
> Everyone uses English, so you have to too
That's exactly the point, the most spoken language in the World is English spoken by non native speakers. Like me. It's not British English or American English (in Europe is Russian, anyway, and Chinese and Spanish would like to have a word with you).
So it is people's Esperanto, which is kinda of an abomination linguistically, but language evolve naturally it does not need a compiler or an interpreter to work.
When I am abroad for holidays or conferences, I can perfectly understand what people mean when they speak "Engrish", native speakers often don't.
But in programming the concepts are the same in every language, so it's not like learning Finnish if you are Egyptian, it's more like learning to ride a motorbike if you can ride a bicycle.
People learn Pandas and Numpy and Scikit-learn, not Python, when I learned how they worked porting the examples to Axon[1] wasn't hard. I managed to do it with the help of a colleague whose versed in learning programming and he thought Axon was more readable than Python. But then again, people usually think they know X better, feel more confident in X and will keep making the same mistakes over and over, because they don't know what they don't know and their salary do not depend on it. They have people like us fixing their code. Their salary depend on writing "I know X" on their CV, which usually is just not entirely true.
Ruby just got out of fashion, but it isn't inferior to any other language out there and its ecosystem is completely fine.
Adoption-wise Ruby is a new Perl. Such a shame really, Ruby is one of the best scripting languages yet available, if Linux distributions had it by default it would dominate over py and shell-scripts.
It's a shame that this example will only be understood by the people who already agree with arguments against Python; but you really made my day with it.
In what situation is python the worst possible choice, while ruby which is very similar to it is the best possible choice? Unless you're doing some clever ruby metaprogramming type stuff which is totally impossible in python.
> In what situation is python the worst possible choice, while ruby which is very similar to it is the best possible choice?
in no particular order, on top of my mind (there are many more):
- mixed environments when you can't compartmentalize Python in a container. Python package management is one of the best examples of "poor implementation"
- mixed environments, when both Python 2.x and 3.x are present. Migration to Python 3.x is the textbook example of "badly executed". And we are still not entirely there 10 years after.
- prototyping web apps, in the same time spent configuring Python venv, you have a perfectly functioning Ruby prototype
- writing web apps, in the same time you understand how to make a custom sql query in Django, you're already selling your first product in Ruby and the website won't be ugly as hell by default. Rails is the killer app, nobody can deny it.
My biggest gripe with Python is that many times when I have to deploy Python, I discover an issue and ask the author(s), I'm back to "but It works on my computer" times, like when I started, in the 90s of previous century.
Yes, Python is used to write beautiful things such as youtube-dl and Sublime Text (porting Sublime to Python 3 is one of the reasons why Sublime is almost dead). However, given the fact that in Sublime plugins are written in Python, people flocked to (even!) Atom, because they could use other languages, not inherently better, but with less issues connected to the language used.
I lost count of how many times Sublime died on me and stopped working spouting Python errors that I had no time nor will to fix.
Disclaimer: I am a paying customer of Sublime 2 and 3.
Edit: lots of Pythonists triggered for no reason apparently.
Don't take it personally, if you have counter opinions, express them. Downvoting is not an opinion, it's a passive aggressive way to show disagreement, which frankly is the reason why we're still stuck with Python. I don't mind an honest discussion and people disagreeing with me, it's why I am here after all.
I think this could be summed up as a) python venvs can be very annoying, and are a weakness of python, and b) rails + active record is a strength for ruby. Fully agree with both, but disagree with the hyperbole (worst possible choice vs. best possible choice). FWIW I haven't even seen Python 2 code in about 6 years.
With all due respect, as someone that’s probably downvoted everything you’ve said on this thread, my reasons for doing so have nothing to do with your language preferences. Your comments are needlessly impassioned and vitriolic. I am not even remotely interested in the type of religious war discussion you are trying to foster.
I can honestly say with complete confidence that I’d feel this way regardless of what language you were talking about.
In addition to this though, as someone that writes Python / Django professionally and has done so for some time, my familiarity with the language gives me the necessarily insight to see where your experience is limited. I’ve seen a few inarguable factual inaccuracies (i.e. not based on opinion) in what you’ve said in a few comments. It seems obvious that when you engage with Python and Django you aren’t doing so all that willingly. But honestly your strength in your convictions puts me off getting into a back and forth with you to reach a shared understanding. The confidence with which you’re writing feels a bit misplaced.
Your overuse of hyperbole makes it hard to tell what you actually believe and what you’d genuinely argue for in a real-life professional context rather than behind a screen name on an Internet forum, so even if I wanted to engage in a back and forth I wouldn’t even know where to meet you.
This is a classic example of the loudest and most impassioned voices framing themselves as winning because people just don’t want to engage.
This is all to say before writing off downvoters are upset people on “the other team” which are lesser than you, consider the possibility that you’re probably throwing your weight around a bit too much and are creating an environment that’s generally unpleasant. I’ve enjoyed the tech community largely moving away from the “us vs them” mentality. Truth be told, none of this shit matters enough to warrant that sort of mentality. I feel like I’ve stepped back in time reading your comments. Not only are they unenjoyable to read, but I am not an iota more enlightened about the comparative benefits of Ruby vs Python. So I ask you…what’s actually your intention in commenting in the first place? The truthful answer to that question is why I’ll continue to downvote.
> Your comments are needlessly impassioned and vitriolic
I'm simply Italian and english is not my native language, so I use the most simple versions of it, resulting in what you call "vetriolic"
Have you ever heard some english native speaker, especially Americans, trying to speak Italian?
they all sound like Don Vito Corleone. Should I assume they work for the mob?
So, basically, you let your prejudice guide your actions.
If you prefer possiamo parlare in Italiano, la mia lingua madre, che conosco molto bene e grazie alla quale posso esprimermi in maniera estremamente più formale. In Italiano, per esempio, le avrei dato del Lei, non del tu, che ritengo molto poco professionale fra persone che non si conoscono e stanno sostenendo una conversazione in pubblico. Nella mia lingua è un segno di reciproco rispetto.
Spero Lei capisca che il mondo parla molto poco inglese e che quello che a Lei sembra "al vetriolo" certifica solamente una sua mancanza di empatia nei confronti delle altrui culture.
Cordiali saluti.
> This is all to say before writing off downvoters are upset people on “the other team”
I have no "team" I just have 26 years of experience in the field and Python deployment is way worse than deploying PHP apps in 1995. It's hyperbolic, I agree, but it's also not far from the truth. PHP was a simple FTP all the files on some host, Python projects most of the time miss or have incomplete requirements.txt, you have to reverse engineer dependencies, there are N distributions so you have something developed on Windows using Conda but the deployment server is Debian stable with pip etc. etc.
I don't think I'm saying something people never faced, but if that is the case, well, It means I am the only one and that is good news!
Add to that that, not to their fault, scientist have been sold the lie that Python "is easy" or "is the language for scientists" (I still remember in 1995 at uni when as a CS student I was working together with the Biology department on DNA sequencing and Perl was all the rage thanks to "Beginning Perl for bioinformatics" book, how much things can change in a couple of decades...)
Python is not so easy and coding something that runs in production is not the same thing of running experiments in a lab once, where "it just works" is enough.
Also, language inconsistencies and a patchwork design, led to very confusing results, like C++, without the extreme power of C++.
Like Perl, without the extremely good bits of Perl.
I do not write Python as my daily job and I do not write Ruby since 2015.
Ruby is simply a better language than Python and Python 2, as a language, was better than the first 5-6 years of Python 3, because it was really a simple language where there was only one way to do stuff.
Python 3 is simply another language, that solved very few of the issues with packaging and dependency management it inherited, broke backwards compatibility and for a decade coexisted with Python2 making everything a lot more problematic than it should have been.
Is that a language's fault? Only marginally, but I think that the way transitions are handled is one of those things that tell you a lot about how much you can trust a tool. Python failed miserably.
While, for example, PHP in the same time frame it took to migrate Python from 2 to 3 solved a lot of its problems to the point that, if it was preinstalled, I would much prefer it to Python.
Meanwhile Ruby, the real argument of this submission, arrived at version 3.2 with a new Jit that improves performance 40% in benchmarks. Not bad for a "slow language".
The only thing IMO that saved Python from oblivion is that Google invested a lot of money on it.
Briefly about the ecosystem: I've recently started using Polars in Rust and Elixir and it's a 100% replacement with better API and performance [1] than Pandas. It has also Python and Ruby bindings. Why people do not adopt it? Beca...
> one that lacks the elegance and consistency but which has a larger ecosystem.
... and decent first party docs, actual code modules rather than “execute every source file in the global namespace”, a first party Windows build, etc., etc., etc.
If the Ruby community can't acknowledge the real things holding it back compared to other available options, well, that makes it that much harder to catch up.
They did apparently manage to make their interpreter figure out where mismatched "end" statements are most likely to be, which was one several serious pain points for me with the language.
I don't think the execution model you mention, which results in the absurdity of C style transitive includes polluting the global namespace, will ever be changed though.
> I don't think the execution model you mention, which results in the absurdity of C style transitive includes polluting the global namespace, will ever be changed though.
There is a proposal at https://bugs.ruby-lang.org/issues/19024 to change this but, as you can see from the comments, it’s a bit tricky to get right while preserving backwards compatibility. (Whether that conversation makes you more or less optimistic about the chances of it ever being changed is up to you.)
> They did apparently manage to make their interpreter figure out where mismatched "end" statements are most likely to be, which was one several serious pain points for me with the language.
Searching for a mismatched/missing _end_ is preferable to having a line or block get accidentally unindented and end up still "working" (running) while producing very confusing results.
Moving blocks of code in Python requires great care, especially since the editor cannot reasonably guess which scope level the paste should go into.
Also, the lack of an _end_ or bracket as with other languages means the editor cannot visually assist with identifying block boundaries. To be fair though, my vim-memory of using % to bounce between start/end brackets doesn't work in Ruby because of the begin/end words instead of matched symbols :(. However, RubyMine does show the beginning of the block as an unobtrusive popup at the top of the window when your cursor is on the _end_ keyword. That's super handy when there are several blocks closing in succession.
I had over million euro of machinery stop because a rarely reached branch had one line with one less space due to missing linter run. Apparently Python 3 still doesn't fully parse and validate code on load, or somehow it made a valid if nonsense AST out of that.
> Moving blocks of code in Python requires great care, especially since the editor cannot reasonably guess which scope level the paste should go into.
Even when I was new to python, the only problem I ever really had with this is when I mess up and copy the first line starting at the the first nonwhitespace character so the relative indentation is wrong. When do you ever move a block and not know what scope you want it in? At most, with really long blocks, you fold the more deeply nested blocks before pasting.
> Also, the lack of an _end_ or bracket as with other languages means the editor cannot visually assist with identifying block boundaries.
No, it doesn’t. In practice, editors usually don’t, but they recognize the beginning and ending of blocks, and use it for folding, which means they could insert phantom labels (as editors often use for blame information, inferred type signatures, etc.) to provide informatiom about the block ending (and even align them to indicate the indentation level corresponding to each ending block.)
An existing line of text is not necessary for editors to provide feedback.
> To be fair though, my vim-memory of using % to bounce between start/end brackets doesn't work in Ruby because of the begin/end words instead of matched symbols :(
Yes, that's the problem for plain vi(m) which only supports single character braces.
matchit/matchup extends this to language specific delimiter words. This animation https://github.com/andymass/vim-matchup#screenshot shows how you can iterate over multiple sequences like if/elsif/else/endif.
Yeah indentation in Python can be problematic - I've run into problems from time to time.
The issue with Ruby specifically (which doesn't exist in other common languages that have bracket- or keyword-delimited blocks) is that non-keywords can start blocks. So it's difficult for an editor to determine the likely matches, and it's even harder for a human. That's my vague recollection of the problem that I ran into numerous times, though it was about a decade ago.
This suprises me. I've missed `end`s before as much as anyone, but I guess as an OCD reformatter (prettier, IntelliJ, rubocop, etc.), they show up VERY OBVIOUSLY and right quick. They've never even been an itch, much less "pain".
You are obviously referring to Python and so I would like to note a few things. (I have nothing against Ruby)
> Ruby ... its combined attributes of brevity, expressive power, and feature consistency.
> [Python] lacks the elegance and consistency
First I would argue Python is very consistent in its design, it aims to only have one obvious way to do things and so it's easy to guess how apis will work. It also aims for explicitness, which makes code very easy to follow and reason about.
Secondly on "brevity" and "expressiveness", I don't really see them as an attribute that make a language "better". Sure for experienced developers who like a personal game of code golf (don't we all at times!) those are attributes can can make coding more "fun". But that doesn't necessarily translate to code that is ideal when working as part of a team, or code that is easy to follow when a new developer starts on an existing codebase.
Ultimately I think that's why Python has gained more traction than Ruby, it's an "easer" language to follow and start with. Ruby is probably a more fun and intellectually stimulating language to work with though.
Python gained traction because of Google (Google used it initially then Guido worked for them for a decade+, vs. Matz at Heroku/salesforce) and then because it's the easiest way to use ML libs. That's it.
It's slower than Ruby, has worse package management and less consistent syntax but if you want to use Tensorflow, PyTorch, etc..., it's the default.
I first started using Python slightly after that time and for years it was a pretty niche language that relatively few people used, especially compared to the other 'P' languages, Perl and PHP. I'd estimate 2001-2002 as when it would say it started to become a 'normal' language and I wouldn't say it really started taking off until around 2005ish.
Can I assume the '85' in your username indicates a birth year?
Zope was a Python project from the late 90s, and had quite a bit of attention and traction in the early cms/publishing days. That brought Python attention, and certainly gave it some mindshare in the late 90s.
I don't think Zope/Plone had hardly anything to do with Python's rise. While a number of significant sites were built on Zope or Plone, the relative ease with setting up such a site meant that little or no code-level modification or extension was necessary.
My first real professional programming project was written in Python, using Django 0.96, in 2007. It was at a large shipping company, and "under the radar" - i.e., the "business side" did it, as IT wouldn't support it.
Two years later the project had become an integral part of some critical business processes, and IT had to take it on. They decided to rewrite it in C#. I left the company at that point, and almost a decade later I got a call from a former coworker asking for help to fix the system. It turns out it was basically unchanged from when I left, and the address of the Exchange server that it relied on for auth had changed.
In fact, Google---back then BackRub---was originally implemented in Java and Python, long before Guido joined Google. "Huge" is obviously a subjective word but if it means "not small" then Python was already not a small language even at that time.
That's a fairly Silicone Valley focused argument. I don't subscribe to the theory at all that Google closed internal use of Python was instrumental in its adoption.
Django was released in 2005 and RoR in 2004. I suspect my journey was similar around then (late 2005), I had used PHP, classic ASP and a little Perl. I was looking for something better, read the tutorials for both Django and RoR. Had a look at what desktop GUI toolkits were available for both Ruby and Python (I wanted to lean one new language), Python had a few more options and so went with Python and Django.
At the same time Python was gaining significant traction in the scientific community with NumPy (2006/1995) and SciPy (2001). Ruby I don't believe had an answer to that back then. I was vaguely aware of that and it somewhat influenced my decision.
Ultimately it was the two pronged (web + scientific) development of the ecosystem that pushed Python ahead of Ruby.
Had a similar journey, started with ASP in the 2000s, then PHP around 2003, then worked with both RoR and Django professionally for a few years.
As much as I liked RoR for its scaffolding and easiness of bootstrapping new CRUD projects, over time with larger codebases and teams it just starts to be a mess. Ruby programmers love the terseness of the language and write some of the most ungrokable code I've encountered (second only to some Scala codebases I worked with). That and the magic of autoloading modules which then could introduce a DSL, the usage of mixins that are hard to trace where they are loaded from, and a lot of other magic features that are extremely opaque to parse through and debug is, ultimately, what made me abandon Ruby and RoR.
It has its uses but I've yet to see a decent legacy RoR codebase without these pitfalls of magic, after so many years professionally working with code I prefer any language environment that is explicit, Ruby is not explicit.
Python was already in the gold path years before Rails, thanks to Zope, being an alternative to Perl, and research labs like CERN and Fermilab starting to adopt it, this is back in 2000 - 2004.
When Ruby and Rails started to make an appearance in European circles, around 2007, it hardly mattered when Python was already around.
Basically any benchmark that uses just the language. Throw some loops and maths in there.
It doesn't really matter though, both languages are used typically for scripting. But just shows it's not really about the "language", it's about the ecosystem.
JavaScript is a scripting language but wipes the floor with either (like 25 and more times faster) and can be used to actually do something other than being a glue.
JS was slow before V8. Also TruffleRuby brings Ruby very close to V8 speeds. I just didn't consider that because it's not really a drop-in CRuby replacement.
Also JS is still too slow for most things compiled languages are used for.
A Miata will smoke a Neon in the corners and is just more pleasant to drive. Miatas are the number one hobby motorsport (racing) vehicles of choice for a reason.
Which is actually a great analogy for Ruby vs Python!
When I looked at Python vs Ruby many years ago, I found the opposite: Why does Python have (special) functions like len() and map(), instead of 'properly' supporting both OOP (len should just be a method on objects) and/or FP (support multi-line lambdas so I can actually use map/filter etc).
I never understood how this can be considered consistent at all, and those IMHO language design warts made me look into Ruby at the time.
Has this improved since? I know print was changed in Python3 to make it not-special.
map() and filter() being functions means you can run them on any object that implements __iter__(). To make them methods they'd have to be added to each individual type that might want to use them. IIRC Ruby does that using mixins but that takes up a lot of room in the namespace of each type and makes it a little harder to figure out where the methods come from.
The justification for len() is thinner: Guido van Rossum thinks it looks better, and it enforces a consistent name with a consistent meaning (you don't get length methods with different names, or with the right name but strange behavior). Under the hood it just calls obj.__len__(), so it's only the notation that's not OOP.
There are no multi-line lambdas because nobody could come up with an indentation-based syntax for them that Guido van Rossum was happy with.
In short: none of them improved, all of them have reasons, some of those reasons are bad.
Those functions take any object that supports the iteration protocol. There’s no need for adding say, len, to every object that needs a len function. I’d argue that is consistent.
Sure, multi line lambdas might be nice, but equally you can define functions wherever you need them so it’s not really all that different.
> There’s no need for adding say, len, to every object that needs a len function.
fwiw, Ruby does the same thing, but using the Enumerable mixin rather than a free floating function.
> I’d argue that is consistent.
I don’t understand this argument. It’s convenient and more efficient to write, yes. But how is it more consistent to have two different calling conventions?
The claim that there’s one way to do something irks me as well. There’s one way to find the length of something, but that introduces two ways of querying an object. It’s a good guiding principle, but when people use it to make stronger claims, it ends up superficial.
By which I mean that you can consistently use `len` etc on any iterable and they will always behave in the same way. You learn them on day one and they work consistently in every place you see them forever.
> There’s no need for adding say, len, to every object that needs a len function. I’d argue that is consistent.
Python's len works by calling the __len__ method, which must be added to every class that needs a len function.
Since you're already defining a method with a standard name on every class that needs it, Ruby just has you call that method directly as opposed to the absurdity of intentionally obfuscating the method name with underscores so that people use a global helper function instead.
Even C++, with all its warts and its 1980s design got this right in the std lib with the size method.
Honestly, I find some of these defenses of Python quite humorous.
It's almost like they have become memes in themselves. "There is only one way to do it" -> except for those cases where there is a multitude, including the base choice of major release of interpreter, package manager, and so on. Python is very usable but it definitely isn't perfect and the only way you get to improve on stuff is to recognize its shortcomings.
I'd agree that __len__ is a fairly trivial example, but it is used for truthiness in Python too. It seems like a reasonable choice to mark these blessed methods that the language is using deeply as part of the runtime in a special way but I'll happily concede that it could have been X.len() instead.
`sorted`, `list`, `set`, are more interesting cases where they all work with the underlying __iter__ protocol. You don't also want to add X.sorted(), X.as_list(), X.as_set() etc too. Again, you could have X.as_iterable() to implement these, or you could mixin sorted, which will call the __iter__ function. But honestly, it's really neither here nor there.
For the full avoidance of doubt - I'm not arguing for these other "memes" and, in particular, "There is only one way to do it" has never made that much sense to me.
I am arguing that Pythons `sorted` api is reasonable, consistent and not worth worrying about.
Language design is a hard problem. You have to make so many compromises to get it to the point where it works for a large variety of use cases that the degree of ugliness is almost directly proportional to the breadth of application and adoption. The only languages that manage to stay clean are the ones that nobody uses.
I don't think that's avoidable. Mistakes made early on have a habit of compounding over time and calcification makes it harder and harder to deal with them decisively and in a non-breaking way. Python made a couple of bad decisions but on the whole the language came out relatively unscathed, most of the original design constraints are still satisfied. As opposed to say PHP or Java which ended up very far removed from where they started out.
Case in point: Python's GIL must have seemed like a good idea at the time, a quick fix for an urgent problem. And now that quick fix is the albatross that we can't seem to get rid of.
I think it's definitely worth considering what could / can be done better, but people often argue deeply about things that aren't really a massive deal. You've pointed out examples that are much more interesting than "should __len__() have been called len()".
Certainly makes one appreciate Guido's stewardship in keeping the language fairly clean but applicable to large number of use cases for so long!
Yes, I think he did an amazing job. Being the maintainer of a popular open source project is the most thankless job and if the project is a language or an operating system doubly so. Every Tom, Dick & Harriet that has ever opened a CS book will have an opinion and dealing with all that over the years in a courteous way really adds up.
res = (1..10).select { |x| x != 5 }.map { |x| x ** 2 }
With filter_map:
res = (1..10).filter_map { |x| x ** 2 if x != 5 }
In both cases, I think the Ruby solution is more readable.
Python list comprehensions invert the subject (data) and the verb (action). You see what will be done before you see what the subject is. I would argue that showing the subject first allows easier code review as you know immediately what you are working with.
But beyond that, the first Ruby example tells you in English what is happening. "take this range", "select a subset", then "map some actions to the elements".
And the filter_map abbreviation does the same, telling you "take this range, filter it and perform an operation on the remaining elements".
Python tells you nothing... and what it does say is in awkward order.
As functional and data-oriented programming is gaining in popularity (for good reason), adopting some functional practices in Ruby is a pleasant experience. Doing the same in Python exposes more of these... irregularities.
Edit - I always forget how to format symbols in these comments!
The Python one looks fine to me, although I am a Pythonish person.
It uses what people already know: the for something in somethings syntax of the for loop, and the if syntax. Also it's nice that this works in dictionaries, generators and lists.
It also has the same narrative flow of Haskell's list comprehensions, which I think come from set theory:
[x^2 | x <- [0..10], x `mod` 5 /= 0]
As for your Ruby examples: I think you could argue that the filter_map version is very readable, but not necessarily more so, but the select one looks pretty painful.
> As for your Ruby examples: I think you could argue that the filter_map version is very readable, but not necessarily more so, but the select one looks pretty painful.
The select does two passes, which makes it quite inefficient. One does not even need filter_map, since the example is essentially a reduce operation.
res = (1..10).reduce([]) { |a, x| x != 5 ? a.push(x**2) : a }
This works in ruby 2.5.1. Probably works in 1.9 and mruby as well.
I think this is purely a personal preference but I also think there is a bias towards list comprehensions being more difficult to mentally parse.
I do a lot of contract work and chatted with a ton of folks ranging from beginners to veterans. A lot of them (well more than half) avoid list compressions, especially when working with teams because it's such a mixed bag of either being able to instantly understand them or it requires more effort. Personally I don't use them in my code (for both reasons).
Both Ruby solutions are much more clear to me even though I have no functional programming background. I have no preference towards functional styles either, I would say it's the opposite. I struggled with Elixir long enough that I stopped using it.
And yet, in the production Python codebases I've worked with, list comprehensions are rarely seen. Usually it's typical loop iterations. I wonder why that is?...
I always have to stare at list comprehensions very closely to understand operation being done. The source of the data is in the middle, where it should logically come first. The filter is at the end, where logically it should come after the source. The mapping is at the start, where logically it should come at the end.
I find the monadic, additive style of Ruby much easier to understand:
10.times.select { |x| x != 5 }.map { |x| x ** 2 }
IMO it's more composable. What if you want to exclude even numbers from the result? Just add another filter:
10.times.select { |x| x != 5 }.map { |x| x ** 2 }.select { |x| x % 2 != 0 }
Incrementally building up a streaming computation this way is much more useful to me than a list comprehension.
For example, you can add a lazy to the stream to avoid performing all the operations eagerly, and now you have a way to process sequences without blowing out your memory.
By the Python developers and its wider community. As Python doesn't have anonymous function blocks in the same way as Ruby (only lambda expressions), tutorials, lessons and the Python docs steer users toward list comprehensions instead.
I'm not saying the ruby syntax is not elegant (it is), I'm saying in Python list comprehensions are recommended over filter/map functions.
On the composable front, personally I prefer to breaks these down into smaller chunks with descriptive variable names rather than chaining.
Python also has the sister "generator" (() rather than []) syntax which also ensures it remains efficient as it pipelines the whole sequence of generators. (Lazily rather than eagerly as you say)
You're effectively saying something like: Canadians prefer Canada. What about the rest of the world?
Once you start adding more "and" to the if-statement in the list comprehension, it becomes a mess. Breaking them down to smaller chunks is required because comprehensions are messy. You are doing smaller chunks due to a shortcoming of comprehensions. Chaining is nice option to have, especially when the chained functions are straight forward.
> Map/filter are considered inferior in Python to list comprehensions.
> By who?
> By the Python developers and its wider community.
> You're effectively saying something like: Canadians prefer Canada. What about the rest of the world?
They're actually saying that Python developers prefer one particular way of doing something rather than a different particular way of doing the same thing. You're suggesting that they're saying Python developers (Canadians) prefer Python (Canada).
I don't mean to speak against your broader points, just that this specific call out is mistaken.
Map, filter and similar can be chained together and composed much better than comprehensions I think. I realize that it's probably not your opinion that comprehension are superior, (although it might be) but rather the general python style.
I also think that map and filter style computations can be much more powerful, there are quite a few things other than just map and filter, like count, take, skip, find, flatten, fold, map-while and quite a few more!
In python I guess you are supposed to use a standard for loop to do these things instead.
No. You are supposed to use intermediate variables that contain generators, and write short named functions to call within generator expressions, instead of writing big run-on chains and compositions with little bits of anonymous logic floating around in it.
The = binding is the chaining/composition tool of choice. This is why generator expressions are so important, relative to list and dict comprehensions. They both defer the allocation of space for intermediate values and allow the space to be bounded no matter what the input length is.
Often the “reduce” step, or even more commonly, realizing the side effects of such a generator composed of generators is a simple for loop—because that’s the most readable way to walk through it.
In essence, I don't think it has anything to do with elegance, syntax, or "easiness". It's more about timing + origin + corporate adoption:
* Python was created in Europe, Ruby was created in Japan - when Ruby gained more recognition in English-speaking world (~2004), Python has already been present and used worldwide for a decade
* Ruby was created as a personal, hobby project; Python was created while Guido worked in research institutions, and it helped Python gain recognition in academia environment
* Guido joined Google in 2005, boosting the adoption of Python; Ruby has never gained such a large corporate backing
Eventually I believe it was the combination of the latter 2 that pushed Python to top spot in popularity - scientists all over the world were familiar with Python, and with the rise of Data Science/ML (with Google being one of the main forces behind it), it became the most obvious choice for the new tools.
> * Ruby was created as a personal, hobby project; Python was created while Guido worked in research institutions, and it helped Python gain recognition in academia environment
As a data point, I remember interviewing for an internship in a research institution doing some work on medical images around 2002/2003 and the supervisor telling me that Python was the lingua franca in this domain (from a research and POC development perspective).
These explain why Python is the defacto for AI/ML which is interesting but I still totally agree with the idea of Python's simplicity making it just a better choice to get things done. I had a journey from Scala, a compile-time type-safe, flexible and exciting language to Python a dynamic, simple and boring one. Python code just end up being done fast and clean. Scala one never gets the team consensus and is never consistent.
Note that the Python core team started working with the scientific community very early on, the first scientific packages (as well as additions to python for scicom like extended slices) date back to the mid 90s.
GvR’s background probably helped spread the word and thus get feedback, but as often Python’s overnight success was the result of years of work.
The Python core team early on was part of the scientific community. GvR worked at CWI (Centrum voor Wiskunde en Informatica), which was a part of the particle accelerator installation that Amsterdam had once upon a time until most such research went to Switzerland and the USA. CWI has, together with NikHef (the Dutch Nuclear Phyiscs Institute) done a lot of ground breaking research over the years and was the cradle of quite a few spin-off projects.
Be that as it may, what does it matter? You are chronicling ancient history at this point. These languages are more alike than they are different.
Or at least they are similar enough that one pulled ahead and subsumed the other. Like a twin eating his brother in the womb. Maybe it could have gone the other way and we would have ended up pretty much in the same place. Or maybe it is a case of worse is better. But not that much worse/better frankly and here we are. Salivating over rust. ;)
> These languages are more alike than they are different.
I agree with this point. I learned python years before I learned Ruby and I found them to be very similar. Ultimately I dropped ruby because I didn't care much for the syntax and I like whitespace.
I think you're spot on. Ruby actually gained wider appeal only when it gained visibility in the US (via rails). Being present in the markets which drive adoption matters more than being consistent, which python isn't ("one way of doing things" is mostly a meme nowadays, everyone touching python knows it's fake).
PHP got popular coz it could get barely code-literate HTML/CSS web designer to write a dynamic app, and host it easily
Ruby got popular coz Rails could get barely code-literate graduate to write CRUD app and so it was cheap (famous 15 minutes to blog tutorial) for companies.
JS got popular coz, well you ain't got fucking choice on frontend and having your then-frontend JS/HTML/CSS designer be able to also do backend is, well, again, easy and cheap.
"Ruby got popular coz Rails could get barely code-literate graduate to write CRUD app and so it was cheap (famous 15 minutes to blog tutorial) for companies."
That's not what happened, instead Ruby got popular with advanced web developers working in Java who saw that Rails was had better answers than J2EE. If you were barely code-literate graduate you wouldn't recognize that Rails was offering new unique ways doing things.
The 15 minute blog tutorial wasn't really indicative of what Rails was like, just a small sample about how it was different.
It was an advanced tool for advanced users with a long learning curve that eventually paid off in better productivity.
> advanced web developers working in Java who saw that Rails was had better answers than J2EE
I was not "advanced" at web development in 2006, but this is exactly what got me to try Ruby. Previously I had been reasonably happy with JSP and Java Servlets, but this Rails thing promised a better way. And it turned out for most of my needs, it was much better.
Also, the Rails Depot book was excellent, even back in the 1.x days (IIRC). It covered enough that you could build a fully working app with sessions, auth, crud, and reasonably abstracted layouts/views. Oh, and because Ruby was "simple", you honestly could start with that Rails book without knowing Ruby.
I was doing J2EE and was hardly surprised with Rails.
We did Rails one decade earlier with our own version of AOLServer.
The very reason we went to .NET (as beta testers during its availability only to MSFT partners) was because we were fed up having to rewrite TCL into C due to performance issues.
All the Active Record stuff was already something that AOLServer introduced, and we had an improved approach on our product.
The founders of that company went on to create OutSystems based on our learnings.
> JS got popular coz, well you ain't got fucking choice on frontend and having your then-frontend JS/HTML/CSS designer be able to also do backend is, well, again, easy and cheap.
IIRC, a bigger reason for Node's popularity (at least at the very beginning of its popularity) was the fact that it had event-based I/O, which let a single process handle a lot more in-flight requests than Ruby (where the concurrency model was to spin up a bunch of processes and multiplex across them with nginx or similar).
I don't think threads are a poor idea but they have sharp edges.
I work on multithreaded software and I get 31,516,776 synchronizations per second with a lock free algorithm and 12 threads and 31,565,052 on the lock benchmark.
When the threads are increased to 100 (contention) the lock benchmark does 3,419,271 requests per second whereas the lock free algorithm does 19,926,428 so the contention hurts them both but the lock free benchmark scales far better.
For me personally, the killer was that python is typically pre-installed on linuxen while Ruby isn't, and if those environments are controlled or locked down in any way it can be a ballache to get ruby on there. Hence python is the path of least resistance.
I agree with the timing and origin. I think corporate backing was just luck.
Google used Python very early, but other languages became more prominent in 2005, culminating in the creation of Go, after which GvR left.
Indeed people talked a lot about Google "supporting" Python, but the support was pretty minimal (50% job for GvR, where you cannot really do much).
Python has way better marketing though the PSF though. They understood that you can create a circus around the language that is completely removed from engineering, fundamentals and actual core development. If Ruby had been as shameless, it might be #1 today.
Perl was everywhere (on Linux/Unix). Then Python came along an offered enough net benefit over Perl that it really started to displace it, and became the defacto scripting language that you would reach for when creating programs on Linux/Unix.
Ruby has some niceties over python, but doesn't provide enough of a net benefit over it for that same kind of displacement to happen.
I think Python was conveniently there when teaching was looking to switch away from Java. Each wave of students exiting their institutions with a Python background made Python more popular in the field.
> Python was conveniently there when teaching was looking to switch away from Java. Each wave of students exiting their institutions with a Python background made Python more popular in the field
This, plus what other commentors have noted regarding Pythons early developments in academia, have had multiplying effects on adoption.
The alternatives were C, C++, some "academic" language like Lisp (which I wish had really broken into commerce more), Prolog etc., and eventually Java. Python was at such a higher level that it definitely made more sense as a first language for many people... especially since it was capable enough to be more than just a first language.
I don't know about corporate adoption. I started programming around 2008 or so, and the first things I encountered outside of grad school were Ruby and Python. At first I used Ruby because I felt like anything I wrote "just worked", but later I switched to Python because there was just "one way to do things", and also because of NumPy/SciPy/Jupyter.
The thing is, the “one way” is not at all true now. Maybe it was then.
Today’s landscape is better but also very different. And when looking up how to do certain things in Python, Stackoverflow will show you a multitude of options.
The problem for me is that I dislike most of them.
Certainly that was the case for me. Way back I was wondering what language to learn next. It came down to Ruby or Python.
Python was just clear to read.
Ruby looked a bit cleverer but was not so simple. Coming from working on a large C++ code base, I decided Python was the one to do next. Simplicity, clarity and one obvious way to do things as a philosophy.
Personally I think the Python syntax make its more explicit which is an in-place sort vs returning a sorted copy. And also what's a method call vs an attribute access.
It's a convention, quite a nice one, but not all libraries are consistent and it does have different meanings too (! is sometimes used for "raise an error instead of returning a boolean").
In the Python case, `list.sort()` operates on the object, so you can kind of expect it to do mutation (but there's no convention / guarantee). Though it only makes sense as a function that the list object itself implements.
`sorted` is a general function that gives you a sorted list from any iterable, and because working with iterables is such a common thing in software, Python has a bunch of standard functions like that. It's nice because you learn them once and they apply absolutely everywhere.
Ultimately you learn the behaviours of a language and they become second nature. I find both Ruby and Python very clean and easy to read.
You take out the chars from the string, sort them and then join them together again
because a string cannot be sorted, sorting a string makes no sense, you sort the chars composing it.
Also, Python could not do this for many years, while Ruby could no prob
sorted("gheliabciouß⌚⌨⌛🆔🉑🈶🈚🈸🈺🈷🆚🉐㊙㊗🈴")
edit: Python also shows some very counterintuitive semantic
take the example above, to return a string you use
''.join(sorted("gheliabciou"))
'abceghiilouß'
which is probably the last thing someone would think of.
sorting a list does not produce any output, because sort is _always_ in place, so you have to waste a variable to sort a list because you can't sort it inline
list("fedcba")
['f', 'e', 'd', 'c', 'b', 'a']
print(list("fedcba").sort())
None # <-- where did the list go?
# you have to do
l = list("fedcba")
l.sort()
print(l)
['a', 'b', 'c', 'd', 'e', 'f']
again, highly unexpected
my favourite
print([c for c in "bca"].sort())
None # <- WTF? list comprehension is a functional concept!
# this is how you "intuitively" do it
print(''.join(sorted([c for c in "cba"])))
abc
Lots of objects don't have a natural way to return a sorted version of themselves, especially inplace (what's the reverse sort of a range, for example). You get the same in Ruby, as you've just demonstrated. Sorting into a list is the only thing that makes sense in all cases.
In that way `sorted` _is_ totally consistent - it always takes an iterable and returns a list of the elements. If we can't agree on that then I don't think there's much of a discussion to be had here.
> In that way `sorted` _is_ totally consistent - it always takes an iterable and returns a list of the elements
except Iterable is the wrong "interface"
in Python it is defined as
> An iterable is any Python object capable of returning its members one at a time, permitting it to be iterated over in a for-loop.
which is not always what you want for sorting
quicksort doesn't work one element at a time
so basically you have to extract all the elements before sorting them
what about infinite streams?
At least Ruby Enumerable mixins explicitly states that
> The Enumerable mixin provides collection classes with several traversal and searching methods, and with the ability to __sort__.
Another problem with sorted is that it accepts any iterable, true, returning a list of items, but it is not clear how you can tell if the object is an iterbale or not
>>> sorted(123)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
ok
>>> isinstance(123, iterable)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'iterable' is not defined
mmmm
maybe it's because int is not iterable?
>>> isinstace("abc", iterable)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'iterable' is not defined
so the solutions are
# fails for strings in Python 2
>>> try:
_ = iter(some_object)
except TypeError as te:
print('is not iterable')
or
# if 2.6 >= Python < 3.3
from collections import Iterable
# if Python >= 3.3
from collections.abc import Iterable # <- personal note, abc stands for...? core maybe?
# no idea on how to do it in Python < 2.6
>>> isinstance("abc", Iterable)
True
not only it's very ugly, but it can also fail in mysterious ways. As per documentation
Checking isinstance(obj, Iterable) detects classes that are registered as Iterable or that have an __iter__() method, but it does not detect classes that iterate with the __getitem__() method. The only reliable way to determine whether an object is iterable is to call iter(obj).
I have (had) this for all languages, including ruby. No two people are alike and since it's all a "I think this is best" approach (either by person or committee) you will always have some form of it. Unless you use brainfuck, maybe.
When i learned Ruby, it wasn't really a WTF for me - I just learned that '!' methods are destructive, while non-'!' aren't.
However, the destructiveness semantic has been significantly overloaded over the time, so each Ruby (Rails) project probably interprets them in a different way, and it ends up having arbitrary semantics.
I'm used to it, but I personally think that for the reason above, it's not a good syntax/semantic to have in a language.
I wouldn't go so far to say it is arbitrary (unless someone uses it wrongly :) ).
As far as I know, a bang name only exists if a non-bang name exists as well. And the one with ! indicates an unexpected or comparatively dangerous outcome, such as a mutation, raising an exception, bypassing some normal check, etc.
While ! is not always the same meaning, it exists when there is a non-bang version; and it means "watch out, this does some sh*t". Maybe it means mutating the source, or maybe it means "doesn't take the usual path", as with Active Record stuff (raising an exception if validations fail on save instead of just returning false).
And the ? is a godsend, as you can clearly indicate functions which return a boolean (or intentionally truthy) value. As naming functions is a chore, and one which can have significant impact on code readability later, the ! and ? have good value when used properly.
For example, Python's sorted() vs list.sort(). If you are new to Python, and you see sorted(list), you may wonder if that is telling you if the list is sorted or sorting the list. It's actually also very awkward, because most functions are named as their actions in present tense, not in past tense. The built-in Python function "sorted" really should be "sort".
In the list of Python built-in functions, you see present tense verbs like slice(), sum(), round(), etc. Those are inconsistent with sorted() and reversed(). When we see a past tense verb, it feels like a question. With Ruby, if it's a question, it ends with a ?.
BTW, why the hell is Python sorted() and reversed() not just called sort() and reverse()?
And while I'm ranting about inconsistencies, Python my_list.sort() mutates my_list, while sorted(my_list) doesn't. In Ruby, my_list.sort returns my_list sorted, without mutating. my_list.sort!. That is consistent and concise, and the bang warns you that it is destructive.
To me, the ! and ? syntax in Rugby is genius. It is a language wide self documenting tool to explain a dangerous function and a boolean, which make total sense.
I'm definitely a Python person, having used both fairly significantly - Python about ~12y, Ruby ~3y.
One thing I think Ruby gets right is the naming convention for methods that modify the object they're called on (<obj>.<method>!) and callables in general that return a boolean (<callable>?).
My biggest gripe with Ruby is the class implementation. I find metaclasses a bit more difficult to understand in Ruby. I hate that I can't easy determine where a given method of an arbitrary object is defined.
I recall that it wasn't uncommon for popular libraries to "open up" a class that was an integral part of Rails and redefine methods, overriding the original implementation. I recall trying to figure out why the method I was calling wasn't returning the value I expected, even after reading the Rails source. Come to find out, some random library had overridden it. They'd matched the behavior of a previous Rails version, but the Rails behavior had since changed. I spent hours on that specific problem and still resent it to this day :P.
> Ultimately I think that's why Python has gained more traction than Ruby, it's an "easer" language to follow and start with
I don't know enough Python to say anything about how easy it is but Python existed for a decade or so before it became popular and that was after Ruby had became popular. That points to it not being popular because it is easy but for some other reason. My guess is BI and AI made Python popular.
I also explored why Ruby is so hard to learn for people like me on my blog [1]. I totally agree with you. I had to use Ruby at work and I really struggled to grok it. I've picked up many programming languages in my career but Ruby was one of the hardest to really understand.
To me, Python felt like R. Designed by an academic - possibly without computer science knowledge. In a manner where humans bow to how a computer does things. Whereas a similar language of the time, C++ was a more properly designed language.
Ruby more like a philosophy major designing an OOP language - getting done and enjoying getting there were the goals. I took to Ruby more because i never cared about the "engineering" part of languages - just using them as tools to get things done.
For the benefit of those not familiar with the Python string interpolation/formatting situation, I present 4 ways to perform the same string formatting:
> Ultimately I think that's why Python has gained more traction than Ruby, it's an "easer" language to follow and start with. Ruby is probably a more fun and intellectually stimulating language to work with though.
May be now, but for a long time when RoR first came out, many people pick python instead of Ruby because scalability. Maybe a lot has improved with Ruby, and with introduction of Crystal, that may not be an issue any more.
> it aims to only have one obvious way to do things and so it's easy to guess how apis will work.
I’ve seen that statement multiple times, but in my experience it’s far from the truth. For every thing I ever had to look up in Python I often found more than one way of accomplishing the same task and all of them were (subjectively) uglier and less straightforward than Ruby.
> on "brevity" and "expressiveness", I don't really see them as an attribute that make a language "better". Sure for experienced developers
It’s an attribute including for inexperienced developers. Perhaps especially for them. Even for something as basic¹ as writing a file, one needs multiple lines of code and know about `with` or opening and closing the file². In Ruby: `File.write("/path/to/write.txt", "file contents")`. One line, immediately understandable.
> that doesn't necessarily translate to code that is ideal when working as part of a team, or code that is easy to follow when a new developer starts on an existing codebase.
Agreed. Though in Ruby I have found myself thinking “I wonder if this keyword will work” and it does exactly what I expected. With Python, the norm is frustration with the impossibility of doing the simplest of things like defining a constant.
¹ From the coder’s point of view, never mind the underlying implementation.
² Failing the goal of one and only one obvious way to do something.
> Ultimately I think that's why Python has gained more traction than Ruby, it's an "easer" language to follow and start with. Ruby is probably a more fun and intellectually stimulating language to work with though.
Working with various Ruby-adjacent stuff for 10+ years and nothing about Ruby was even "fun" to work with, it was mix of "WTF" and "who designs language like that!".
Python is also not "easier" to start with, I'd put Ruby/JS/Python to be at pretty similar level there. No worrying much about types (till they bite you, inevitably, of course, and cause untold bugs), simple things are simple and actual proper (i.e. "not send it to some piece of C code to calculate) multithreading sucks donkey balls.
I work in Python now, and I often have to use 5-7 lines for what would have been 2-4 in Ruby. Because you have to clutter the Python with trivial details, not because the Ruby code is "magic".
> Maybe like blockchain, once the AI/ML fantasy hype dies down
Two minutes of silence for the poor sods who still thinks that AI/ML is pure hype.
(Granted, there is hype. But there is much real stuff.)
And, also, blockchain and ML/AI are nothing similar, except for Twitter bottom-feeders trying to milk each.
AI/ML already has real applications with hundreds of millions of dollars actual value created. And just like CS itself, AI/ML will perpetrate more and more fields in the coming days.
There may not be an AGI soon, or ever, but mark my words, AI/ML will continue to have growing real applications in different fields.
Blockchain had only hype. ML has substance + hype (AGI, silver bullet to all problems, etc.).
I will not engage in language wars like GP here, because those are stupid.
I work all day with Python, and I also enjoy coding in Ruby sometimes in hobby projects.
>AI/ML already has real applications with hundreds of millions of dollars actual value created.
Hundreds of billions a year probably (and that may be low) if you count online advertising and large consumer facing sites in general. If you turned off the ML behind Facebook/Google/Netflix/Amazon then you'd be lucky to only lose 50% revenue based on my personal experience of adding ML on top of such products.
>I said, "there are so many more jobs for another popular language", and I was clearly speaking of the broad job market... not a few big players.
Most every large company uses AI/ML to actually drive revenue and the number of engineers they'll hire dwarfs all the small startups put together.
To you question however looking at the latest recruitment thread on HN there's roughly twice as much Python as Ruby. About 30% of the Python work is Data/ML related at first glance. So 40% more companies are hiring for Python versus Ruby pure backend right now. I'm not sure how a 40% difference is such a catastrophic difference.
Python is popular because most every large company uses it nowadays and not because a bunch of non-name startups are using it slightly more often than Ruby.
> reason for a company to choose Ruby is if they want Rails
And that there, is the whole "Problem" of Ruby.
Ruby is a beauty. Rails isn't. It's nice, productive (for certain niches) and has a long track-record. But Rails is also often the root of problems such as maintainability, long-term-productiveness, hosting (performance, scaling), and lock-in.
There are far better solutions for simple CRUD-apps today than writing them all out in MVC code. And when you need complex business-logic (i.e no longer a simlpe CRUD app) the , the weird MVC (plus Concerns) that rails offers is simply not cutting it.
Yet Ruby is Rails, and Rails is Ruby. So when Rails looses its niche and usefulness, Ruby uses it's niche and usefulness. And that's a shame.
(I am a 12+years Ruby, former Rails, and now moving-to-Rust developer)
Honestly I don’t agree. In my experience Rails easily becomes a rat’s nest of magical code that is nearly impossible to read. A bajillion imports leads to code being pulled in from who knows where.
Last time I used Rails was years ago, but I found Rails had a huge mental load when developing. So much magic and inference, you had to carry the whole Rails mental model around with you to read some simple code. I think that's a danger in any framework, but it felt especially acute to me in Rails.
This is really a matter (or problem) of how people use Rails. I am very much not a fan of magic, and I prefer explicit over implicit.
You cannot use the same approaches for serious, big Rails projects as you might for quick and dirty proof of concepts. And by that I mean OO, mixins, fat models, overemphasis of ORM, etc. will hurt down the road. But most of these same points are true for Django too.
The better way to use Rails is for the core features, and then keep the business logic in modules in "services" (just domain specific organized modules which have little or no dependency on Rails, and are therefore super easy to write complete tests for).
An organically grown Rails project that started as an MVP will predictably turn into a ball of sadness if not refactored significantly at various stages in the life of the project.
I've used Ruby since 2005, and I've disliked Rails pretty much from day one, and really wish the two were not so intertwined. At the same time I've used Ruby professionally almost as long while only rarely needing to touch Rails so I disagree it loses its usefulness though Rails fading from popularity certainly has an effect.
I did not mean that Ruby isn't useful without Rails.
But I do see the fading popularity of Rails (and therefore) Ruby to start affecting its usefulness. Less libraries, fewer bindings, abandoned libs and fewer hosting options.
But Ruby is slow. Performance matters. In a world when everything seems to run in cloud servers, efficiency matters.
If you can have 20 times more simultaneous users in the same cloud server by using a different tech stack, there's no reason to keep using Ruby.
For the record, I also think Python is generally slow, but it has improved in the latest version, and the important libraries for Python are written in C++.
Not in the vast majority of practical use-cases anyway.
There'll obviously always be the exceptions like Twitter having to migrate off Ruby (Well rails) because scaling is just too hard. But those are exceptions.
My direct experience with combating scaling issues in Rails applications always comes back to Rails itself. (ab)uses of Active record, specifically. And sometimes they're very hard to detangle. After well over a decade of doing this sort of work I'm simply not interested in seeing yet another Rails mess.
I do agree that Rails is often a cause of bad performance.
Not in the first place because of its own, or Ruby's poor performance, but because it's easy to write horrible code, and hard to write nice code in it. AR is a very leaky abstraction over a DB. A horrible query always a mere has_many, sort or default scope away. It's MVC horribly unsuited to manage and isolate business logic. The result often indeed being code that performs terrible.
And then there is PHP... which is also insanely fast now compared to even 5 years ago, it is stateless by default, but you can also run application servers in long threads for even more performance. For 2023, the PHP community is seriously committing resources to making this long running scenario more efficient and performant.
Except for the ML/AI use case, Laravel has more batteries included I would argue than Django. A ton more features when compared to Rails. All of them are first party solutions for things like Auth/Queues/Monitoring/Payments/Testing/Local Development and even some starter kits.
If you're building a new web based company that isn't focused on building the next AI avatar generator, Laravel should be on your radar if you're also considering Rails or Django.
If anything, the popularity of the major cloud providers is evidence that efficiency in the sense of computing power per dollar matters very little to most, as their pricing is extortionate.
Ruby was a day late and a dollar short. "Established language X, but cleaner and more elegant" has never succeeded on its own and never will; if you want people to switch languages then you have to have a clear selling point that language X doesn't do.
(Also if you ask me Ruby never was cleaner and more elegant than Python in the first place, at least in the ways that matter; there are definitely things it does better, but if one of your language's selling points is scripting style use then there are limits to the value of consistency)
> But that other language also has a popular (and comparatively clumsy) web framework
Django is today more elegant, more complete, and better documented than Rails ever was. 10 years ago you would have been correct. 5 years ago they were about evenly matched. Today it's not even close. Python is eating the world, and web frameworks are no exception.
Django might be better but Ruby as a language is way better thought out than Python. Python feels like it's cobbled together compared to Ruby. There is a certain elegance with the language, that is hard to find elsewhere.
I use Python every day and I like it. However, functional semantics are not elegant at all IMO. Using list() and map() all over the place is not cool, and like many others say, list comprehensions, though concise, are not always that readable (and I say this as someone who reads and writes plenty of them). Lambdas are not great, either.
In Django in particular, async feels like an afterthought, compared to other frameworks where it's first class.
Python lambdas are not great but Ruby not having first-class functions is also not great. Neither are perfect and there is no syntactic reason outside of variations of personal taste to choose one language over the other.
There are a boatload of compelling reasons to choose Python for its libraries and documentation and adoption level, though.
I didn't know Ruby didn't have first-class functions but that's already a massive no for me. You don't need to convince me regarding Python though - it's too convenient to pass up. And despite its shortcomings it's certainly not a language devoid of elegance like some in this thread are painting... Like the old adage goes, there's the languages nobody uses, and there's the languages people talk shit about. Or in simpler terms, as seen in this thread: "everything I don't use is utter shit".
"The identifier of a regular "function" in Ruby (which is really a method) cannot be used as a value or passed. It must first be retrieved into a Method or Proc object to be used as first-class data. The syntax for calling such a function object differs from calling regular methods."
Why do people like you insist on talking about things you don't actually know about?
The Wikipedia article is wrong. A proc is a function. The misunderstanding here is confusing methods with functions. "def foo" defines a method, not a function. That same article claims that Java has first class functions on the basis of anonymous inner classes, that C# has them because of lambda expressions, etc. OCaml has different syntax for functions and methods. Does that mean it doesn't have first-class functions?
You should really consider whether this is an important enough topic to be worth personally insulting people over.
Ruby doesn't have first-class methods, either. Python has both first-class methods and first-class functions.
> In computer science, a programming language is said to have first-class functions if it treats functions as first-class citizens. This means the language supports passing functions as arguments to other functions, returning them as the values from other functions, and assigning them to variables or storing them in data structures.[1]
OCaml has first-class functions, the names can be passed around as parameters and returned as values. Ruby functions and methods cannot; only Proc objects and Method objects proxying for them can be.
You should really consider whether pointing out your incorrectness constitutes an insult and why you think this is so.
Everything is an object in Ruby. Proc objects and Method objects _are_ functions. The same is true in Python -- functions are instances of the 'function' class. What's the difference between a proc and a function? Nothing.
"[P]eople like you insist on talking about things you don't actually know about" is insulting language. Consider discussing this with some people you know in real life to see what they think.
You can’t use a Proc or Method value directly to call a method with the Ruby method invocation syntax! In Python and JavaScript and Scheme and OCaml you can! This is the whole idea behind “first-class.” Whether “everything is an object” or not is irrelevant.
There is nothing about first-class functions that requires function call syntax to be the same as method invocation syntax. OCaml, Objective-C, and Smalltalk all have different syntax for method invocation and function calls.
To make it concrete: what are you unable to do in Ruby that you're able to do in the languages that you claim do have first-class functions?
This is such an asinine argument. Function pointers and passing an environment struct in C let you do everything an OO language does. What are you unable to do in C that you can do in Ruby?
You can implement a type system in Scheme if you really want to, what can you do in Haskell that you can’t do in Scheme?
Just admit you are wrong, bud. It’s not as hard as you’re making it out to be. Strachey’s definition is quite clear and Ruby doesn’t have first-class functions nor first-class methods. It’s a language flaw just like Python’s lambda is a language flaw.
I'm not sure how clear Strachey's definition can be, considering he never provided one. But his description of ALGOL procedures as second-class mentions that they can "never be represented by a variable or expression":
In Ruby you can assign a function to a variable, pass it to a function as a parameter, return it as the result of a function, and test two function objects for equality. Ruby has first-class functions. If it didn't, you would easily be able to provide an example of a program using first-class functions that cannot be represented in Ruby.
Procs are functions (at least, they are functionally equivalent to Python functions—as pure OO languages, in both Ruby and Python first-class callable entities are richer than classic functions, even when counting closures as a kind functions and not a separate thing that includes a function, because they can carry metadata besides the environment of a closure.)
> It's in the Wikipedia page.
The Wikipedia page is wrong in that conclusion.
> The identifier of a regular "function" in Ruby (which is really a method) cannot be used as a value or passed
A method is a very different thing than a function. But, on a deeper level, I think it is also a mistake to call the thing it is referring the identifier for the method, its just syntax sugar for a symbol passed to a #send call, which, if send isn't overwritten on the sender (which it probably shouldn’t be, overriding send is a good way to cause chaos) will result in the method being called, unless some other method has priority.
> The syntax for calling such a function object differs from calling regular methods
The syntax is different only inna waybthat reflects thebdifferent behavior. Calling #call on a Proc or Method object (again, assuming a sane world where the object’s send method isn’t overidden) does dynamic method lookup on the :call name in the Method or Proc, and its syntax is exactly normal method-call syntax for that behavior (unless you use the shortcut syntax of “.()” for “.call()”, but that's just syntax sugar).
Using normal method call syntax does dynamic lookup on the method name provided in the call on the receiver object identified in the call.
That is, Ruby methods are first class, but what it is a convenient shortcut to think of as “method call syntax” in Ruby is not really method call syntax, it is syntax for a message send that will (by overridable default) result in calling a method with that name if it exists in the ancestor chain of classes for the object, so it is inaccurate to view the “method call” syntax excluding any parameters as “the identifier for the method”.
> its just syntax sugar for a symbol passed to a #send call
This isn't the case. If you override `send` it only affects direct usage of `send`. You can't override method dispatch. You can in some other OO languages but not Ruby.
Agreed otherwise. `x.foo` in Python and `x.method(:foo)` in Ruby do the exact same thing -- return a bound method object that can be called. These are both "proxies" in a sense but they're also first-class functions in all meaningful senses.
> This isn't the case. If you override `send` it only affects direct usage of `send`.
Correct, I both (minor) confused #send with #__send__ and (more signifcant) misremembered the mechanism of some deep metaprogramming hacks involving a a mostly blank proxy object and #method_missing as using metaclasses and #send/#__send__ hacking; where that came from I don’t know. Should have not mentioned overriding (as its a tangent, in any case, as well as vmbeung wrong) or the #send method and referred to the fundamental underlying message send operation.
You just gave away the difference right there. x.foo doesn’t “return a bound method object.” It just accesses an attribute and returns the value of that attribute. The attribute can be any Python value. If it’s a callable then it can be called with parens. There is no proxying whatsoever.
In contrast x.method(:foo) does do that proxy construction that you describe… because Ruby does not have first-class functions.
> x.foo doesn’t “return a bound method object.” It just accesses an attribute and returns the value of that attribute. The attribute can be any Python value.
x.foo returns an "instance method object", which is a "callable type". Also referred to as a "bound method", the same term that Ruby and JavaScript use.
> When an instance method object is called, the underlying function (__func__) is called, inserting the class instance (__self__) in front of the argument list. For instance, when C is a class which contains a definition for a function f(), and x is an instance of C, calling x.f(1) is equivalent to calling C.f(x, 1)... Note that the transformation from function object to instance method object happens each time the attribute is retrieved from the instance... It is also important to note that user-defined functions which are attributes of a class instance are not converted to bound methods; this only happens when the function is an attribute of the class.
This last part is why the following program has an error:
def foo(self):
print(self)
class Foo:
def __init__(self, fn):
self.foo = fn
x = Foo(foo)
x.foo()
You are studiously missing the point and spamming irrelevant details. Yes, there's a Python "proxy" in your docs but it is syntactically transparent. Proc's proxy is not transparent.
me:
> If it's a callable then it can be called with parens
The docs:
> These are the types to which the function call operation (see section Calls) can be applied:
True of Python instance method objects. False of Ruby Methods and Procs. Therefore Python has first-class methods, and Ruby does not have first-class functions nor first-class methods. End of discussion.
In Ruby, the function call operator, `.()`, can be used on both Method and Proc objects. This being different from the syntax used for method invocation does not have anything whatsoever to do with whether functions are first class. You are both wrong and being unreasonably rude about it.
This is simply false. Ruby has first-class functions.
Not only that, it has blocks, which few other languages have. Ruby optimizes for the common use-case of a method that takes a single callback/piece of code, and I miss it in most other languages, including Python.
In Python, the "with" statement is super special. But in Ruby, it's just a method that takes a block. And any method can take a block, not just one per class.
I don't know anything about Rails but after having built a fairly large production web app with Django about a year ago, nothing about it felt cutting-edge to me:
- Async support was second class back then, not obvious how to implement fully.
- REST APIs are a library add-on instead of first-class. An excellent library, but still.
- The package ecosystem sometimes reminded me of the wild-west that is Node.js
- Dependency management is a complicated story (arguably caused by Python, rather than Django itself)
- Django Models are cool and expressive, but nowadays I would rather express my models in something like a dataclass, or a Pydantic model, or just a regular class...
Maybe Rails has these problems and more, I don't know. I'm not saying I'm never going to use Django again, but there's a large chance I will look elsewhere for a batteries-included framework next time I need one.
Lack of libraries is noticeable - especially since I've worked with python for past years.
However Ruby's syntax is way nicer. I can actually write what I think instead of having to translate my thoughts into python. Of course over time working with python has made my thoughts to conform into more pythonic way, but I still occasionally find myself thinking how something would have been way nicer to write in ruby instead.
I chose python over ruby eons ago because, for whatever reason, ruby reminded me of perl (not a good thing). Something about the syntax turned me off. Rust has similar problems for me.
What made me pick Django (and Python) over RoR back in 2009 when I was looking for next language after becoming unhappy PHP was experience with part of its community.
But it wasn't positive experience with Djangonauts. It was negative experience with RoR devs. I've never had random Django person come from nowhere either on web dev forum or PHP forum to *flame* others for using PHP. But it was regular thing with Rails devs. AFAIR the term "Rails Zealot", meaning combative tribalistic RoR developer who goes around the web to try to convince other devs that they should switch to RoR using aggressive and flaming rhetoric comes from around that time.
I've though this was regular PHP hate, but when I've started learning Django and participating on Python communities I've found out that at smaller scale the flamewars are also there. But this time the reasons why I am "harming myself" and "not real programing" were different.
So, how do you reconcile this opinion with the fact that Ruby can't even do a proper REPL on Windows? It just starts showing weird output, overwriting lines and doubling up other ones... that other language just works.
And look, I LOVE Ruby. I come from twentyish years of Perl, and I really like the way Ruby feels when banging out a script but these days, time is in short supply, and I just don't have time to screw around with Ruby.
If I were someone who was gravely concerned with Ruby's future, I really don't know where to even begin.
* DataSci/ML scene is basically nonexistent, that's a problem.
* Windows scene isn't good, at all. That's a problem. At least it's kinda there, so you wouldn't be starting from scratch at least, like Crystal team has fought with.
* I think something could be done with integrating Rubocop or some other linter (? idk what real Rubyists use) in order to begin solidifying the code culture. PEP8 is a huge factor of Python's success imo.
* Packaging. I'm not familiar with the modern Ruby stack, but in my limited dabbling, rake has done just fine. In Python, hearing about Packaging Issues is the new vogue from customers/people who have no idea what they're doing in the slightest. I've used pip/setup.py in the past, but funny enough I'm actually reading up on Hatch lately, which is the new hotness.
Anyhow, I don't think it's quite fair to throw this much shade at Python when Ruby hasn't really addressed any of the things that makes Python so popular. If Ruby is so much better, than it needs to do all those things at least as well if not better.
If anyone reading this is thinking “why does Windows even matter for development?” then congratulations because you’ve discovered you’re in a filter bubble.
Well, I'm programming on windows for about 6 months now, comming from using Linux for the last 5 years. I have to admit I was forced as my new notebook BIOS has a wrong VBT configuration and that makes the Linux kernel to not recognize my HDMI port.
And I can acomplish any other task a regular developer can do (and I was doing) programming in Java (with sdkman), using docker containers, git on the command line, Big Data tools (flink, iceberg, haddop, etc) and even some bash scripts (nothing too fancy).
The only things that bothers me are the CRLF x LF and sometimes the windows defender making the fans go crazy, but thats is a minimum and I can do some workarounds, the same way I did with bluetooth and audio on Linux.
I’ve only seen people program on windows or Macs professionally. Lots of HN people talk about developing on Linux desktop but I’ve never had a good experience with my hardware. Wether it’s an old MacBook Pro or a custom built PC, something like Bluetooth, WiFi, Ethernet, display issues, or the track pad just doesn’t work right.
I guess company laptops that run Linux have been vetted a little more.
I've been doing Ruby on Rails since the early 2.x days. (I dabbled with 1.x, but gave up to let it "age" a little.) For the first 5 years, I was on Linux full time, and it was great.
Then I moved to Mac, and it was almost as great. (The terminal situation and general integration of the command line is still more cohesive in Linux.)
For about the past 10 years, I've been at a standard Fortune 250 Windows-is-the-entire-world kind of place. I've been able to do my work on my personal Mac, but I've always made sure that I can do all of my Rails work on my corporate Windows laptop. There are times my code needs to access file locations and other applications inside the corporate firewall.
Obviously, people are correct that Ruby is not a "first-class" citizen on Windows, but RubyInstaller (https://rubyinstaller.org) has been a lifesaver. Not only does it "just work," and compile all the gems I've used, but it also includes a neat little script that addresses the common "corporate" practice of having to install custom SSL certificates so that IT can decode all traffic going through their firewall. (They install these certs directly into the Windows networking stack, but bundler doesn't use the stack.) The SSL bundle their script creates is also useful for use with Postgres database connections. You just need RubyInstaller, NodeJS, and a better terminal application (or maybe RubyMine), and you're GTG on Windows.
I've tried to use WSL, both version 1 and 2. If you need to support many Rails apps, and switch Ruby versions (with RVM or rbenv), that might be the way to go, but for just one (big) project, I prefer to stay inside the native environment. And even if I were tempted to use WSL, I'd rather just use an actual VM software like VMWare or OpenBox, and control the details of the virtualization myself. YMMV.
> I don't think it's quite fair to throw this much shade at Python when Ruby hasn't really addressed any of the things that makes Python so popular
My issue is that most companies using Python probably don't need the Python-only libraries. Aside from the fantasy AI point I originally mentioned, I think Python is the PHB's choice (like the mauve database) because that's what they've read in or heard in their circles, or because the first person building the webapp wants Django's built-in admin interface (which always becomes a problem later, like apps in Excel become problems later).
> Rubocop
Yes, it is fairly standard. And I dislike it like I dislike Black (Python's PEP8 dominatrix). Although Rubocop goes well beyond by giving you often helpful advice about optimization choices or unnecessary code. I like it for that, but I want to format in a more column-oriented way than Rubocop or Black allow (without config mods).
Black is a horror show to me. It's almost like it was designed to chew up as much vertical whitespace as possible. It's not as bad as PHP norms, but it really does like to turn pleasant tight blocks into twice as many lines and extra ( ) (out of necessity, since Python can't deal with linebreaks well).
Sure. Once all of online advertising, search (web, ecommerce, specialized sites, etc.), image editing, spell checking, recommendations (streaming, ecommerce, email, marketing, etc.) and a hundred other things cease to exist. Or more broadly once every large consumer facing company decides, for whatever reason, that it'd prefer to make significantly less money.
People talking about things without realizing what they are and where they're used usually indicates that their broader argument is going to be filled with equally many invalid assumptions and logical holes.
What percentage of companies (including startups) that use Python are using anything more than Django/Flask/sqlalchemy and the usual network modules?
I did not say that AI/ML is not useful. But I'm quite sure that some (many) of the companies using Python are not doing any of that - even if they say on their pitch deck that they are or will.
I'm not sure why you're focused on startups so much when a minority of engineers work at them. Python is also used heavily for data analytics, data science and data engineering which aren't AI/ML and likely much more common at startups.
Does Ruby still not allow type annotations in the same file as your code? Last time I checked, you had to put them in separate .rbs files. That’s a dealbreaker for me
You can with a third party library, Sorbet. It's not the nicest experience due to not being native but it works much better than you'd expect without being native.
If this comment is indicative of the general attitude of the Ruby / RoR community then I can’t exactly say that I’m jumping up and down to get involved. I feel like I’ve been transported 10-15 years back in time with this ridiculous negativity.
Django and RoR are much of a muchness. Ruby and Python are too, to a lesser extent. This whole thing stinks of narcissism of small differences and sour grapes. To imply that even most users of the most popular non-browser language in the world are partaking in ML hype is utterly absurd.
When you need to use nebulous words like “clumsy” to describe why you don’t something it’s inarguable that you’re unable to not take your own familiarly into account. I prefer Python, am certainly more familiar with it, and could truthfully say that I feel about Ruby the way that you obviously feel about Python. The difference is I’d never jump onto a Python post on Hacker News and try to pass these feelings off as fact in a way that puts down so many people for preferring a certain tool.
I have used both languages extensively, off and on for nearly 20 years. I've also used C, C++, Java, and built some small projects with Clojure and Elixir.
Of course people have differing sensibilities when it comes to aesthetics, but at a certain point equally observed options can be compared - with one being recognized as better.
I don't put down Python or Pythonistas because I dislike them; I just voiced my frustration that so many companies choose Python when I obviously believe there are better choices (particularly similar complexity/feature options like Ruby).
Clumsy, an incomplete comparison:
Python
OOP
Having to explicitly pass self.
Not having public/protected/private members. Ruby does, including convenience attribute reader/writer functions. And in Ruby you can still provide your own custom methods. In Python, you have to keep an internal _attrname and then have some set_attrname function if you want to provide special logic on your setter.
General recommendation to not use dunders, except that you should define dunders such as __init__ and __str__ for many classes. Ruby's class initializer is an optional method called... "initialize". (Principle of least surprise.) It also has a standard of to_something() methods which return the object in different formats, such as to_str, to_i, to_f, etc. More on this later.
Built-in functions:
sorted(), a past tense verb, doesn't "sorted" a list, it gives you a sorted copy of a list. Not to be confused with list.sort(), which also sorts but returns nothing and mutates list.
next(), which mutates the iterator you pass it. Most other built-ins do not mutate their arguments.
int(), float(), sorted(), next(), etc. all only work for certain argument types. The way to know is just to know. In Ruby, these would be object methods. And you could know if you could do foo.to_i (convert to int) just by asking "abc".respond_to?(:to_i).
Incidentally, Python's int("abcd") raises an exception, while int("1") works as expected. You can't ask the string "can you be converted to int?" Now maybe converting strings to ints is unwise in general, and that's fair. But the ergonomics here are... not good.
And regarding sorted() vs foo.sort(), in Ruby we have foo.sort (non-destructive, returning a sorted list), and foo.sort! (mutates in place). The ! indicates a more significant impact of the function compared to the non-bang version.
Elsewhere in the threads I illustrate list comprehension vs Ruby's collection methods and blocks.
Ternary operator:
Many languages: flag_set ? 1 : 0
Python: 1 if flag_set else 0
This is an if else. So written as an if else, it would be:
if flag_set
1
else
0
The Python ternary operator rearranges this logic.
But! In Python you can't do "1 if flag_set". Ironically, that's fine in Ruby.
Speaking of block return values... (from the imperative if/else above)...
Ruby:
x = if flag_set
1
else
0
end
You cannot do this in Python because conditional blocks do not return a value.
It is common in Ruby to say x = case(foo) ... and each match will have a value. The value of the expression in the case which matches is used to set x. In Python (now that you finally, as of 3.10 actually have a switch statement), you must repeat the x = expr for each match.
I will say I'm amazed that after so long of no switch statement in Python, they chose to build one with pattern matching reminiscent of Elixir's.
If I were to dig through my memory I could find more examples of Python oddities. My decision to merely compress it all into one word - clumsy - was to avoid getting into these details...
Python's pattern matching also isn't an expression, it's a statement and creates bindings that persist outside of the match block! This is a very strange way to do things but python for some reason is allergic to expressions.
After using languages with no statements, going back feels like a pointless restriction in expressiveness. You don't even need a ternary operator when blocks are expressions that can be used for assigning to variables.
Rails is quite the double-edged sword, too. Even putting aside the controversial close ties to DHH (which is a hell of an exception to be making), the dominating presence of Rails within the Ruby ecosystem means that any Ruby-adjacent project either becomes a Rails-adjacent project (and possibly gets absorbed into Rails itself) or fades into irrelevance. It makes expanding the language into non-web framework domains really challenging.
It appears the Elixir community has observed this pattern and has learned from it; time will tell whether that lovely language can build enough popularity to overcome its relative niche status.
(Context: Ruby is my primary programming language; I rotate clients fairly frequently; nobody doesn’t use Rails.)
Elixir is Erlang/BEAM VM, and Phoenix is a small (but awesome) thing in comparison.
Elixir has first class access to an incredibly rich (and battled-hardened) network/distributed ecosystem... if you need it. I know there are major voip companies who build on it, and of course Discord is famous for what they were able to do efficiently with it. These are all outside the realm of Phoenix.
That's not to say Phoenix isn't significant. I think it will definitely be a bridge that pulls Ruby (and the few willing Python) devs over to Elixir. It got me, and I built a successful project in it a few years ago.
IMO Ruby the language is a great enabler. The Ruby ecosystem is the real selling point.
It's the most productive ecosystem out there because of the sheer level of polish that exists within the Gem ecosystem and the Aspect Oriented Programming capabilities that make it so easy to plug and layer functionality from them.
Combine that with this relentless commitment to Developer Experience and it's a tremendous enabler. No other language and ecosystem that I know of enables so few people to accomplish so much, so fast, so well.
I recently started a new job that uses RoR and I'm blown away by how different it is. Coming from Java, I'm still always struggling to get basic things done but it's really cool how Rails has features for things that would otherwise require manual code.
I love Ruby. Sinatra was actually my entry into using Ruby and recently have been working on a side project with Rails 7.
I work with PHP and Laravel too and after working with Rails 7 for a bit Laravel is like a cheap imitation.
I also work with python a lot and I wouldn't want to do the web work in python as much as I would ruby but I would rather do the data crunching in python.
I love Ruby, and a substantial amount of our application is written in Ruby. However, there's a very significant portion that requires NodeJS, and to write it in Ruby would be an absolute ball of mud of kludginess and abstraction. I'm happy to write code in a time when I have great tools I can piece together appropriately to make great solutions.
I woudn't exactly call it consistent and design decisions are questionable. Even the article-mentioned
def foo(*)
bar(*)
end
is some needless nonsensical bloat, who on earth complained "oh, saying def foo(a) is so 90s, we need to have option to replace it with symbol used for multiplication or pointers in some cases!"
It's mediocre language that happened to have some then-popular web framework written in
imo, Ruby optimizes for flexibility over consistency in a way that is unpleasant and lends itself to unforced errors.
The Python standard library has never straight up failed on me in the way that Ruby has.
Ruby had buggy named-argument splatting, i.e. func(*kwargs), until 2.7, and even that was a half-realized implementation. It took something like 5 years to fix: https://bugs.ruby-lang.org/issues/11860
Been through it before, when I used ColdFusion. Not highly regarded these days, but among the options at the time, it was ridiculously fast to build applications in. To this day, even has some features missing in other languages/frameworks. However, things shift in the industry. In CF's case, it was the shift to open source and package managers, IMO. There's no value in casting stones at the use cases that undermine your worldview. (Personally I love Ruby, but if and when the time comes, I'll move on to whatever meets the needs of my employer/client)
when I was mostly doing ruby, with the occasional foray into python, I would have agreed with you. but having gotten a python day job and using it as my primary language for the past several years, I think there are features that python got right and ruby did not, as well as vice versa of course. the top one is the way the two languages handle modules and namespaces (ruby lets you reopen modules, which is nice, but python lets you easily see at the call site whether you are calling a function from an imported file, which is amazing for large projects), but I also miss introspectable doc strings, and syntactic support for type annotations (which are also introspectable at runtime!) when I'm writing ruby these days.
this would be close to making whitespace in Ruby significant, which would be unpleasant. Ruby already gives you plenty of options to write code without an 'end' keyword.
Annoying to use acronym "WASI" and assume that everyone knows what it means. Apparently it’s Web Assembly System Interface. But what does that mean? To quote from https://github.com/WebAssembly/WASI:
> The WebAssembly System Interface is not a monolithic standard system interface, but is instead a modular collection of standardized APIs. None of the APIs are required to be implemented to have a compliant runtime. Instead, host environments can choose which APIs make sense for their use cases.
Uhh… OK, I guess. So it’s a collection of APIs to allow Web Assembly programs to make system calls? Why not just say that?
JIT compilation is done lazily on a per basic block level (so you only JIT blocks you're about to run). It keeps track of statically known information for specific basic-blocks and specializes different versions of basic blocks based on this. So if you're coming from an if-statement checking the type of X, into a new basic block, then the JIT specializes the block based on the knowledge that X indeed has said type (so it can specialize operations or skip future checks).
If you're curious about how their YJIT, with it's lazy basic block versioning, works then I can highly recommend watching their presentation on it: https://www.youtube.com/watch?v=PFb5wNj2ztM
No, that is not per definition. While the JITing uses memory a JIT can remove unnecessary allocations from the JITed code and in theory reduce memory usage. But in practice you should expect higher memory use.
Depends what you are after and what you are constrained by.
Some people might be struggling with memory usage and may not see it as worth it, but for others who may have some extra RAM sitting around, it might come as a free perf increase.
In case you want to stay up to date with what is happening in Ruby world I am curating a free weekly newsletter at https://newsletter.shortruby.com (I took a two weeks vacation but will be back soon with new editions).
Love both languages. However, by the time I discovered Ruby, around 2010, I had already invested a lot of time in Python - and the Python ecosystem was already leaps and bounds ahead when it came to numerical and analysis-related libraries. But Ruby had an elegance to it and expressiveness which was a welcome change from Python and other commonly-used languages at the time. I think a lot of people had similar experiences but were already invested in a tool which came with a large collection of ready-made and tested add-ons.
Just some anecdata but I'm not seeing such dramatic improvements with YJIT, actually in my limited testing it's much slower...
Ruby 3.2.0, on a M1 MacBook Pro hitting a simple healthcheck route in a production Rails 6.1 app with wrk (`wrk -c8 -t8 -d30s http://localhost:3000/healthcheck`):
- 423 reqs/second with JIT disabled (using 229MB of RAM)
- 74 reqs/second running with `RUBYOPT="--yjit"` (using 385 MB of RAM)
340 comments
[ 2.5 ms ] story [ 277 ms ] threadhttps://bugs.ruby-lang.org/issues/19104
they are using memoization to defeat regular expression denial of service (ReDoS)
It is mentioned only briefly in Cox's article on regex matching in the wild. Look for the word "bitstate": https://swtch.com/~rsc/regexp/regexp3.html
I didn't know Perl had implemented this trick too.
The paper[1] cited in the Ruby bug ticket was published very recently. When I first read the Ruby bug ticket, I immediately wondered how they sidestepped the memory use problem. The paper's abstract seems to suggest there is some technique for doing so, as it rebuffs the idea of doing "full" memoization. Alas, I do not have access the paper. (Which is fucking ridiculous.)
[1]: https://ieeexplore.ieee.org/abstract/document/9519427
> while caching is used to accelerate backtracking in Perl and a rare path in RE2.
Although I wouldn't call it rare. It's probably used every time one wants capturing groups and the regex isn't one pass (pretty common) and the input isn't too big (like, say, a line in a log file).
The actual part of the paper that contains the key contribution (memoization but with less space) is fairly dense and I don't have the time right now to look more closely. But it looks like it might be applicable to RE2, Go's regexp package and Rust's regex crate. All three already use already use bounded backtracking (i.e., "full caching"), but if the space usage could be cut back, then it would increase the opportunity of using the bounded backtracker. Namely, all three put a bound on `size(regex) * size(haystack)`. If the search needs something bigger than that bound, then the backtracker isn't used. But if memory usage were instead much less than `size(regex) * size(haystack)`, then the backtracker could be used more often. (Which is a good thing since it's generally faster than a full Thompson NFA simulation.)
Doesn't Ruby allow scientific notation for floats?
- 1.4
- -1.4
- .4
- -.4
- 1.
- -1.
... plus exponents, also you don't need a decimal point if there's an exponent
Won't Ruby parse a string into a float? I would just use that and check for an error unless your requirements are different.
[1]: https://sorbet.org
When we tested, there was barely an experimental type checker for RBS, that was 1 year ago.
Overall, we tried, had to bail out and stick to YARD. Horrible experience.
edit: thank you to everyone involved
https://www.ruby-lang.org/en/news/2022/12/25/ruby-3-2-0-rele...
you deserve more publicity, really lovely :)
It's disappointing that there are so many more jobs for another popular language - one that lacks the elegance and consistency but which has a larger ecosystem.
As far as I know, the only well known reason for a company to choose Ruby is if they want Rails (and obviously if the founding team already knows/likes Ruby). But that other language also has a popular (and comparatively clumsy) web framework plus well known modules for all the fantasy capabilities that startups dream of... you know, the AI/ML "not sure how we will use it but we know it will be great, and it's good for marketing".
Sadly, I don't expect this situation to reverse in the future. Maybe like blockchain, once the AI/ML fantasy hype dies down the other comparatively-unpleasant language will lose general appeal and Ruby will gain more attention.
Edit - also, the domain squatters "rubylang.org" should lose their domain. There is no legitimate excuse for having this domain which redirects to a general garbage site.
> one that lacks the elegance and consistency
upvoted for perfectly concise description of that language.
it is even more sad knowing that high quality alternatives for the most popular libraries exist, but inertia is simply too high.
@work I've tried to introduce Ruby to my colleagues that are very bad at programming, but good at science. They ditched it with reasons like "I don't like it" or "it's too slow" without even measuring (it is not! Shopify would have died by now). I'm still using it without them knowing and it's the reason why I'm 10x faster than everybody else to build solutions.
The other language it's the only one they "learned" at uni and keep using it for everything, even when it's the worst possible choice, management doesn't care and doesn't know the difference.
software engineering is still not engineering, unfortunately.
Ruby today is slow as hell, but not as much as slower than other slow as hell languages as Ruby used to be.
After all, sharding message distribution via federation (even if you hide the federation behind a veneer of a global userid -> shard mapping) was a well understood long before Twitter even launched (e-mail... reflectors...), so it was a rather embarrassing architectural decision to not even try to account for it. Heck, I co-founded a webmail provider in '99, and one of the first things we did was implement ways to map user ids to a distributed set of backends and support for migrating accounts between backends, because we knew it'd be necessary to be able to shard smtp servers, frontends, and storage separately. That wasn't in Ruby, but the architectural pattern is so obvious.
The language change may or may not have made sense for them at the time (after all Ruby was much slower then, and they by then had the size where a rewrite of core parts to cut hosting costs might have been worth it), but that they blamed their architectural failures on Rails was a cheap shot.
Jruby a little faster than CRuby (it used to be more significantly faster, but CRuby has seen more recent performance increase); TruffleRuby is, OTOH, not slow like other implementations.
> Normally the "ruby is slow" argument, is based on not being involved with ruby and solving real problems with it.
Ruby is abstractly my preferred language, and I’ve done a fair amount in it, though I don't get to use it as much in anger because of issues other than its speed (ending up using another slow language as my main day to day.)
> Some people will just LOL this argument even harder if you add development time and code maintenance costs on that equation.
That’s just equivocation; time and cost to market is an orthogonal concern to execution speed, not a component of it; yes, Ruby has a decent code-writing experience, especially for small systems.
Probably you meant rails here. I don't see why ruby should be a problem for something not small, moreover, you should first define what a small system is, specially if you count the LOC of all the gems that you use..
Ruby is not "pretty fast". The hardware you run it on is insanely, mind bogglingly, out of this world fast and so people don't notice the way that they used to.
...which is fine, you don't always need to be fast. Just be wary of misattribution.
Truffleruby is "A high performance implementation of the Ruby programming language, built on GraalVM." If you prefer there is even a rust based ruby https://github.com/artichoke/artichoke
again, IMO, the microbenchmark, doesn't matter. What matters is the problem domain, whole stack and the whole "speed", including development, deployment and etc, and for some domains, ruby is the best and fast choice.
It's quiet fun to play around with actually, to see all your cores being utilized.
Don't ask me...
> Ruby in science is the path of most resistance; if your work isn't already hard enough
It actually isn't that hard, honestly.
Very few people do cutting edge work that requires analyzing massive amounts of data and, from my experience, other languages are not much better.
They still rely on C (or Rust) bindings, because they aren't adequate per se for the task.
> That's because everyone is using Python
Yep, the aforementioned inertia.
But, IMO, as a programming languages nerd, some syntax are worse than others and I have to review many Python programs that conceptually read like someone speaking a foreign language without knowing the rules, like "I go make shoppings". That code wasn't "created" but simply copy/pasted from somewhere else and then adapted because some concepts don't require understanding, just tinkering.
Python it's not easier than Ruby, shooting yourself in the foot with Python it's easier than in Ruby and yet, here we are.
At least in the diatribe C vs Rust, C is actually simpler than Rust as a language and programmers have to learn fewer concepts, even though Rust is better as a language/ecosystem overall.
> Everyone uses English, so you have to too
That's exactly the point, the most spoken language in the World is English spoken by non native speakers. Like me. It's not British English or American English (in Europe is Russian, anyway, and Chinese and Spanish would like to have a word with you).
So it is people's Esperanto, which is kinda of an abomination linguistically, but language evolve naturally it does not need a compiler or an interpreter to work.
When I am abroad for holidays or conferences, I can perfectly understand what people mean when they speak "Engrish", native speakers often don't.
A recent submission about it
https://news.ycombinator.com/item?id=25784683
But in programming the concepts are the same in every language, so it's not like learning Finnish if you are Egyptian, it's more like learning to ride a motorbike if you can ride a bicycle.
People learn Pandas and Numpy and Scikit-learn, not Python, when I learned how they worked porting the examples to Axon[1] wasn't hard. I managed to do it with the help of a colleague whose versed in learning programming and he thought Axon was more readable than Python. But then again, people usually think they know X better, feel more confident in X and will keep making the same mistakes over and over, because they don't know what they don't know and their salary do not depend on it. They have people like us fixing their code. Their salary depend on writing "I know X" on their CV, which usually is just not entirely true.
Ruby just got out of fashion, but it isn't inferior to any other language out there and its ecosystem is completely fine.
Reminder: TruffleRuby exists.
[1] https://github.com/elixir-nx/axon
edit: formatting
Adoption-wise Ruby is a new Perl. Such a shame really, Ruby is one of the best scripting languages yet available, if Linux distributions had it by default it would dominate over py and shell-scripts.
It's a shame that this example will only be understood by the people who already agree with arguments against Python; but you really made my day with it.
in no particular order, on top of my mind (there are many more):
- mixed environments when you can't compartmentalize Python in a container. Python package management is one of the best examples of "poor implementation"
- mixed environments, when both Python 2.x and 3.x are present. Migration to Python 3.x is the textbook example of "badly executed". And we are still not entirely there 10 years after.
- prototyping web apps, in the same time spent configuring Python venv, you have a perfectly functioning Ruby prototype
- writing web apps, in the same time you understand how to make a custom sql query in Django, you're already selling your first product in Ruby and the website won't be ugly as hell by default. Rails is the killer app, nobody can deny it.
My biggest gripe with Python is that many times when I have to deploy Python, I discover an issue and ask the author(s), I'm back to "but It works on my computer" times, like when I started, in the 90s of previous century.
Yes, Python is used to write beautiful things such as youtube-dl and Sublime Text (porting Sublime to Python 3 is one of the reasons why Sublime is almost dead). However, given the fact that in Sublime plugins are written in Python, people flocked to (even!) Atom, because they could use other languages, not inherently better, but with less issues connected to the language used.
I lost count of how many times Sublime died on me and stopped working spouting Python errors that I had no time nor will to fix.
Disclaimer: I am a paying customer of Sublime 2 and 3.
Edit: lots of Pythonists triggered for no reason apparently. Don't take it personally, if you have counter opinions, express them. Downvoting is not an opinion, it's a passive aggressive way to show disagreement, which frankly is the reason why we're still stuck with Python. I don't mind an honest discussion and people disagreeing with me, it's why I am here after all.
worst possible choice VS not worst
> FWIW I haven't even seen Python 2 code in about 6 years.
there are a lot of scripts lurking around in corporate environments all over the World
6 years is brand new to them
There are a lot of environments "certified" to work only on, let's say, Redhat 5 <= 5.2
I can honestly say with complete confidence that I’d feel this way regardless of what language you were talking about.
In addition to this though, as someone that writes Python / Django professionally and has done so for some time, my familiarity with the language gives me the necessarily insight to see where your experience is limited. I’ve seen a few inarguable factual inaccuracies (i.e. not based on opinion) in what you’ve said in a few comments. It seems obvious that when you engage with Python and Django you aren’t doing so all that willingly. But honestly your strength in your convictions puts me off getting into a back and forth with you to reach a shared understanding. The confidence with which you’re writing feels a bit misplaced.
Your overuse of hyperbole makes it hard to tell what you actually believe and what you’d genuinely argue for in a real-life professional context rather than behind a screen name on an Internet forum, so even if I wanted to engage in a back and forth I wouldn’t even know where to meet you.
This is a classic example of the loudest and most impassioned voices framing themselves as winning because people just don’t want to engage.
This is all to say before writing off downvoters are upset people on “the other team” which are lesser than you, consider the possibility that you’re probably throwing your weight around a bit too much and are creating an environment that’s generally unpleasant. I’ve enjoyed the tech community largely moving away from the “us vs them” mentality. Truth be told, none of this shit matters enough to warrant that sort of mentality. I feel like I’ve stepped back in time reading your comments. Not only are they unenjoyable to read, but I am not an iota more enlightened about the comparative benefits of Ruby vs Python. So I ask you…what’s actually your intention in commenting in the first place? The truthful answer to that question is why I’ll continue to downvote.
I'm simply Italian and english is not my native language, so I use the most simple versions of it, resulting in what you call "vetriolic"
Have you ever heard some english native speaker, especially Americans, trying to speak Italian?
they all sound like Don Vito Corleone. Should I assume they work for the mob?
So, basically, you let your prejudice guide your actions.
If you prefer possiamo parlare in Italiano, la mia lingua madre, che conosco molto bene e grazie alla quale posso esprimermi in maniera estremamente più formale. In Italiano, per esempio, le avrei dato del Lei, non del tu, che ritengo molto poco professionale fra persone che non si conoscono e stanno sostenendo una conversazione in pubblico. Nella mia lingua è un segno di reciproco rispetto.
Spero Lei capisca che il mondo parla molto poco inglese e che quello che a Lei sembra "al vetriolo" certifica solamente una sua mancanza di empatia nei confronti delle altrui culture.
Cordiali saluti.
> This is all to say before writing off downvoters are upset people on “the other team”
I have no "team" I just have 26 years of experience in the field and Python deployment is way worse than deploying PHP apps in 1995. It's hyperbolic, I agree, but it's also not far from the truth. PHP was a simple FTP all the files on some host, Python projects most of the time miss or have incomplete requirements.txt, you have to reverse engineer dependencies, there are N distributions so you have something developed on Windows using Conda but the deployment server is Debian stable with pip etc. etc.
I don't think I'm saying something people never faced, but if that is the case, well, It means I am the only one and that is good news!
Add to that that, not to their fault, scientist have been sold the lie that Python "is easy" or "is the language for scientists" (I still remember in 1995 at uni when as a CS student I was working together with the Biology department on DNA sequencing and Perl was all the rage thanks to "Beginning Perl for bioinformatics" book, how much things can change in a couple of decades...)
Python is not so easy and coding something that runs in production is not the same thing of running experiments in a lab once, where "it just works" is enough.
Also, language inconsistencies and a patchwork design, led to very confusing results, like C++, without the extreme power of C++.
Like Perl, without the extremely good bits of Perl.
I do not write Python as my daily job and I do not write Ruby since 2015.
Ruby is simply a better language than Python and Python 2, as a language, was better than the first 5-6 years of Python 3, because it was really a simple language where there was only one way to do stuff.
Python 3 is simply another language, that solved very few of the issues with packaging and dependency management it inherited, broke backwards compatibility and for a decade coexisted with Python2 making everything a lot more problematic than it should have been.
Is that a language's fault? Only marginally, but I think that the way transitions are handled is one of those things that tell you a lot about how much you can trust a tool. Python failed miserably.
While, for example, PHP in the same time frame it took to migrate Python from 2 to 3 solved a lot of its problems to the point that, if it was preinstalled, I would much prefer it to Python.
Meanwhile Ruby, the real argument of this submission, arrived at version 3.2 with a new Jit that improves performance 40% in benchmarks. Not bad for a "slow language".
The only thing IMO that saved Python from oblivion is that Google invested a lot of money on it.
Briefly about the ecosystem: I've recently started using Polars in Rust and Elixir and it's a 100% replacement with better API and performance [1] than Pandas. It has also Python and Ruby bindings. Why people do not adopt it? Beca...
It is what it is.
The problem for Dlang is that it never reached the popularity Ruby did.
Airbnb, Github, Shopify, Gitlab, old Twitter (and many, many others) are all written entirely in Ruby on Rails.
... and decent first party docs, actual code modules rather than “execute every source file in the global namespace”, a first party Windows build, etc., etc., etc.
If the Ruby community can't acknowledge the real things holding it back compared to other available options, well, that makes it that much harder to catch up.
I don't think the execution model you mention, which results in the absurdity of C style transitive includes polluting the global namespace, will ever be changed though.
There is a proposal at https://bugs.ruby-lang.org/issues/19024 to change this but, as you can see from the comments, it’s a bit tricky to get right while preserving backwards compatibility. (Whether that conversation makes you more or less optimistic about the chances of it ever being changed is up to you.)
Searching for a mismatched/missing _end_ is preferable to having a line or block get accidentally unindented and end up still "working" (running) while producing very confusing results.
Moving blocks of code in Python requires great care, especially since the editor cannot reasonably guess which scope level the paste should go into.
Also, the lack of an _end_ or bracket as with other languages means the editor cannot visually assist with identifying block boundaries. To be fair though, my vim-memory of using % to bounce between start/end brackets doesn't work in Ruby because of the begin/end words instead of matched symbols :(. However, RubyMine does show the beginning of the block as an unobtrusive popup at the top of the window when your cursor is on the _end_ keyword. That's super handy when there are several blocks closing in succession.
Even when I was new to python, the only problem I ever really had with this is when I mess up and copy the first line starting at the the first nonwhitespace character so the relative indentation is wrong. When do you ever move a block and not know what scope you want it in? At most, with really long blocks, you fold the more deeply nested blocks before pasting.
> Also, the lack of an _end_ or bracket as with other languages means the editor cannot visually assist with identifying block boundaries.
No, it doesn’t. In practice, editors usually don’t, but they recognize the beginning and ending of blocks, and use it for folding, which means they could insert phantom labels (as editors often use for blame information, inferred type signatures, etc.) to provide informatiom about the block ending (and even align them to indicate the indentation level corresponding to each ending block.)
An existing line of text is not necessary for editors to provide feedback.
Put "runtime macros/matchit.vim" into your .vimrc. Or for even better support add the matchup plugin. https://github.com/andymass/vim-matchup
matchit/matchup extends this to language specific delimiter words. This animation https://github.com/andymass/vim-matchup#screenshot shows how you can iterate over multiple sequences like if/elsif/else/endif.
The issue with Ruby specifically (which doesn't exist in other common languages that have bracket- or keyword-delimited blocks) is that non-keywords can start blocks. So it's difficult for an editor to determine the likely matches, and it's even harder for a human. That's my vague recollection of the problem that I ran into numerous times, though it was about a decade ago.
This suprises me. I've missed `end`s before as much as anyone, but I guess as an OCD reformatter (prettier, IntelliJ, rubocop, etc.), they show up VERY OBVIOUSLY and right quick. They've never even been an itch, much less "pain".
> Ruby ... its combined attributes of brevity, expressive power, and feature consistency.
> [Python] lacks the elegance and consistency
First I would argue Python is very consistent in its design, it aims to only have one obvious way to do things and so it's easy to guess how apis will work. It also aims for explicitness, which makes code very easy to follow and reason about.
Secondly on "brevity" and "expressiveness", I don't really see them as an attribute that make a language "better". Sure for experienced developers who like a personal game of code golf (don't we all at times!) those are attributes can can make coding more "fun". But that doesn't necessarily translate to code that is ideal when working as part of a team, or code that is easy to follow when a new developer starts on an existing codebase.
Ultimately I think that's why Python has gained more traction than Ruby, it's an "easer" language to follow and start with. Ruby is probably a more fun and intellectually stimulating language to work with though.
It's slower than Ruby, has worse package management and less consistent syntax but if you want to use Tensorflow, PyTorch, etc..., it's the default.
From my perspective, python was just starting to gain real popularity in the mid 2000s, more than half a decade after Google was founded...
I first started using Python slightly after that time and for years it was a pretty niche language that relatively few people used, especially compared to the other 'P' languages, Perl and PHP. I'd estimate 2001-2002 as when it would say it started to become a 'normal' language and I wouldn't say it really started taking off until around 2005ish.
So 4 years after Google.
Which made my point to the parent.
And apparently everyone's been living under a rock because Python didn't become truly huge until maybe 10 years ago.
When people decided what language to use, it was very much a "X uses this, maybe we should" kind of decision. Still is for the most part.
Zope was a Python project from the late 90s, and had quite a bit of attention and traction in the early cms/publishing days. That brought Python attention, and certainly gave it some mindshare in the late 90s.
Two years later the project had become an integral part of some critical business processes, and IT had to take it on. They decided to rewrite it in C#. I left the company at that point, and almost a decade later I got a call from a former coworker asking for help to fix the system. It turns out it was basically unchanged from when I left, and the address of the Exchange server that it relied on for auth had changed.
Django was released in 2005 and RoR in 2004. I suspect my journey was similar around then (late 2005), I had used PHP, classic ASP and a little Perl. I was looking for something better, read the tutorials for both Django and RoR. Had a look at what desktop GUI toolkits were available for both Ruby and Python (I wanted to lean one new language), Python had a few more options and so went with Python and Django.
At the same time Python was gaining significant traction in the scientific community with NumPy (2006/1995) and SciPy (2001). Ruby I don't believe had an answer to that back then. I was vaguely aware of that and it somewhat influenced my decision.
Ultimately it was the two pronged (web + scientific) development of the ecosystem that pushed Python ahead of Ruby.
As much as I liked RoR for its scaffolding and easiness of bootstrapping new CRUD projects, over time with larger codebases and teams it just starts to be a mess. Ruby programmers love the terseness of the language and write some of the most ungrokable code I've encountered (second only to some Scala codebases I worked with). That and the magic of autoloading modules which then could introduce a DSL, the usage of mixins that are hard to trace where they are loaded from, and a lot of other magic features that are extremely opaque to parse through and debug is, ultimately, what made me abandon Ruby and RoR.
It has its uses but I've yet to see a decent legacy RoR codebase without these pitfalls of magic, after so many years professionally working with code I prefer any language environment that is explicit, Ruby is not explicit.
Perl!
I think Silicone Valley is, uh, another type of valley.
When Ruby and Rails started to make an appearance in European circles, around 2007, it hardly mattered when Python was already around.
Any reference/numbers to back this up ? Just genuinely curious about this.
It doesn't really matter though, both languages are used typically for scripting. But just shows it's not really about the "language", it's about the ecosystem.
https://github.com/kostya/benchmarks
Bearing in mind these are probably not even using YJIT, which makes Ruby considerably faster in some scenarios.
That’s like saying that Dodge Neon is Slower than Mazda Miata.
Both are bottom of the barrel compared to any compiled language.
Scripting languages and compiled languages are used for different things.
And you're right, both are slow as hell and speed doesn't really matter for scripting, but when all else is equal, it matters, a lil...
Also JS is still too slow for most things compiled languages are used for.
Which is actually a great analogy for Ruby vs Python!
I know. :^)
Both are shit compared to better cars, though.
I never understood how this can be considered consistent at all, and those IMHO language design warts made me look into Ruby at the time.
Has this improved since? I know print was changed in Python3 to make it not-special.
The justification for len() is thinner: Guido van Rossum thinks it looks better, and it enforces a consistent name with a consistent meaning (you don't get length methods with different names, or with the right name but strange behavior). Under the hood it just calls obj.__len__(), so it's only the notation that's not OOP.
There are no multi-line lambdas because nobody could come up with an indentation-based syntax for them that Guido van Rossum was happy with.
In short: none of them improved, all of them have reasons, some of those reasons are bad.
Sure, multi line lambdas might be nice, but equally you can define functions wherever you need them so it’s not really all that different.
fwiw, Ruby does the same thing, but using the Enumerable mixin rather than a free floating function.
> I’d argue that is consistent.
I don’t understand this argument. It’s convenient and more efficient to write, yes. But how is it more consistent to have two different calling conventions?
The claim that there’s one way to do something irks me as well. There’s one way to find the length of something, but that introduces two ways of querying an object. It’s a good guiding principle, but when people use it to make stronger claims, it ends up superficial.
Python's len works by calling the __len__ method, which must be added to every class that needs a len function.
Since you're already defining a method with a standard name on every class that needs it, Ruby just has you call that method directly as opposed to the absurdity of intentionally obfuscating the method name with underscores so that people use a global helper function instead.
Even C++, with all its warts and its 1980s design got this right in the std lib with the size method.
Honestly, I find some of these defenses of Python quite humorous.
`sorted`, `list`, `set`, are more interesting cases where they all work with the underlying __iter__ protocol. You don't also want to add X.sorted(), X.as_list(), X.as_set() etc too. Again, you could have X.as_iterable() to implement these, or you could mixin sorted, which will call the __iter__ function. But honestly, it's really neither here nor there.
For the full avoidance of doubt - I'm not arguing for these other "memes" and, in particular, "There is only one way to do it" has never made that much sense to me.
I am arguing that Pythons `sorted` api is reasonable, consistent and not worth worrying about.
I don't think that's avoidable. Mistakes made early on have a habit of compounding over time and calcification makes it harder and harder to deal with them decisively and in a non-breaking way. Python made a couple of bad decisions but on the whole the language came out relatively unscathed, most of the original design constraints are still satisfied. As opposed to say PHP or Java which ended up very far removed from where they started out.
Case in point: Python's GIL must have seemed like a good idea at the time, a quick fix for an urgent problem. And now that quick fix is the albatross that we can't seem to get rid of.
I think it's definitely worth considering what could / can be done better, but people often argue deeply about things that aren't really a massive deal. You've pointed out examples that are much more interesting than "should __len__() have been called len()".
Certainly makes one appreciate Guido's stewardship in keeping the language fairly clean but applicable to large number of use cases for so long!
res = (1..10).select { |x| x != 5 }.map { |x| x ** 2 }
With filter_map:
res = (1..10).filter_map { |x| x ** 2 if x != 5 }
In both cases, I think the Ruby solution is more readable.
Python list comprehensions invert the subject (data) and the verb (action). You see what will be done before you see what the subject is. I would argue that showing the subject first allows easier code review as you know immediately what you are working with.
But beyond that, the first Ruby example tells you in English what is happening. "take this range", "select a subset", then "map some actions to the elements".
And the filter_map abbreviation does the same, telling you "take this range, filter it and perform an operation on the remaining elements".
Python tells you nothing... and what it does say is in awkward order.
As functional and data-oriented programming is gaining in popularity (for good reason), adopting some functional practices in Ruby is a pleasant experience. Doing the same in Python exposes more of these... irregularities.
Edit - I always forget how to format symbols in these comments!
Nope.
It uses what people already know: the for something in somethings syntax of the for loop, and the if syntax. Also it's nice that this works in dictionaries, generators and lists.
It also has the same narrative flow of Haskell's list comprehensions, which I think come from set theory:
As for your Ruby examples: I think you could argue that the filter_map version is very readable, but not necessarily more so, but the select one looks pretty painful.The select does two passes, which makes it quite inefficient. One does not even need filter_map, since the example is essentially a reduce operation.
This works in ruby 2.5.1. Probably works in 1.9 and mruby as well.I disagree and I’ve used both professionally for about the same amount of code.
I do a lot of contract work and chatted with a ton of folks ranging from beginners to veterans. A lot of them (well more than half) avoid list compressions, especially when working with teams because it's such a mixed bag of either being able to instantly understand them or it requires more effort. Personally I don't use them in my code (for both reasons).
Both Ruby solutions are much more clear to me even though I have no functional programming background. I have no preference towards functional styles either, I would say it's the opposite. I struggled with Elixir long enough that I stopped using it.
Coming from a point of zero knowledge of the codebase, I picked Flask. I picked the cli.py module in Flask. And what do I find?
https://github.com/pallets/flask/blob/main/src/flask/cli.py#...
https://github.com/pallets/flask/blob/main/src/flask/cli.py#...
https://github.com/pallets/flask/blob/main/src/flask/cli.py#...
https://github.com/pallets/flask/blob/main/src/flask/cli.py#...
https://github.com/pallets/flask/blob/main/src/flask/cli.py#...
https://github.com/pallets/flask/blob/main/src/flask/cli.py#...
https://github.com/pallets/flask/blob/main/src/flask/cli.py#...
https://github.com/pallets/flask/blob/main/src/flask/cli.py#...
The keyword "for" occurs twice as often in comprehensions and generator expressions as it does in "typical loop iterations!"
I always have to stare at list comprehensions very closely to understand operation being done. The source of the data is in the middle, where it should logically come first. The filter is at the end, where logically it should come after the source. The mapping is at the start, where logically it should come at the end.
I find the monadic, additive style of Ruby much easier to understand:
IMO it's more composable. What if you want to exclude even numbers from the result? Just add another filter: Incrementally building up a streaming computation this way is much more useful to me than a list comprehension.For example, you can add a lazy to the stream to avoid performing all the operations eagerly, and now you have a way to process sequences without blowing out your memory.
By the Python developers and its wider community. As Python doesn't have anonymous function blocks in the same way as Ruby (only lambda expressions), tutorials, lessons and the Python docs steer users toward list comprehensions instead.
I'm not saying the ruby syntax is not elegant (it is), I'm saying in Python list comprehensions are recommended over filter/map functions.
On the composable front, personally I prefer to breaks these down into smaller chunks with descriptive variable names rather than chaining.
Python also has the sister "generator" (() rather than []) syntax which also ensures it remains efficient as it pipelines the whole sequence of generators. (Lazily rather than eagerly as you say)
Once you start adding more "and" to the if-statement in the list comprehension, it becomes a mess. Breaking them down to smaller chunks is required because comprehensions are messy. You are doing smaller chunks due to a shortcoming of comprehensions. Chaining is nice option to have, especially when the chained functions are straight forward.
> By who?
> By the Python developers and its wider community.
> You're effectively saying something like: Canadians prefer Canada. What about the rest of the world?
They're actually saying that Python developers prefer one particular way of doing something rather than a different particular way of doing the same thing. You're suggesting that they're saying Python developers (Canadians) prefer Python (Canada).
I don't mean to speak against your broader points, just that this specific call out is mistaken.
Looking at it makes me miss Perl oneliners
I also think that map and filter style computations can be much more powerful, there are quite a few things other than just map and filter, like count, take, skip, find, flatten, fold, map-while and quite a few more!
In python I guess you are supposed to use a standard for loop to do these things instead.
The = binding is the chaining/composition tool of choice. This is why generator expressions are so important, relative to list and dict comprehensions. They both defer the allocation of space for intermediate values and allow the space to be bounded no matter what the input length is.
Often the “reduce” step, or even more commonly, realizing the side effects of such a generator composed of generators is a simple for loop—because that’s the most readable way to walk through it.
Ruby code has no parenthese.
In essence, I don't think it has anything to do with elegance, syntax, or "easiness". It's more about timing + origin + corporate adoption:
* Python was created in Europe, Ruby was created in Japan - when Ruby gained more recognition in English-speaking world (~2004), Python has already been present and used worldwide for a decade
* Ruby was created as a personal, hobby project; Python was created while Guido worked in research institutions, and it helped Python gain recognition in academia environment
* Guido joined Google in 2005, boosting the adoption of Python; Ruby has never gained such a large corporate backing
Eventually I believe it was the combination of the latter 2 that pushed Python to top spot in popularity - scientists all over the world were familiar with Python, and with the rise of Data Science/ML (with Google being one of the main forces behind it), it became the most obvious choice for the new tools.
[0] https://www.notonlycode.org/why-python-has-won/
As a data point, I remember interviewing for an internship in a research institution doing some work on medical images around 2002/2003 and the supervisor telling me that Python was the lingua franca in this domain (from a research and POC development perspective).
Trainings for getting Python skills were a common offering.
GvR’s background probably helped spread the word and thus get feedback, but as often Python’s overnight success was the result of years of work.
So we got at least two major contributions from the CWI. One is Python and the other one is the game of Hack. :)
The father of A*:
https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
ALGOL 60 and ALGOL 68
First node on the Internet outside of the USA
Python
Various contributions to the improvement of encryption.
CWI has a long, long history of quietly contributing to all kinds of stuff the world over and has a pretty good reputation.
https://en.wikipedia.org/wiki/ALGOL_60
Or at least they are similar enough that one pulled ahead and subsumed the other. Like a twin eating his brother in the womb. Maybe it could have gone the other way and we would have ended up pretty much in the same place. Or maybe it is a case of worse is better. But not that much worse/better frankly and here we are. Salivating over rust. ;)
I agree with this point. I learned python years before I learned Ruby and I found them to be very similar. Ultimately I dropped ruby because I didn't care much for the syntax and I like whitespace.
Ruby got popular coz Rails could get barely code-literate graduate to write CRUD app and so it was cheap (famous 15 minutes to blog tutorial) for companies.
JS got popular coz, well you ain't got fucking choice on frontend and having your then-frontend JS/HTML/CSS designer be able to also do backend is, well, again, easy and cheap.
There is clear pattern here...
"Ruby got popular coz Rails could get barely code-literate graduate to write CRUD app and so it was cheap (famous 15 minutes to blog tutorial) for companies."
That's not what happened, instead Ruby got popular with advanced web developers working in Java who saw that Rails was had better answers than J2EE. If you were barely code-literate graduate you wouldn't recognize that Rails was offering new unique ways doing things.
The 15 minute blog tutorial wasn't really indicative of what Rails was like, just a small sample about how it was different.
It was an advanced tool for advanced users with a long learning curve that eventually paid off in better productivity.
I was not "advanced" at web development in 2006, but this is exactly what got me to try Ruby. Previously I had been reasonably happy with JSP and Java Servlets, but this Rails thing promised a better way. And it turned out for most of my needs, it was much better.
Also, the Rails Depot book was excellent, even back in the 1.x days (IIRC). It covered enough that you could build a fully working app with sessions, auth, crud, and reasonably abstracted layouts/views. Oh, and because Ruby was "simple", you honestly could start with that Rails book without knowing Ruby.
We did Rails one decade earlier with our own version of AOLServer.
The very reason we went to .NET (as beta testers during its availability only to MSFT partners) was because we were fed up having to rewrite TCL into C due to performance issues.
All the Active Record stuff was already something that AOLServer introduced, and we had an improved approach on our product.
The founders of that company went on to create OutSystems based on our learnings.
IIRC, a bigger reason for Node's popularity (at least at the very beginning of its popularity) was the fact that it had event-based I/O, which let a single process handle a lot more in-flight requests than Ruby (where the concurrency model was to spin up a bunch of processes and multiplex across them with nginx or similar).
"Why Threads Are A Bad Idea (for most purposes)"
https://web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf
I work on multithreaded software and I get 31,516,776 synchronizations per second with a lock free algorithm and 12 threads and 31,565,052 on the lock benchmark.
When the threads are increased to 100 (contention) the lock benchmark does 3,419,271 requests per second whereas the lock free algorithm does 19,926,428 so the contention hurts them both but the lock free benchmark scales far better.
Threads aren't bad. The domain is not easy.
In terms of pre installed options, especially on older systems, Python is the best choice for integrating and extending systems.
Google used Python very early, but other languages became more prominent in 2005, culminating in the creation of Go, after which GvR left.
Indeed people talked a lot about Google "supporting" Python, but the support was pretty minimal (50% job for GvR, where you cannot really do much).
Python has way better marketing though the PSF though. They understood that you can create a circus around the language that is completely removed from engineering, fundamentals and actual core development. If Ruby had been as shameless, it might be #1 today.
Perl was everywhere (on Linux/Unix). Then Python came along an offered enough net benefit over Perl that it really started to displace it, and became the defacto scripting language that you would reach for when creating programs on Linux/Unix.
Ruby has some niceties over python, but doesn't provide enough of a net benefit over it for that same kind of displacement to happen.
This, plus what other commentors have noted regarding Pythons early developments in academia, have had multiplying effects on adoption.
The alternatives were C, C++, some "academic" language like Lisp (which I wish had really broken into commerce more), Prolog etc., and eventually Java. Python was at such a higher level that it definitely made more sense as a first language for many people... especially since it was capable enough to be more than just a first language.
Today’s landscape is better but also very different. And when looking up how to do certain things in Python, Stackoverflow will show you a multitude of options.
The problem for me is that I dislike most of them.
Agreed. It was a smaller language then, but it's never been as expressive as Ruby.
Python was just clear to read.
Ruby looked a bit cleverer but was not so simple. Coming from working on a large C++ code base, I decided Python was the one to do next. Simplicity, clarity and one obvious way to do things as a philosophy.
Someone new to Ruby will be WTF is the ! for?
Every Ruby tutorial explains that an exclamation mark means in-place, and this convention is consistent across Ruby libraries, unlike Python.
In the Python case, `list.sort()` operates on the object, so you can kind of expect it to do mutation (but there's no convention / guarantee). Though it only makes sense as a function that the list object itself implements.
`sorted` is a general function that gives you a sorted list from any iterable, and because working with iterables is such a common thing in software, Python has a bunch of standard functions like that. It's nice because you learn them once and they apply absolutely everywhere.
Ultimately you learn the behaviours of a language and they become second nature. I find both Ruby and Python very clean and easy to read.
the meaning is the same high level: it has side effects, being it a destructive update, an in place operation or throwing an exception.
> `sorted` is a general function that gives you a sorted list from any iterable
iterable in Python is a very loose concept though.
And it's not very consistent too
you give it a str it returns a list of charin Ruby it makes much more sense
You take out the chars from the string, sort them and then join them together againbecause a string cannot be sorted, sorting a string makes no sense, you sort the chars composing it.
Also, Python could not do this for many years, while Ruby could no prob
edit: Python also shows some very counterintuitive semantictake the example above, to return a string you use
which is probably the last thing someone would think of.sorting a list does not produce any output, because sort is _always_ in place, so you have to waste a variable to sort a list because you can't sort it inline
again, highly unexpectedmy favourite
Edit: ok, some do and some don’t. 🈶 is allowed but :laugh_with_tears: isn’t. I guess there’s a specific list of emojis that are getting stripped.
https://news.ycombinator.com/item?id=19482991
In that way `sorted` _is_ totally consistent - it always takes an iterable and returns a list of the elements. If we can't agree on that then I don't think there's much of a discussion to be had here.
except Iterable is the wrong "interface"
in Python it is defined as
> An iterable is any Python object capable of returning its members one at a time, permitting it to be iterated over in a for-loop.
which is not always what you want for sorting
quicksort doesn't work one element at a time
so basically you have to extract all the elements before sorting them
what about infinite streams?
At least Ruby Enumerable mixins explicitly states that
> The Enumerable mixin provides collection classes with several traversal and searching methods, and with the ability to __sort__.
Another problem with sorted is that it accepts any iterable, true, returning a list of items, but it is not clear how you can tell if the object is an iterbale or not
ok mmmmmaybe it's because int is not iterable?
so the solutions are or not only it's very ugly, but it can also fail in mysterious ways. As per documentationChecking isinstance(obj, Iterable) detects classes that are registered as Iterable or that have an __iter__() method, but it does not detect classes that iterate with the __getitem__() method. The only reliable way to determine whether an object is iterable is to call iter(obj).
while in Ruby it's straightforward
However, the destructiveness semantic has been significantly overloaded over the time, so each Ruby (Rails) project probably interprets them in a different way, and it ends up having arbitrary semantics.
I'm used to it, but I personally think that for the reason above, it's not a good syntax/semantic to have in a language.
I wouldn't go so far to say it is arbitrary (unless someone uses it wrongly :) ).
As far as I know, a bang name only exists if a non-bang name exists as well. And the one with ! indicates an unexpected or comparatively dangerous outcome, such as a mutation, raising an exception, bypassing some normal check, etc.
This takes so little time to learn. Same with ?.
While ! is not always the same meaning, it exists when there is a non-bang version; and it means "watch out, this does some sh*t". Maybe it means mutating the source, or maybe it means "doesn't take the usual path", as with Active Record stuff (raising an exception if validations fail on save instead of just returning false).
And the ? is a godsend, as you can clearly indicate functions which return a boolean (or intentionally truthy) value. As naming functions is a chore, and one which can have significant impact on code readability later, the ! and ? have good value when used properly.
For example, Python's sorted() vs list.sort(). If you are new to Python, and you see sorted(list), you may wonder if that is telling you if the list is sorted or sorting the list. It's actually also very awkward, because most functions are named as their actions in present tense, not in past tense. The built-in Python function "sorted" really should be "sort".
In the list of Python built-in functions, you see present tense verbs like slice(), sum(), round(), etc. Those are inconsistent with sorted() and reversed(). When we see a past tense verb, it feels like a question. With Ruby, if it's a question, it ends with a ?.
BTW, why the hell is Python sorted() and reversed() not just called sort() and reverse()?
And while I'm ranting about inconsistencies, Python my_list.sort() mutates my_list, while sorted(my_list) doesn't. In Ruby, my_list.sort returns my_list sorted, without mutating. my_list.sort!. That is consistent and concise, and the bang warns you that it is destructive.
To me, the ! and ? syntax in Rugby is genius. It is a language wide self documenting tool to explain a dangerous function and a boolean, which make total sense.
One thing I think Ruby gets right is the naming convention for methods that modify the object they're called on (<obj>.<method>!) and callables in general that return a boolean (<callable>?).
My biggest gripe with Ruby is the class implementation. I find metaclasses a bit more difficult to understand in Ruby. I hate that I can't easy determine where a given method of an arbitrary object is defined.
I recall that it wasn't uncommon for popular libraries to "open up" a class that was an integral part of Rails and redefine methods, overriding the original implementation. I recall trying to figure out why the method I was calling wasn't returning the value I expected, even after reading the Rails source. Come to find out, some random library had overridden it. They'd matched the behavior of a previous Rails version, but the Rails behavior had since changed. I spent hours on that specific problem and still resent it to this day :P.
https://tenderlovemaking.com/2016/02/05/i-am-a-puts-debugger...
The relevant bit is under the heading:
> I’m calling a method, but I don’t know where it goes
It sounds like this is the answer to your monkey-patching woes.I don't know enough Python to say anything about how easy it is but Python existed for a decade or so before it became popular and that was after Ruby had became popular. That points to it not being popular because it is easy but for some other reason. My guess is BI and AI made Python popular.
[1] https://wbk.one/article/a463c360/the-ruby-tutorial-i-wish-i-...
Ruby more like a philosophy major designing an OOP language - getting done and enjoying getting there were the goals. I took to Ruby more because i never cared about the "engineering" part of languages - just using them as tools to get things done.
This argument is dead the second one stumbles upon the string interpolation/formatting situation. Or the list comprehensions, ew.
May be now, but for a long time when RoR first came out, many people pick python instead of Ruby because scalability. Maybe a lot has improved with Ruby, and with introduction of Crystal, that may not be an issue any more.
I’ve seen that statement multiple times, but in my experience it’s far from the truth. For every thing I ever had to look up in Python I often found more than one way of accomplishing the same task and all of them were (subjectively) uglier and less straightforward than Ruby.
> on "brevity" and "expressiveness", I don't really see them as an attribute that make a language "better". Sure for experienced developers
It’s an attribute including for inexperienced developers. Perhaps especially for them. Even for something as basic¹ as writing a file, one needs multiple lines of code and know about `with` or opening and closing the file². In Ruby: `File.write("/path/to/write.txt", "file contents")`. One line, immediately understandable.
> that doesn't necessarily translate to code that is ideal when working as part of a team, or code that is easy to follow when a new developer starts on an existing codebase.
Agreed. Though in Ruby I have found myself thinking “I wonder if this keyword will work” and it does exactly what I expected. With Python, the norm is frustration with the impossibility of doing the simplest of things like defining a constant.
¹ From the coder’s point of view, never mind the underlying implementation.
² Failing the goal of one and only one obvious way to do something.
Working with various Ruby-adjacent stuff for 10+ years and nothing about Ruby was even "fun" to work with, it was mix of "WTF" and "who designs language like that!".
Python is also not "easier" to start with, I'd put Ruby/JS/Python to be at pretty similar level there. No worrying much about types (till they bite you, inevitably, of course, and cause untold bugs), simple things are simple and actual proper (i.e. "not send it to some piece of C code to calculate) multithreading sucks donkey balls.
I work in Python now, and I often have to use 5-7 lines for what would have been 2-4 in Ruby. Because you have to clutter the Python with trivial details, not because the Ruby code is "magic".
Two minutes of silence for the poor sods who still thinks that AI/ML is pure hype.
(Granted, there is hype. But there is much real stuff.)
And, also, blockchain and ML/AI are nothing similar, except for Twitter bottom-feeders trying to milk each.
AI/ML already has real applications with hundreds of millions of dollars actual value created. And just like CS itself, AI/ML will perpetrate more and more fields in the coming days.
There may not be an AGI soon, or ever, but mark my words, AI/ML will continue to have growing real applications in different fields.
Blockchain had only hype. ML has substance + hype (AGI, silver bullet to all problems, etc.).
I will not engage in language wars like GP here, because those are stupid.
I work all day with Python, and I also enjoy coding in Ruby sometimes in hobby projects.
Hundreds of billions a year probably (and that may be low) if you count online advertising and large consumer facing sites in general. If you turned off the ML behind Facebook/Google/Netflix/Amazon then you'd be lucky to only lose 50% revenue based on my personal experience of adding ML on top of such products.
ML in recsys of Netflix and product suggestion/placement in Amazon are worth tens of billions of dollar alone, per month.
I said, "there are so many more jobs for another popular language", and I was clearly speaking of the broad job market... not a few big players.
Most every large company uses AI/ML to actually drive revenue and the number of engineers they'll hire dwarfs all the small startups put together.
To you question however looking at the latest recruitment thread on HN there's roughly twice as much Python as Ruby. About 30% of the Python work is Data/ML related at first glance. So 40% more companies are hiring for Python versus Ruby pure backend right now. I'm not sure how a 40% difference is such a catastrophic difference.
Python is popular because most every large company uses it nowadays and not because a bunch of non-name startups are using it slightly more often than Ruby.
And that there, is the whole "Problem" of Ruby.
Ruby is a beauty. Rails isn't. It's nice, productive (for certain niches) and has a long track-record. But Rails is also often the root of problems such as maintainability, long-term-productiveness, hosting (performance, scaling), and lock-in.
There are far better solutions for simple CRUD-apps today than writing them all out in MVC code. And when you need complex business-logic (i.e no longer a simlpe CRUD app) the , the weird MVC (plus Concerns) that rails offers is simply not cutting it.
Yet Ruby is Rails, and Rails is Ruby. So when Rails looses its niche and usefulness, Ruby uses it's niche and usefulness. And that's a shame.
(I am a 12+years Ruby, former Rails, and now moving-to-Rust developer)
You cannot use the same approaches for serious, big Rails projects as you might for quick and dirty proof of concepts. And by that I mean OO, mixins, fat models, overemphasis of ORM, etc. will hurt down the road. But most of these same points are true for Django too.
The better way to use Rails is for the core features, and then keep the business logic in modules in "services" (just domain specific organized modules which have little or no dependency on Rails, and are therefore super easy to write complete tests for).
An organically grown Rails project that started as an MVP will predictably turn into a ball of sadness if not refactored significantly at various stages in the life of the project.
But I do see the fading popularity of Rails (and therefore) Ruby to start affecting its usefulness. Less libraries, fewer bindings, abandoned libs and fewer hosting options.
But Ruby is slow. Performance matters. In a world when everything seems to run in cloud servers, efficiency matters.
If you can have 20 times more simultaneous users in the same cloud server by using a different tech stack, there's no reason to keep using Ruby.
For the record, I also think Python is generally slow, but it has improved in the latest version, and the important libraries for Python are written in C++.
There'll obviously always be the exceptions like Twitter having to migrate off Ruby (Well rails) because scaling is just too hard. But those are exceptions.
Not in the first place because of its own, or Ruby's poor performance, but because it's easy to write horrible code, and hard to write nice code in it. AR is a very leaky abstraction over a DB. A horrible query always a mere has_many, sort or default scope away. It's MVC horribly unsuited to manage and isolate business logic. The result often indeed being code that performs terrible.
Except for the ML/AI use case, Laravel has more batteries included I would argue than Django. A ton more features when compared to Rails. All of them are first party solutions for things like Auth/Queues/Monitoring/Payments/Testing/Local Development and even some starter kits.
If you're building a new web based company that isn't focused on building the next AI avatar generator, Laravel should be on your radar if you're also considering Rails or Django.
And C++20 is actually very nice to use.
In contrast, these two, Ruby and Python, are slogs.
(Also if you ask me Ruby never was cleaner and more elegant than Python in the first place, at least in the ways that matter; there are definitely things it does better, but if one of your language's selling points is scripting style use then there are limits to the value of consistency)
Django is today more elegant, more complete, and better documented than Rails ever was. 10 years ago you would have been correct. 5 years ago they were about evenly matched. Today it's not even close. Python is eating the world, and web frameworks are no exception.
In Django in particular, async feels like an afterthought, compared to other frameworks where it's first class.
There are a boatload of compelling reasons to choose Python for its libraries and documentation and adoption level, though.
https://en.wikipedia.org/wiki/First-class_function
"The identifier of a regular "function" in Ruby (which is really a method) cannot be used as a value or passed. It must first be retrieved into a Method or Proc object to be used as first-class data. The syntax for calling such a function object differs from calling regular methods."
Why do people like you insist on talking about things you don't actually know about?
You should really consider whether this is an important enough topic to be worth personally insulting people over.
> In computer science, a programming language is said to have first-class functions if it treats functions as first-class citizens. This means the language supports passing functions as arguments to other functions, returning them as the values from other functions, and assigning them to variables or storing them in data structures.[1]
OCaml has first-class functions, the names can be passed around as parameters and returned as values. Ruby functions and methods cannot; only Proc objects and Method objects proxying for them can be.
You should really consider whether pointing out your incorrectness constitutes an insult and why you think this is so.
"[P]eople like you insist on talking about things you don't actually know about" is insulting language. Consider discussing this with some people you know in real life to see what they think.
To make it concrete: what are you unable to do in Ruby that you're able to do in the languages that you claim do have first-class functions?
You can implement a type system in Scheme if you really want to, what can you do in Haskell that you can’t do in Scheme?
Just admit you are wrong, bud. It’s not as hard as you’re making it out to be. Strachey’s definition is quite clear and Ruby doesn’t have first-class functions nor first-class methods. It’s a language flaw just like Python’s lambda is a language flaw.
https://en.wikipedia.org/wiki/First-class_citizen#History
In Ruby you can assign a function to a variable, pass it to a function as a parameter, return it as the result of a function, and test two function objects for equality. Ruby has first-class functions. If it didn't, you would easily be able to provide an example of a program using first-class functions that cannot be represented in Ruby.
Procs are functions (at least, they are functionally equivalent to Python functions—as pure OO languages, in both Ruby and Python first-class callable entities are richer than classic functions, even when counting closures as a kind functions and not a separate thing that includes a function, because they can carry metadata besides the environment of a closure.)
> It's in the Wikipedia page.
The Wikipedia page is wrong in that conclusion.
> The identifier of a regular "function" in Ruby (which is really a method) cannot be used as a value or passed
A method is a very different thing than a function. But, on a deeper level, I think it is also a mistake to call the thing it is referring the identifier for the method, its just syntax sugar for a symbol passed to a #send call, which, if send isn't overwritten on the sender (which it probably shouldn’t be, overriding send is a good way to cause chaos) will result in the method being called, unless some other method has priority.
> The syntax for calling such a function object differs from calling regular methods
The syntax is different only inna waybthat reflects thebdifferent behavior. Calling #call on a Proc or Method object (again, assuming a sane world where the object’s send method isn’t overidden) does dynamic method lookup on the :call name in the Method or Proc, and its syntax is exactly normal method-call syntax for that behavior (unless you use the shortcut syntax of “.()” for “.call()”, but that's just syntax sugar).
Using normal method call syntax does dynamic lookup on the method name provided in the call on the receiver object identified in the call.
That is, Ruby methods are first class, but what it is a convenient shortcut to think of as “method call syntax” in Ruby is not really method call syntax, it is syntax for a message send that will (by overridable default) result in calling a method with that name if it exists in the ancestor chain of classes for the object, so it is inaccurate to view the “method call” syntax excluding any parameters as “the identifier for the method”.
This isn't the case. If you override `send` it only affects direct usage of `send`. You can't override method dispatch. You can in some other OO languages but not Ruby.
Agreed otherwise. `x.foo` in Python and `x.method(:foo)` in Ruby do the exact same thing -- return a bound method object that can be called. These are both "proxies" in a sense but they're also first-class functions in all meaningful senses.
Correct, I both (minor) confused #send with #__send__ and (more signifcant) misremembered the mechanism of some deep metaprogramming hacks involving a a mostly blank proxy object and #method_missing as using metaclasses and #send/#__send__ hacking; where that came from I don’t know. Should have not mentioned overriding (as its a tangent, in any case, as well as vmbeung wrong) or the #send method and referred to the fundamental underlying message send operation.
In contrast x.method(:foo) does do that proxy construction that you describe… because Ruby does not have first-class functions.
Python docs, section 3.2, subsection "Callable types".
https://docs.python.org/3/reference/datamodel.html#the-stand...
x.foo returns an "instance method object", which is a "callable type". Also referred to as a "bound method", the same term that Ruby and JavaScript use.
> When an instance method object is called, the underlying function (__func__) is called, inserting the class instance (__self__) in front of the argument list. For instance, when C is a class which contains a definition for a function f(), and x is an instance of C, calling x.f(1) is equivalent to calling C.f(x, 1)... Note that the transformation from function object to instance method object happens each time the attribute is retrieved from the instance... It is also important to note that user-defined functions which are attributes of a class instance are not converted to bound methods; this only happens when the function is an attribute of the class.
This last part is why the following program has an error:
me:
> If it's a callable then it can be called with parens
The docs:
> These are the types to which the function call operation (see section Calls) can be applied:
True of Python instance method objects. False of Ruby Methods and Procs. Therefore Python has first-class methods, and Ruby does not have first-class functions nor first-class methods. End of discussion.
This is simply false. Ruby has first-class functions.
Not only that, it has blocks, which few other languages have. Ruby optimizes for the common use-case of a method that takes a single callback/piece of code, and I miss it in most other languages, including Python.
In Python, the "with" statement is super special. But in Ruby, it's just a method that takes a block. And any method can take a block, not just one per class.
https://yehudakatz.com/2010/02/07/the-building-blocks-of-rub...
https://blog.appsignal.com/2018/09/04/ruby-magic-closures-in...
- Async support was second class back then, not obvious how to implement fully.
- REST APIs are a library add-on instead of first-class. An excellent library, but still.
- The package ecosystem sometimes reminded me of the wild-west that is Node.js
- Dependency management is a complicated story (arguably caused by Python, rather than Django itself)
- Django Models are cool and expressive, but nowadays I would rather express my models in something like a dataclass, or a Pydantic model, or just a regular class...
Maybe Rails has these problems and more, I don't know. I'm not saying I'm never going to use Django again, but there's a large chance I will look elsewhere for a batteries-included framework next time I need one.
However Ruby's syntax is way nicer. I can actually write what I think instead of having to translate my thoughts into python. Of course over time working with python has made my thoughts to conform into more pythonic way, but I still occasionally find myself thinking how something would have been way nicer to write in ruby instead.
But it wasn't positive experience with Djangonauts. It was negative experience with RoR devs. I've never had random Django person come from nowhere either on web dev forum or PHP forum to *flame* others for using PHP. But it was regular thing with Rails devs. AFAIR the term "Rails Zealot", meaning combative tribalistic RoR developer who goes around the web to try to convince other devs that they should switch to RoR using aggressive and flaming rhetoric comes from around that time.
I've though this was regular PHP hate, but when I've started learning Django and participating on Python communities I've found out that at smaller scale the flamewars are also there. But this time the reasons why I am "harming myself" and "not real programing" were different.
And look, I LOVE Ruby. I come from twentyish years of Perl, and I really like the way Ruby feels when banging out a script but these days, time is in short supply, and I just don't have time to screw around with Ruby.
If I were someone who was gravely concerned with Ruby's future, I really don't know where to even begin.
* DataSci/ML scene is basically nonexistent, that's a problem.
* Windows scene isn't good, at all. That's a problem. At least it's kinda there, so you wouldn't be starting from scratch at least, like Crystal team has fought with.
* I think something could be done with integrating Rubocop or some other linter (? idk what real Rubyists use) in order to begin solidifying the code culture. PEP8 is a huge factor of Python's success imo.
* Packaging. I'm not familiar with the modern Ruby stack, but in my limited dabbling, rake has done just fine. In Python, hearing about Packaging Issues is the new vogue from customers/people who have no idea what they're doing in the slightest. I've used pip/setup.py in the past, but funny enough I'm actually reading up on Hatch lately, which is the new hotness.
Anyhow, I don't think it's quite fair to throw this much shade at Python when Ruby hasn't really addressed any of the things that makes Python so popular. If Ruby is so much better, than it needs to do all those things at least as well if not better.
Surveys, such as StackOverflow’s (https://survey.stackoverflow.co/2022/#section-most-popular-t...) consistently find that
> Windows is the most popular operating system for developers, across both personal and professional use.
If it makes anyone feel better, I’m in this filter bubble as well. I’ve never seen someone program professionally in Windows.
And I can acomplish any other task a regular developer can do (and I was doing) programming in Java (with sdkman), using docker containers, git on the command line, Big Data tools (flink, iceberg, haddop, etc) and even some bash scripts (nothing too fancy).
The only things that bothers me are the CRLF x LF and sometimes the windows defender making the fans go crazy, but thats is a minimum and I can do some workarounds, the same way I did with bluetooth and audio on Linux.
I guess company laptops that run Linux have been vetted a little more.
Then I moved to Mac, and it was almost as great. (The terminal situation and general integration of the command line is still more cohesive in Linux.)
For about the past 10 years, I've been at a standard Fortune 250 Windows-is-the-entire-world kind of place. I've been able to do my work on my personal Mac, but I've always made sure that I can do all of my Rails work on my corporate Windows laptop. There are times my code needs to access file locations and other applications inside the corporate firewall.
Obviously, people are correct that Ruby is not a "first-class" citizen on Windows, but RubyInstaller (https://rubyinstaller.org) has been a lifesaver. Not only does it "just work," and compile all the gems I've used, but it also includes a neat little script that addresses the common "corporate" practice of having to install custom SSL certificates so that IT can decode all traffic going through their firewall. (They install these certs directly into the Windows networking stack, but bundler doesn't use the stack.) The SSL bundle their script creates is also useful for use with Postgres database connections. You just need RubyInstaller, NodeJS, and a better terminal application (or maybe RubyMine), and you're GTG on Windows.
I've tried to use WSL, both version 1 and 2. If you need to support many Rails apps, and switch Ruby versions (with RVM or rbenv), that might be the way to go, but for just one (big) project, I prefer to stay inside the native environment. And even if I were tempted to use WSL, I'd rather just use an actual VM software like VMWare or OpenBox, and control the details of the virtualization myself. YMMV.
My issue is that most companies using Python probably don't need the Python-only libraries. Aside from the fantasy AI point I originally mentioned, I think Python is the PHB's choice (like the mauve database) because that's what they've read in or heard in their circles, or because the first person building the webapp wants Django's built-in admin interface (which always becomes a problem later, like apps in Excel become problems later).
> Rubocop
Yes, it is fairly standard. And I dislike it like I dislike Black (Python's PEP8 dominatrix). Although Rubocop goes well beyond by giving you often helpful advice about optimization choices or unnecessary code. I like it for that, but I want to format in a more column-oriented way than Rubocop or Black allow (without config mods).
Black is a horror show to me. It's almost like it was designed to chew up as much vertical whitespace as possible. It's not as bad as PHP norms, but it really does like to turn pleasant tight blocks into twice as many lines and extra ( ) (out of necessity, since Python can't deal with linebreaks well).
Sure. Once all of online advertising, search (web, ecommerce, specialized sites, etc.), image editing, spell checking, recommendations (streaming, ecommerce, email, marketing, etc.) and a hundred other things cease to exist. Or more broadly once every large consumer facing company decides, for whatever reason, that it'd prefer to make significantly less money.
People talking about things without realizing what they are and where they're used usually indicates that their broader argument is going to be filled with equally many invalid assumptions and logical holes.
I did not say that AI/ML is not useful. But I'm quite sure that some (many) of the companies using Python are not doing any of that - even if they say on their pitch deck that they are or will.
Django and RoR are much of a muchness. Ruby and Python are too, to a lesser extent. This whole thing stinks of narcissism of small differences and sour grapes. To imply that even most users of the most popular non-browser language in the world are partaking in ML hype is utterly absurd.
When you need to use nebulous words like “clumsy” to describe why you don’t something it’s inarguable that you’re unable to not take your own familiarly into account. I prefer Python, am certainly more familiar with it, and could truthfully say that I feel about Ruby the way that you obviously feel about Python. The difference is I’d never jump onto a Python post on Hacker News and try to pass these feelings off as fact in a way that puts down so many people for preferring a certain tool.
It really isn't. On the whole I've rarely found a tech community that is kinder and more welcoming than Ruby's.
I have used both languages extensively, off and on for nearly 20 years. I've also used C, C++, Java, and built some small projects with Clojure and Elixir.
Of course people have differing sensibilities when it comes to aesthetics, but at a certain point equally observed options can be compared - with one being recognized as better.
I don't put down Python or Pythonistas because I dislike them; I just voiced my frustration that so many companies choose Python when I obviously believe there are better choices (particularly similar complexity/feature options like Ruby).
Clumsy, an incomplete comparison:
Python
OOP
Having to explicitly pass self.
Not having public/protected/private members. Ruby does, including convenience attribute reader/writer functions. And in Ruby you can still provide your own custom methods. In Python, you have to keep an internal _attrname and then have some set_attrname function if you want to provide special logic on your setter.
General recommendation to not use dunders, except that you should define dunders such as __init__ and __str__ for many classes. Ruby's class initializer is an optional method called... "initialize". (Principle of least surprise.) It also has a standard of to_something() methods which return the object in different formats, such as to_str, to_i, to_f, etc. More on this later.
Built-in functions:
sorted(), a past tense verb, doesn't "sorted" a list, it gives you a sorted copy of a list. Not to be confused with list.sort(), which also sorts but returns nothing and mutates list.
next(), which mutates the iterator you pass it. Most other built-ins do not mutate their arguments.
int(), float(), sorted(), next(), etc. all only work for certain argument types. The way to know is just to know. In Ruby, these would be object methods. And you could know if you could do foo.to_i (convert to int) just by asking "abc".respond_to?(:to_i).
Incidentally, Python's int("abcd") raises an exception, while int("1") works as expected. You can't ask the string "can you be converted to int?" Now maybe converting strings to ints is unwise in general, and that's fair. But the ergonomics here are... not good.
And regarding sorted() vs foo.sort(), in Ruby we have foo.sort (non-destructive, returning a sorted list), and foo.sort! (mutates in place). The ! indicates a more significant impact of the function compared to the non-bang version.
Elsewhere in the threads I illustrate list comprehension vs Ruby's collection methods and blocks.
Ternary operator:
Many languages: flag_set ? 1 : 0
Python: 1 if flag_set else 0
This is an if else. So written as an if else, it would be:
if flag_set
else The Python ternary operator rearranges this logic.But! In Python you can't do "1 if flag_set". Ironically, that's fine in Ruby.
Speaking of block return values... (from the imperative if/else above)...
Ruby:
x = if flag_set
else endYou cannot do this in Python because conditional blocks do not return a value.
It is common in Ruby to say x = case(foo) ... and each match will have a value. The value of the expression in the case which matches is used to set x. In Python (now that you finally, as of 3.10 actually have a switch statement), you must repeat the x = expr for each match.
I will say I'm amazed that after so long of no switch statement in Python, they chose to build one with pattern matching reminiscent of Elixir's.
If I were to dig through my memory I could find more examples of Python oddities. My decision to merely compress it all into one word - clumsy - was to avoid getting into these details...
After using languages with no statements, going back feels like a pointless restriction in expressiveness. You don't even need a ternary operator when blocks are expressions that can be used for assigning to variables.
It appears the Elixir community has observed this pattern and has learned from it; time will tell whether that lovely language can build enough popularity to overcome its relative niche status.
(Context: Ruby is my primary programming language; I rotate clients fairly frequently; nobody doesn’t use Rails.)
Elixir has first class access to an incredibly rich (and battled-hardened) network/distributed ecosystem... if you need it. I know there are major voip companies who build on it, and of course Discord is famous for what they were able to do efficiently with it. These are all outside the realm of Phoenix.
That's not to say Phoenix isn't significant. I think it will definitely be a bridge that pulls Ruby (and the few willing Python) devs over to Elixir. It got me, and I built a successful project in it a few years ago.
It's the most productive ecosystem out there because of the sheer level of polish that exists within the Gem ecosystem and the Aspect Oriented Programming capabilities that make it so easy to plug and layer functionality from them.
Combine that with this relentless commitment to Developer Experience and it's a tremendous enabler. No other language and ecosystem that I know of enables so few people to accomplish so much, so fast, so well.
This smugness is insufferable to me. What are you talking about?
I work with PHP and Laravel too and after working with Rails 7 for a bit Laravel is like a cheap imitation.
I also work with python a lot and I wouldn't want to do the web work in python as much as I would ruby but I would rather do the data crunching in python.
It's mediocre language that happened to have some then-popular web framework written in
The Python standard library has never straight up failed on me in the way that Ruby has.
Ruby had buggy named-argument splatting, i.e. func(*kwargs), until 2.7, and even that was a half-realized implementation. It took something like 5 years to fix: https://bugs.ruby-lang.org/issues/11860
I've had similar experiences with Rails.
Which means the `end` keyword can be elimilated all together :D
> The WebAssembly System Interface is not a monolithic standard system interface, but is instead a modular collection of standardized APIs. None of the APIs are required to be implemented to have a compliant runtime. Instead, host environments can choose which APIs make sense for their use cases.
Uhh… OK, I guess. So it’s a collection of APIs to allow Web Assembly programs to make system calls? Why not just say that?
Edit: The official release notes do not make this mistake. https://www.ruby-lang.org/en/news/2022/12/25/ruby-3-2-0-rele...
- JIT - "just-in-time" compilation
- YJIT - "Yet Another Ruby JIT"
- Regex - "regular expression" / sometimes "rational expression"
>This novel approach lazily generates type-specialized versions of basic blocks on-the-fly while propagating context-dependent type information.
Does anyone know how it is different from tracing JIT compilers?
I can highly recommend watching their presentation on it: https://www.youtube.com/watch?v=PFb5wNj2ztM
The actual memory increase depends heavily on the app size so I could quote some figures but it would likely be irrelevant to you.
Some people might be struggling with memory usage and may not see it as worth it, but for others who may have some extra RAM sitting around, it might come as a free perf increase.
As for memory usage, proper use of CoW can reduce it dramatically: https://github.com/Shopify/pitchfork/blob/master/benchmark/R...
https://toitlang.org/
It's dedicated for esp32 programming but it has semantics very similar to Ruby and Python while syntactically it is incredibly simple and clean.
Haven't touched either since like Ruby 1.8/Rails 3
In case you want to stay up to date with what is happening in Ruby world I am curating a free weekly newsletter at https://newsletter.shortruby.com (I took a two weeks vacation but will be back soon with new editions).
where i live, Germany, is java .net and 99% are enterprises old managers with old software :(
- Static typing
We have RBS but that is written to a separate file, the only thing I see being close is the Contracts gem
- Lots of first class scientific libraries and other cool libs
http://sciruby.com is working towards lowering that barrier
Ruby 3.2.0, on a M1 MacBook Pro hitting a simple healthcheck route in a production Rails 6.1 app with wrk (`wrk -c8 -t8 -d30s http://localhost:3000/healthcheck`):
- 423 reqs/second with JIT disabled (using 229MB of RAM)
- 74 reqs/second running with `RUBYOPT="--yjit"` (using 385 MB of RAM)
I must be doing something wrong?
RubyVM::YJIT.enabled?
RubyVM::YJIT.runtime_stats