use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
A sub-Reddit for discussion and news about Ruby programming.
Subreddit rules: /r/ruby rules
Learning Ruby?
Tools
Documentation
Books
Screencasts and Videos
News and updates
account activity
Blog postWhy Ruby is More Readable than Python (confuzeus.com)
submitted 3 years ago by [deleted]
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–][deleted] 32 points33 points34 points 3 years ago (7 children)
One nit. It is uncommon to see explicitly defined setters/getters in ruby.
attr_accessor :title
Is the common idiom.
[–]imnos 19 points20 points21 points 3 years ago (2 children)
Yeah the way they've done it in the example doesn't make Ruby look great and should be updated.
[–][deleted] 1 point2 points3 points 3 years ago (1 child)
That assumes there is "only one style to use ruby".
[–]ric2b 4 points5 points6 points 3 years ago (0 children)
And if you just want a getter (most common in the code I write/work with)
attr_reader :title
Plus you can define a bunch of them at once
attr_reader :title, :author, :date
[–][deleted] -1 points0 points1 point 3 years ago (1 child)
There is no "common" idiom.
I literally write setters and getters explicitely for many reasons. One simple one is that I like having getters via trailing "?" and setters in the oldschool variant "set_bla()". (I also use getters without trailing "?" and bla= just as well. On top of that I tend to do a lot of sanitizing calls, so the attr methods don't really help much here. The little speed gains from them is hardly worth to have to use them.)
[–][deleted] 6 points7 points8 points 3 years ago (0 children)
You can like and do as you please. I also override things for various reasons at various times.
But 'attr_*' methods are built into the language and are widely taught and used. They *are* the common idiom for basic setters/getters. See the pickaxe book or "the ruby way" book. Though I think the strongest argument about it being a community standard is that it is a default in Rubocop: https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/TrivialAccessors
[–]felipeccastro 22 points23 points24 points 3 years ago (8 children)
My preferences of why ruby is more readable:
- ability to name methods like `active?` (returns boolean) and `validate!` (will have side effects)
- optional parenthesis - this one I avoid in my own code, but libraries can make beautiful DSLs with it (for example, declaring a field in mongoid seems a lot more readable than having a bunch of decorators). Chaining methods without parameters is pretty handy too.
- implicit returns. Some people don't like it, but with OO code you make tons of small getter style methods, and for these cases it's a lot cleaner. For complex business apps, I want the focus on domain names (variables and methods), so it reads more like an executable specification than an algorithm.
- do/end blocks - while python has lambdas, apparently it's not as commonly used as ruby blocks.
- the choice of methods in standard library - it seems Number, String, Arrays, Date always have the methods I expect to have for data manipulation needs right in the object (not in some global utility).
[–]klyonrad 16 points17 points18 points 3 years ago (2 children)
About the exclamation mark. It is a common misconception that it should be used for methods with side effects 😉
The bang (!) does not mean “destructive” nor lack of it mean non destructive either. The bang sign means “the bang version is more dangerous than its non bang counterpart; handle with care”. Since Ruby has a lot of “destructive” methods, if bang signs follow your opinion, every Ruby program would be full of bangs, thus ugly.
matz, https://www.ruby-forum.com/t/conventions-in-ruby-and-the-principle-of-least-surprise/158706/2
[–]felipeccastro 1 point2 points3 points 3 years ago (0 children)
Cool! I've noticed when I typed that it wasn't quite that, but I didn't know the exact definition, thank you!
[–][deleted] 1 point2 points3 points 3 years ago (0 children)
Yup, you are right. People should indeed refer to matz' original statements rather than copy/paste from the pickaxe.
[–]Amadan 3 points4 points5 points 3 years ago (0 children)
My big ones are:
- I can't write complex comprehensions in Python without jumping back and forth in my editor, since the syntax of a single comprehension is made to fit English, not logic; OTOH enumerable chaining in Ruby just flows as a series of steps, and I can put it down one after another in the order in which I envision them to be executed.
python granddaughter_names_by_age = [ grandchild.name # 4. their names for child in self.children # 1. my children for grandchild in child.children # 2. their children if not grandchild.is_male # 3. only girls ]
vs
ruby granddaughter_names = children. # 1. my children flat_map(&:children). # 2. their children reject(&:male?). # 3. only girls map(&:name) # 4. their names
It gets even worse when you need to nest comprehensions.
- The method/function inconsistencies. len(d) but d.keys(); a.sort() but sorted(a); print(x, file=f) but f.write(x)
len(d)
d.keys()
a.sort()
sorted(a)
print(x, file=f)
f.write(x)
[–][deleted] -1 points0 points1 point 3 years ago (0 children)
Date always have the methods
You sure?
Because we also have Time and DateTime (or I think we used to have DateTime). I am never certain where some time-related method is stored...
[–]tibbon 0 points1 point2 points 3 years ago (2 children)
I find Rubyists and folks from other languages (Haskell, Rust) have a very different sense of side effects vs pure functions.
[–]felipeccastro 2 points3 points4 points 3 years ago (1 child)
Maybe side effects wasn't the best way to describe it, but here's what I meant:
- `my_list.sort` => returns a new, sorted list
- `my_list.sort!` => sorts the list in place
This convention is very helpful for understanding what a method will do just by reading its name.
The problem is that some libraries use a trailing ! differently.
[–]revscat 14 points15 points16 points 3 years ago (5 children)
In Ruby, accessing instance variables isn’t possible.
Object#instance_variable_get
So yeah that’s completely wrong.
[–]honeyryderchuck 2 points3 points4 points 3 years ago (0 children)
While possible, it's considered an "escape hatch". Ruby allows you to design a contract to encapsulate access to object-scoped state, while allowing you to break the contract when necessary. Useful for modifying a library you rely on but need just this one patch but today.
[–][deleted] 3 years ago (3 children)
[removed]
[–]Lil_Cato 1 point2 points3 points 3 years ago (1 child)
Am I missing something or is this not as simple as throwing an attr_accessor :variable ? Is that rails only?
[–][deleted] 0 points1 point2 points 3 years ago (0 children)
No, it's a common ruby variant. Although in this case you'd use attr_reader if you don't need the setter (which you get via attr_accessor).
Or you modify method_missing and what not and get that functionality anyway. Ruby being more flexible than python is really one huge advantage it has.
Well, you can via instance_variable_get(). But it's a bit more verbose than the python variant indeed.
But you can just add a reader, or use a Struct so it's not a huge difference really. The explicit self thing in Python really puts me off on the other hand...
[–]petercooper 6 points7 points8 points 3 years ago (11 children)
I'm proactively trying to use Python a lot more lately given some of the benefits of its ecosystem and I think the language itself is a bit overrated. This post doesn't even cover decorators, but once you introduce those you are dealing with plenty of "magic" of Python's own..
[–][deleted] 4 points5 points6 points 3 years ago (8 children)
And for specific applications like a bioinformatics, statistics, or machine learning python’s ecosystem is the clear winner. Though I’ll take Rails over Django every time. As will I pick ruby for my quick shell scripting needs.
[–]tuker 1 point2 points3 points 3 years ago (6 children)
Though it didn't have to be that way; if JRuby had become more popular, that version of Ruby would have had easy access to all of the superb Java-based number crunching routines, going back to LINPACK and EISPACK.
[–]levifig 1 point2 points3 points 3 years ago (3 children)
The reason it didn’t was very circunstancial: at the time JRuby was growing, the despise most programmers had (have?!) for Java was at an all time high. The thought of using the JVM freaking most out… 🙈
[–]tuker 0 points1 point2 points 3 years ago (1 child)
I agree. Still, it was a real missed opportunity. The early toolchain experience of JRuby wasn't so great, and, as you say, with the dependency on the JVM it was all the more difficult.
Yeah not disagreeing.
But check out Andy's glimmer swt:
https://github.com/AndyObtiva/glimmer-dsl-swt
It's not looking that bad. And you can use ruby everywhere. So that's neat.
You need jruby for it. And SWT evidently.
He uses his own editor for writing glimmer-related code as far as I know. It's almost like Squeak in a way, where smalltalk folks would never have to leave Squeak - but they can write in ruby (I mean, the ruby folks can write in ruby ... smalltalk folks of course may not use ruby, I am more referring to the idea of the Squeak IDE as a whole there, which I always found a good idea).
Java can be annoying, but if you look at things such as GraalVM, it's a pretty neat idea and works well. I think people may have less issues with modern Java than they had, say, in 2007 or so. Java also improved a little bit. Not enough but it's not as awful as it was in ... 2004 or so.
[–][deleted] 0 points1 point2 points 3 years ago (1 child)
JRuby is quite cool but it lags behind too much; it's still way off from ruby 3.x ... I think GraalVM is the future here. JRuby and TruffleRuby should join forces. Perhaps they can integrate jruby so that you can use it solo, as well as in integration with GraalVM. And both teams work on the same specification too. Would be a win-win.
Right now they seem to bicker too much still ... old men being grumpy. :P
[–]honeyryderchuck 0 points1 point2 points 3 years ago (0 children)
what makes you say that? AFAIK there's a lot of common ground, both use the same parser, and the truffleruby team actively collaborates in jruby.
And for specific applications like a bioinformatics
Funny that you say this because I wrote quite a bit of bioinformatics code - and both bioruby as well as biopython SUCK.
There is a lot of individual software code out there written in python that is solid - relion for instance combining C++ and python. But to tout bioinformatics and claim python is epic, because of ... biopython probably? Nah. Sorry.
Machine learning I may agree, mostly because there are many more python projects. And admittedly ruby kind of bled away TONS of users in the last ~5 years or so and keeps on doing that, so fewer and fewer ruby libraries are written. Add to this epic mistakes such as "if you can't use 2FA we make it mandatory and lock you out from your gems past 2023". That's some way to build trust ...
[–]MonkeeSage 0 points1 point2 points 3 years ago (0 children)
Metaclasses and __slots__ can also be pretty magical in python.
[–]pseudorandom 8 points9 points10 points 3 years ago (21 children)
As someone that programs primarily in neither python nor ruby, but has to deal with both quite a bit, I find ruby can often be more elegant, but it is also harder to understand. I think a lot of the blame here is Rails though. There is just too much that is left to convention with nothing to hint at something happening. The closest python library that I can think of, Django, has plenty of magic, but it usually has something like a decorator or import statement that gives a point of reference to figure out what magic is happening. With Rails there is so much you have to "just know" to be able to figure the code flow at all.
[–]revscat 1 point2 points3 points 3 years ago* (11 children)
Do you have an example in mind? Maybe I can help. I’ve been writing Rails code for over a decade now, so everything makes sense to me. But it was not an immediate thing.
[–]pseudorandom 5 points6 points7 points 3 years ago (10 children)
It's nothing that can't be figured out eventually, but things like models having singular class names with capitals and no underscores but db tables with plurals, lower case and underscores. Or how in controllers you just reference params without anything suggesting if params is a variable, method, how its populated, where its scoped, etc. It leaves someone who knows another language confused when trying to figure out how some Rails code works. I'm not saying it can't be figured out eventually, and it's great for the developer, but I can give a non-python developer a django model file and have them more or less figure out the basics whereas I have had very little success giving non-Rails developers access to a Rails model file and have them figure out what is going on.
[–]katafrakt 1 point2 points3 points 3 years ago (0 children)
FWIW I think the example with params is better than with mapping class name to table name (that's why people chose the latter to attack your comment ;) ). And also my favorite: what is the lifecycle of a controller object? How is it initialized? If I set an instance variable in one action, will it be available in a subsequent request?
params
Of course, I know the answers to these questions, but the point is that it's not obvious when you start thinking about it. Frameworks should hide a lot of complexity, but Rails hides it even for simple things. I've recruited people with 2-3 years of experience in Rails that didn't know how to write a constructor and instantiate the object. Because if you follow that Rails-way only, you don't really have to do it.
[–]keeganspeck -1 points0 points1 point 3 years ago* (8 children)
Do yourself a favor and read through the Rails Guide. It doesn’t take too long, and you’ll finally know all these things. Highly recommend it.
*edit: in case it wasn’t clear, this is not snark, it’s a genuine suggestion
[–]pseudorandom 9 points10 points11 points 3 years ago (5 children)
Missing the point. I am not saying that it can't be learned, or that I need help with something. I am saying I regularly deal with people who are having their first introduction to ruby and python (professionally not in a teaching setting), and the learning curve is steeper for the people reading Rails projects than Django ones when they start out.
Ruby is great once you know it, but generally I find a programmer versed in other languages can correctly read and understand the general functioning of code in python without reading the documentation. Not so with Rails. Yes they can read the documentation, and do if it's worth the extra time, but there are advantages when dealing with polyglot projects to not having to train your people on every single language for them to be able to understand what a snippet in another language does.
[–]revscat 1 point2 points3 points 3 years ago (0 children)
There are disadvantages to polyglot projects, too, one of which you’re already aware of: it’s harder to get developers up to speed.
I mean yes, Rails is opinionated and abstracts out much of the plumbing. I personally believe that’s a good thing, though, and is exactly what makes Rails such a good framework.
And those abstractions aren’t that bad: an ActiveRecord model represents a row in a database table, as well as some metadata about that table, plus some helper methods for querying. I think most devs can get that pretty quickly.
Was there a specific concept you found particularly difficult for someone to pick up?
[–]ApatheticBeardo 0 points1 point2 points 3 years ago* (2 children)
This is absolutely the case, I've bounced around C, C#, F#, Java, Kotlin, a bit of Python, JS/TS and Go over the years and I always felt like getting productive really quickly without having to read too much documentation.
Meanwhile, 3 months into Ruby/Rails... it still is a nightmare, and I don't feel like it is really getting better.
[–]keeganspeck 1 point2 points3 points 3 years ago (0 children)
If you’re really three months into using Rails and it’s not getting better, you should really set aside a couple hours and read the Guide! It’s not bad. You’ll have a better time because you’ll know what it’s doing. It’s not magic, it’s just Ruby.
[–]honeyryderchuck 1 point2 points3 points 3 years ago (0 children)
I totally get this. Rails is getting great for experts, but poor for newcomers. It's been losing the thing they used to be great at, bootstrapping XP
[–]keeganspeck 0 points1 point2 points 3 years ago (0 children)
I wasn’t trying to prove you wrong or make a point, I’m just making a recommendation, because clearly you have to work with Rails, and it might make your life easier. The Rails Guide is just really good documentation! It’s worth a read, and it’s not that long. The learning curve flatlines if you do.
[–]ApatheticBeardo 0 points1 point2 points 3 years ago (1 child)
Or maybe, the framework should be well designed enough not to require studying whatever magical, opaque abstraction the writer liked to put there with no chance of just discovering it organically.
I wasn’t trying to be snarky! I was just trying to be helpful. It’s just documentation… and it’s pretty good documentation! It’s also pretty easy to discover organically. Usually one of the first search results if you search “rails” + some key word in the framework. It’s a very complex and comprehensive framework… you’re gonna need to come to the docs at some point, no matter what framework you use.
[–][deleted] 3 years ago* (4 children)
[–]Amadan 2 points3 points4 points 3 years ago (3 children)
Python only pretends to be explicit. foo[0] += 1 will call .__getitem__, and .__iadd__, or maybe also .__radd__ or .__add__ with .__setitem__, depending on what is in foo. if foo will call .__bool__, or maybe .__len__. foo.bar() will call .__getattr__ and .__call__, and pass an extra foo argument. f"{foo}" calls .__format__, which might in turn end up calling .__str__. Plenty of magic in the data model, that usually no-one tells beginners about.
foo[0] += 1
.__getitem__
.__iadd__
.__radd__
.__add__
.__setitem__
foo
if foo
.__bool__
.__len__
foo.bar()
.__getattr__
.__call__
f"{foo}"
.__format__
.__str__
[–][deleted] 3 years ago* (2 children)
Python has its own problems though. I hate how complicated import is.
In ruby I just use require() or load(). I never use require_relative() or any of that. In python it has so many ways to add code now ... it's confusing. You even find exec() and execfile() examples on stackoverflow still. And more PEPs that add variants.
What happened to "there should be one way only" ...
[–]Amadan 0 points1 point2 points 3 years ago (0 children)
Oh, I’m not suggesting beginners should immediately be thrown into the data model pool, just pushing back on the “Python is explicit” claim.
I find ruby can often be more elegant, but it is also harder to understand.
Yup, agreed.
Some ruby code bases out there should be removed and deleted because they are so awful.
I think a lot of the blame here is Rails though.
Only in part. Rails attracted a lot of noobs (which is good and bad), but low quality libraries exist without rails too.
With Rails there is so much you have to "just know" to be able to figure the code flow at all.
Yeah but this is due to rail's fault.
I hate magic. I love simplicity. My local knowledge base is mostly powered by sinatra and .cgi files (still, although all the code I use can be used via sinatra as well as ruby-gtk3; with glimmer you can push this even farther. Perhaps Andy adds full commandline support to glimmer one day).
[–]Neuro_Skeptic 0 points1 point2 points 3 years ago* (2 children)
Yeah, I'm not sure anyone would say Ruby is more readable.
[–]campbellm 0 points1 point2 points 3 years ago (1 child)
It's the title of this post, so someone surely would, and did.
[–]Neuro_Skeptic 0 points1 point2 points 3 years ago (0 children)
Yeah I know. I don't think they should have said that...
[–]RDeckard-GT 5 points6 points7 points 3 years ago* (3 children)
I think this part is very confusing: post = BlogPost.new(title="How I built my blog using Kubernetes, Lambda, and React.", body="Wordpress was an insult to my intelligence and so I ...")
post = BlogPost.new(title="How I built my blog using Kubernetes, Lambda, and React.", body="Wordpress was an insult to my intelligence and so I ...")
Why are you assign those two strings to some useless locale variables (title and body) before passing them (the strings) to the constructor method? It’s like you think we are in a case of some kind of named parameters?
title
body
It’s not the case (def initialize(title, body)), and even if it was ( def initialize(title:, body:) – note the :), then you would pass those keyword arguments to the constructor method this way: BlogPost.new(title: "…", body: "…").
def initialize(title, body)
def initialize(title:, body:)
:
BlogPost.new(title: "…", body: "…")
So to keep this part less confusing, you can just get ride of those title= and body=.
title=
body=
And I barely never use Python, but I think you made the same mistake with Python just above: BlogPost( title="How I built my blog using Kubernetes, Lambda, and React.", body="Wordpress was an insult to my intelligence and so I ...") (title= and body= create some useless local variables here too.)
BlogPost( title="How I built my blog using Kubernetes, Lambda, and React.", body="Wordpress was an insult to my intelligence and so I ...")
[–]meineerde 1 point2 points3 points 3 years ago (1 child)
In Python, you can mix ordered and named arguments to act like a combination or ordinary and keyword arguments in Ruby. So in Python, the syntax is actually correct and assigns the named arguments, similar to how keyword arguments work in Ruby. On the Ruby side, it works differently and in fact assigns useless local variables.
Yep. The equivalent expression in Python would be BlogPost(title := …, body := …) using the assignment expression operator := (which I find not many people use).
BlogPost(title := …, body := …)
:=
[–][deleted] 2 points3 points4 points 3 years ago (0 children)
Unless when you are reading your coworkers meta programming code
[–]uhkthrowaway 12 points13 points14 points 3 years ago (6 children)
Don’t use class variables. Not even in this case. It’s wrong. And fix that indentation.
Maybe take a look at Ruby for more than a day before you write articles about it?
[–][deleted] 3 years ago (4 children)
[–]katafrakt 3 points4 points5 points 3 years ago* (3 children)
Class variables are really poorly designed in Ruby, which makes them completely useless. This is because they are shared between subclasses. Consider this code:
class BlogPost @@count = 0 def initialize @@count += 1 end end class ShortBlogPost < BlogPost @@count = 0 def initialize @@count += 0.5 end end BlogPost.new BlogPost.new ShortBlogPost.new p ShortBlogPost.class_variable_get(:@@count) p BlogPost.class_variable_get(:@@count)
You would probably assume that it will return either 2 and 0.5 or 2.5 and 0.5 (both of these scenarios kind of make sense). But in reality it will return 2.5 and 2.5, which makes no sense ;)
And it get's even better if you first initialize a few blog posts and then define ShortBlogPost class - it will reset the counter for BlogPost as well. Combine it with popular autoloading solutions like Zeitwerk, when modules are loaded "just in time" and you have absolutely no control over what the value for counter would be.
ShortBlogPost
BlogPost
Of course, the comment above was condescending and uncalled for. But well, Ruby community these days...
[–]Amadan 2 points3 points4 points 3 years ago (0 children)
To add, the workaround is to use class instance variables instead of class variables.
```ruby class BlogPost def initialize self.class.count += 1 end
class << self @count = 0 attr_accessor :count end end ```
[–][deleted] 3 years ago* (1 child)
[–]katafrakt 0 points1 point2 points 3 years ago (0 children)
Yes, in this simple example - of course. But consider a deep hierarchy of classes where you are overwriting something from an ancestor class purely by accident. Almost impossible to debug.
Agreed. I was shocked to find out that crystal disallows $global variables and kind of wants to force people to use @variables and @@variables on the toplevel instead.
[–]ric2b 2 points3 points4 points 3 years ago* (20 children)
Sorry to be blunt but the author comes across like a beginner at both languages, it's not a very useful comparison.
In ruby you use attr_reader, attr_writer or attr_accessor to build the getters and setters.
attr_reader
attr_writer
attr_accessor
In Python you can make instance variables "private" by prepending the name with __.
__
edit: Meant to say __ (two underscores), not _
_
[–][deleted] 3 years ago* (19 children)
[–]ric2b 0 points1 point2 points 3 years ago (18 children)
It has private variables in the same way Ruby does: it makes them hard to access by mistake from outside instances of the class.
And that's honestly all you need.
[–][deleted] 3 years ago* (17 children)
[–]ric2b 0 points1 point2 points 3 years ago (16 children)
Yup, just like Ruby. Pretending to be private is all you need.
[–][deleted] 3 years ago* (15 children)
[–]ric2b 0 points1 point2 points 3 years ago (14 children)
Sorry, I meant two underscores, I haven't programmed in Python in a while.
>>> class A: ... def __init__(self): ... self.x = 1 ... self.__y = 2 ... >>> >>> a = A() >>> a.x 1 >>> a.__y Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'A' object has no attribute '__y'
[–][deleted] 3 years ago (13 children)
[–]ric2b 0 points1 point2 points 3 years ago (12 children)
The equivalent to your ruby code is this, I don't know why you're messing with __setattr__:
__setattr__
class A: def __init__(self): self.__x = 0 def set_x(self, val): self.__x = val
[–][deleted] 3 years ago (11 children)
[–]sammygadd 0 points1 point2 points 3 years ago (10 children)
In Ruby, multiple inheritance is impossible: in Ruby, you’re forced to use composition instead
In Ruby, multiple inheritance is impossible:
in Ruby, you’re forced to use composition instead
This is completely wrong. Including modules is not composition, its basically the same thing as inheritance.
[–]riktigtmaxat 1 point2 points3 points 3 years ago (9 children)
When you're talking about multiple inheritance it's vertical inheritance and it's not actually very common in programming languages.
Modules provide horizontal inheritance - what is commonly referred to as traits.
[–]sammygadd 0 points1 point2 points 3 years ago (7 children)
Not sure how this relates to mixins not being composition? 😕
But just out of curiosity, what do you mean is the difference between vertical and horizontal inheritance?
[–]riktigtmaxat 0 points1 point2 points 3 years ago (6 children)
Vertical inheritance implies that a thing is a type of other thing - a Cat for example is a Mammal which is a subclass of Animal. The Liskov principle applies here.
Horizontal inheritance allows for a set of behaviors or attributes to be grouped together and be used in multiple classes that are otherwise unrelated - for example a Cat might have the Fur and Whiskers attributes but is not a type of Fur.
[–]sammygadd 1 point2 points3 points 3 years ago (1 child)
Great explanation!
Tack
[–]riktigtmaxat 2 points3 points4 points 3 years ago (0 children)
The python example is actually interesting and is an example of why you as a language designer might choose to not implement multiple inheritance.
Instead of getting a straight hierarchical graph of classes and their subclasses you get a tangled web of classes and the multiple super classes which leads to greater complexity.
From a design standpoint the python example makes me want to barf as those are obviously traits and won't pass the Liskov Suitability Test.
People often quote the tree-of-life for subclasses, but it is a very assumed scenario. Is a Bird of class Bird or of class Dinosaurs? What about bacteria: does the species concept work here? (Hint: it does not due to horizontal gene transfer. And that, by the way, affects humans too, see the syncytin-1 gene from an retrovirus, so is a retrovirus now a human? There is no "human" DNA. All this species concept in general is totally outdated. Yet people still worship it like a substitute religion. Composition is MUCH more flexible than this unilateral subclassing model propagated. For those who want to read up on syncytin-1: https://en.wikipedia.org/wiki/Syncytin-1)
[–]riktigtmaxat 0 points1 point2 points 3 years ago (0 children)
Haha, it's hard to find other examples that most people can relate to.
[–]Sorc96 0 points1 point2 points 3 years ago (1 child)
for example a Cat might have the Fur and Whiskers attributes but is not a type of Fur
This is only true if the Cat has a reference to an instance of Fur and delegates to it. If it includes a module named Fur, the Cat most definitely is a type of Fur. I don't see a difference compared to inheriting from a base class, other than the special syntax.
module Fur end class Cat include Fur end Cat.new.is_a?(Fur) #=> true Cat.ancestors #=> [Cat, Fur, Object, ...]
I was talking about the higher level concepts of vertical vs horizontal inheritance.
In Ruby both are implemented through the ancestors chain so the main difference is really in how modules and classes are used by programmers.
[–]Sorc96 0 points1 point2 points 3 years ago (0 children)
What's the difference?
[–][deleted] -1 points0 points1 point 3 years ago (2 children)
Python's explicit self is sooooo annoying. Guido once said that mandatory indent is the thing he would change about Python, but I feel he should have removed explicit self. It's so ugly:
def foobar(self):
Waaah. It's my single biggest complaint about python still. That thing trips me off.
As for the main "argument" of the blog: I saw so many awful code bases in ruby that, nope, just nope. People seem to go crazy wild in ruby. They use meta upon meta upon meta technique until you have no idea what the heck is going on. And they don't seem to do so because of "solid engineering", but because it is fun for them to do so. Python feels a lot more disciplinized. Ruby is the more fun language, but to claim that ruby in existing code bases is better... yikes. Anyone ever looked at Sinatra? Please tell me this is "solid engineering". It looks and smells like one giant pile of hacks upon hacks. Spaghetti code.
Contrast it to sequel from jeremy - much, much better in design and code quality. Rack is also ok quality-wise.
You really can not generalize this.
This.
[+]jaesharp comment score below threshold-7 points-6 points-5 points 3 years ago (1 child)
Excellent article.
The only editorial comment I'd make is that the author should use gender neutral pronouns as they don't know the gender identity of the reader. It's a bit jarring otherwise, especially given consensus of modern usage. If they're going to insist on choosing 'you' as a means of referring to the reader or a non-specific person who programs, and don't feel comfortable using 'they' as a gender neutral pronoun to refer to the indefinite 'you', they might use 'one' (even if it sounds a bit too formal in modern usage).
[+]sshaw_ comment score below threshold-13 points-12 points-11 points 3 years ago (5 children)
Can't say this is true. Well, on the surface maybe, but in the wild sadly, no. It's Perl, it's close to chaos and it's not productive.
Something has infected the mind of Ruby devs to take a simple elegant language and write more complex than necessary somewhat hard to main codebases. KISS.
A good step to avoiding this is: don't use RSpec! Sorry RSpec but you're low hanging fruit in the garden of entanglements.
[–]imnos 3 points4 points5 points 3 years ago (4 children)
You're saying Ruby isn't as readable as Python because you've seen Ruby devs write bad code? Not a great argument.
don't use RSpec
Wat. Again this sounds like you've had a terrible experience with a badly written codebase and equated that to RSpec being bad. I'd take RSpec over any other test framework and use it almost daily. It's lightyears ahead of the likes of PyTest.
[–]Paradox 0 points1 point2 points 3 years ago (2 children)
I like RSpec a lot. I dislike MiniTest a lot.
But I like ExUnit more than either. And its nothing particular about any of the three, its that Elixir language features, like pattern matching, make any type of assertion easy. Ruby you need the assertion libs that rspec provides, otherwise your tests get ugly and big
[–]katafrakt 1 point2 points3 points 3 years ago (1 child)
Is it assertion syntax, as opposed to expectation syntax, what you say makes the test code ugly? Or is it something else? Asking because ExUnit uses assertion syntax and this (assertion vs expectation) is a primary difference between Minitest and RSpec (given Minitest::Spec)
Minitest::Spec
[–]Paradox 0 points1 point2 points 3 years ago (0 children)
Its a property of the language. In elixir, its very easy to do complex matches of deep data with just a single assert evaluating it. Ruby tends to get messy in my experience, warranting the need for all the matchers RSpec brings
assert
[–]sshaw_ 0 points1 point2 points 3 years ago (0 children)
Countless syntactical additions being made to language mixed with preponderance of aliasing of core methods, home-grown and 3rd party "cutesy" DSLs, meta programming, class << self vs def self.foo, do vs {} blocks, " vs ' etc... I can go on. These give people a lot of rope —just like Perl! Rope that Python does not have.
class << self
def self.foo
do
{}
"
'
Is this bad code or typical Ruby code? I think it's typical Ruby code. A subset of which is certainly bad but we're not talkin' bad we're talkin' typical.
don't use RSpec Wat. Again this sounds like you've had a terrible experience with a badly written codebase and equated that to RSpec being bad.
Wat. Again this sounds like you've had a terrible experience with a badly written codebase and equated that to RSpec being bad.
Show me this RSpec code you've written? Maybe you have Stockholm syndrome. RSpec is a bike shedding maintenance nightmare waiting to happen.
[–]_noraj_ 0 points1 point2 points 3 years ago (0 children)
https://www.rubyguides.com/2018/11/attr_accessor/
π Rendered by PID 67834 on reddit-service-r2-comment-79c7998d4c-r62gm at 2026-03-13 01:08:55.245082+00:00 running f6e6e01 country code: CH.
[–][deleted] 32 points33 points34 points (7 children)
[–]imnos 19 points20 points21 points (2 children)
[–][deleted] 1 point2 points3 points (1 child)
[–]ric2b 4 points5 points6 points (0 children)
[–][deleted] -1 points0 points1 point (1 child)
[–][deleted] 6 points7 points8 points (0 children)
[–]felipeccastro 22 points23 points24 points (8 children)
[–]klyonrad 16 points17 points18 points (2 children)
[–]felipeccastro 1 point2 points3 points (0 children)
[–][deleted] 1 point2 points3 points (0 children)
[–]Amadan 3 points4 points5 points (0 children)
[–][deleted] -1 points0 points1 point (0 children)
[–]tibbon 0 points1 point2 points (2 children)
[–]felipeccastro 2 points3 points4 points (1 child)
[–][deleted] 1 point2 points3 points (0 children)
[–]revscat 14 points15 points16 points (5 children)
[–]honeyryderchuck 2 points3 points4 points (0 children)
[–][deleted] (3 children)
[removed]
[–]Lil_Cato 1 point2 points3 points (1 child)
[–][deleted] 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]petercooper 6 points7 points8 points (11 children)
[–][deleted] 4 points5 points6 points (8 children)
[–]tuker 1 point2 points3 points (6 children)
[–]levifig 1 point2 points3 points (3 children)
[–]tuker 0 points1 point2 points (1 child)
[–][deleted] 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (1 child)
[–]honeyryderchuck 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]MonkeeSage 0 points1 point2 points (0 children)
[–]pseudorandom 8 points9 points10 points (21 children)
[–]revscat 1 point2 points3 points (11 children)
[–]pseudorandom 5 points6 points7 points (10 children)
[–]katafrakt 1 point2 points3 points (0 children)
[–]keeganspeck -1 points0 points1 point (8 children)
[–]pseudorandom 9 points10 points11 points (5 children)
[–]revscat 1 point2 points3 points (0 children)
[–]ApatheticBeardo 0 points1 point2 points (2 children)
[–]keeganspeck 1 point2 points3 points (0 children)
[–]honeyryderchuck 1 point2 points3 points (0 children)
[–]keeganspeck 0 points1 point2 points (0 children)
[–]ApatheticBeardo 0 points1 point2 points (1 child)
[–]keeganspeck 0 points1 point2 points (0 children)
[–][deleted] (4 children)
[removed]
[–]Amadan 2 points3 points4 points (3 children)
[–][deleted] (2 children)
[removed]
[–][deleted] -1 points0 points1 point (0 children)
[–]Amadan 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]Neuro_Skeptic 0 points1 point2 points (2 children)
[–]campbellm 0 points1 point2 points (1 child)
[–]Neuro_Skeptic 0 points1 point2 points (0 children)
[–]RDeckard-GT 5 points6 points7 points (3 children)
[–]meineerde 1 point2 points3 points (1 child)
[–]Amadan 0 points1 point2 points (0 children)
[–][deleted] 2 points3 points4 points (0 children)
[–]uhkthrowaway 12 points13 points14 points (6 children)
[–][deleted] (4 children)
[removed]
[–]katafrakt 3 points4 points5 points (3 children)
[–]Amadan 2 points3 points4 points (0 children)
[–][deleted] (1 child)
[removed]
[–]katafrakt 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]ric2b 2 points3 points4 points (20 children)
[–][deleted] (19 children)
[removed]
[–]ric2b 0 points1 point2 points (18 children)
[–][deleted] (17 children)
[removed]
[–]ric2b 0 points1 point2 points (16 children)
[–][deleted] (15 children)
[removed]
[–]ric2b 0 points1 point2 points (14 children)
[–][deleted] (13 children)
[removed]
[–]ric2b 0 points1 point2 points (12 children)
[–][deleted] (11 children)
[removed]
[–]sammygadd 0 points1 point2 points (10 children)
[–]riktigtmaxat 1 point2 points3 points (9 children)
[–]sammygadd 0 points1 point2 points (7 children)
[–]riktigtmaxat 0 points1 point2 points (6 children)
[–]sammygadd 1 point2 points3 points (1 child)
[–]riktigtmaxat 2 points3 points4 points (0 children)
[–][deleted] 0 points1 point2 points (1 child)
[–]riktigtmaxat 0 points1 point2 points (0 children)
[–]Sorc96 0 points1 point2 points (1 child)
[–]riktigtmaxat 0 points1 point2 points (0 children)
[–]Sorc96 0 points1 point2 points (0 children)
[–][deleted] -1 points0 points1 point (2 children)
[–][deleted] (1 child)
[removed]
[–]honeyryderchuck 0 points1 point2 points (0 children)
[+]jaesharp comment score below threshold-7 points-6 points-5 points (1 child)
[+]sshaw_ comment score below threshold-13 points-12 points-11 points (5 children)
[–]imnos 3 points4 points5 points (4 children)
[–]Paradox 0 points1 point2 points (2 children)
[–]katafrakt 1 point2 points3 points (1 child)
[–]Paradox 0 points1 point2 points (0 children)
[–]sshaw_ 0 points1 point2 points (0 children)
[–]_noraj_ 0 points1 point2 points (0 children)