In contrast to the mess that is Python. For instance, in Ruby it is natural that each or map are methods of Array or Hash rather than global functions which receive an Array or Hash argument.
This goes as far as having the not operator '!' as a method on booleans:
false.! == true
Once you have understood it, it is a very beautiful language.
Stuff like map() is generic iteration, over any structure that exposes iteration. When it's a member function, it means that every collection has to implement map itself basically. When it's separate, the collections only need to provide the interface needed to iterate over it, and the generic map() will just use that.
Taking OOP more seriously, this kind of thing should be implemented through inheritance, interfaces, mixins, etc. Even though I've got used to it, Python has these inconsistencies that sometimes it wants to be more OOP, sometimes it wants to be more FP.
Ruby has chosen OOP as its size, and implements nicely those functional operations as methods (same for Kotlin, for example). That makes easy for composing them:
# Sum of the square of even elements of a list, in Ruby
my_list.filter{|x| x % 2 == 0}.map{|x| x * 2}.sum
Python could do something like that, but we quickly fall in a parentheses hell:
# The same code, in Python
sum(map(lambda x: x * 2, filter(lambda x: x % 2 == 0, my_list)))
Languages that have chosen the FP path more seriously implement function composition. They could do the same way as Python, but composition makes it more readable:
# The same code, in Haskell
sum . map (^ 2) . filter (\x -> x `mod` 2 == 0) $ my_list
PS: I know that I it would be better to use comprehensions in both Python and Haskell, but these are general examples
So semantically it's actually closer to Python, with the only difference that, since Python doesn't have extension methods, it has to use global functions for this, while Kotlin lets you pretend that those methods are actually members. But this is pure syntactic sugar, not a semantic difference.
FWIW you can have both in this case; you just need to make dotted method calls syntactic sugar for global function invocations.
That might looks really anecdotal, but on practice for example that's is probably the biggest obstacle to providing fully localized version of Ruby for example.
The second biggest challenge to do so would probably be the convention of using majuscule to mark a constant, which thus requires a bicameral writing system. That is rather ironic given that none of the three writing system of Japanese is bicameral (looks fair to exclude romaniji here). Though this can be somehow circumvented with tricks like
``` # Define a global method dynamically Object.send(:define_method, :lowercase_constant) do "This is a constant-like value" end
# Usage puts lowercase_constant ```
Awesome, but with great power come great responsibility ;)
You end up feeling and steered to the the right idiomatic way of doing things is the satisfying way.
The well-known Rails framework uses this to great effect, however, some people argue that the choice of "convention over configuration" and extensive use of meta-programming, derisively called "magic", make it less suitable for inexperienced teams because they get too much rope to hang themselves and the lack of explicitness starts working against you if you're not careful.
That's not even close to true. Even setting aside APL and its descendants, even setting aside Perl, any of the functional programming languages like Haskell and Scala are less verbose.
(The relative lack of success of those languages should indicate why minimizing verbosity is a poor aim to target.)
thread = Thread.new do # thread code end
...
thread.join
In this example we can see that it's not magic, only concise.
I wrote more about it here: https://www.hackerneue.com/item?id=40763640
var thread = new Thread(() -> {
// Thread code
});
thread.start();
// ...
thread.join();Thread.new{ ... thread code ...}.join
The extra verboseness quickly adds up if every statement takes twice as much code.
Kotlin is another language that has this Ruby-style blocks for callbacks.
Also you don't want all and everything being the results of spells you don't have a clue how they are cast.
Why doesn't clojure fit the bill here?
I wouldn't say niche, but the killer app of Ruby is Rails, a web framework similar to Django. In fact, many people treat them as they are the same. But there are big projects that use Ruby and that are not related to Rails. As far as I remember: Metasploit, Homebrew, Vagrant and Jekyll.
Personally I think Ruby is amazing language for writing shell scripts. I write a blog post about it, you can see it and its discussion here: https://www.hackerneue.com/item?id=40763640
What’s the conspiracy theory here? Why would anyone be paying people to hype Ruby? What could possibly be the end goal?
Hiring increasingly disinterested junior devs.
I wouldn't have had this much control of my own environment with another language, so that all of these are pure Ruby:
- My window manager - My shell - My terminal, including the font renderer. - My editor - My desktop manager
That's less than 10k lines of code. I've taken it a bit to the extreme, but I wouldn't have had the time to if I had to fight a more verbose language.
https://github.com/vidarh/rubywm
Beware that one of the joys of writing these for my own use is that I've only added the features I use, and fixed bugs that matter to me, and "clean enough to be readable for me" is very different from best practice for a bigger project.
I'm slowly extracting the things I'm willing to more generally support into gems, though.
That's something that you could submit as a post here in HN
The biggest issue with these projects is that I feel uncomfortable pushing a few of them because I make a living of providing development and devops work, and my personal "only has to work on my machine and certain bugs are fine to overlook" projects are very different to work projects in how clean they are etc... But as I clean things up so they're closer to meeting my standards for publication I'll post more.
It's also got a bunch of semi-functional-programming paradigms throughout that make life quite a bit easier when you get used to using them.
Honestly, if it had types by default and across all / most of its packages easily (no. Sorbet + Rails is pain, or at least was last I tried), I'd probably recommend it over a lot of other languages.
1) It has differences in behavior with certain classes and is not a drop-in replacement.
2) It always compiles, so it's kind of slow to compile-test
Compile/test time is ok. It's a few extra seconds to run tests, but hasn't been an issue in practice for me.
I've tend to have found Kotlin to be the direction I'm more happy going with. It speaks to my particular itches for me personally, more effectively. I can absolutely see how it's a very effective choice.
I wish the TypeScript/React integration was easier. Say what you will but there's no way you can achieve interactivity and convenience of React (et al) UIs with Turbo/Hotwire in a meaningful time.
Have you tried either Inertia (https://github.com/inertiajs/inertia-rails) or vite-ruby (https://vite-ruby.netlify.app/)? Both look very promising.
I don’t think it needs a niche. :)
A simple example: `3.days.ago` is a very commonly used idiom in Rails projects. Under the hood, it extends the base Number class with `def days` to produce a duration and then extends duration with `def ago` to apply the duration to the current time.
Taking that concept to a bigger extreme is this mostly unnecessary library: https://github.com/sshaw/yymmdd
`yyyy-mm-dd(datestr)` will parse a date str that matches yyyy-mm-dd format. It looks like a special DSL, but it's just Ruby. `dd(datestr)` produces a `DatePart`. Then it's just operator overloading on subtraction to capture the rest of the format and return the parsed date.
That library feels unnecessary, but the entire thing is 100 lines of code. The ease of bending the language to fit a use case led to a very rich ecosystem. The challenge is consistency and predictability, especially with a large team.
Where it shines now is in it's width and depth. There are thousands of well documented libraries built by millions of dev's.
If you want to do something; near anything, ruby has a gem for it. It's power today is that it is omni.
Overall, a pleasant and expressive language with an incredible community. Python ends up "winning" because of pytorch + pandas, but is (imo) a worse language to work in + with.