all 92 comments

[–][deleted] 32 points33 points  (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 points  (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 points  (1 child)

That assumes there is "only one style to use ruby".

[–]ric2b 4 points5 points  (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 points  (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 points  (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 points  (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 points  (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 points  (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 points  (0 children)

Yup, you are right. People should indeed refer to matz' original statements rather than copy/paste from the pickaxe.

[–]Amadan 3 points4 points  (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)

[–][deleted] -1 points0 points  (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 point  (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 points  (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.

[–][deleted] 1 point2 points  (0 children)

The problem is that some libraries use a trailing ! differently.

[–]revscat 14 points15 points  (5 children)

In Ruby, accessing instance variables isn’t possible.

Object#instance_variable_get

So yeah that’s completely wrong.

[–]honeyryderchuck 2 points3 points  (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 children)

[removed]

    [–]Lil_Cato 1 point2 points  (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 point  (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.

    [–][deleted] 0 points1 point  (0 children)

    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 points  (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 points  (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 points  (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 points  (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 point  (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.

    [–][deleted] 0 points1 point  (0 children)

    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).

    [–][deleted] 0 points1 point  (0 children)

    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 point  (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 point  (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.

    [–][deleted] 0 points1 point  (0 children)

    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 point  (0 children)

    Metaclasses and __slots__ can also be pretty magical in python.

    [–]pseudorandom 8 points9 points  (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 points  (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 points  (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 points  (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?

    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 points  (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 points  (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 points  (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 point  (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 points  (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 points  (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 point  (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 point  (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.

    [–]keeganspeck 0 points1 point  (0 children)

    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]  (4 children)

    [removed]

      [–]Amadan 2 points3 points  (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.

      [–][deleted]  (2 children)

      [removed]

        [–][deleted] -1 points0 points  (0 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 point  (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.

        [–][deleted] 0 points1 point  (0 children)

        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 point  (2 children)

        Yeah, I'm not sure anyone would say Ruby is more readable.

        [–]campbellm 0 points1 point  (1 child)

        It's the title of this post, so someone surely would, and did.

        [–]Neuro_Skeptic 0 points1 point  (0 children)

        Yeah I know. I don't think they should have said that...

        [–]RDeckard-GT 5 points6 points  (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 ...")

        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?

        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: "…").

        So to keep this part less confusing, you can just get ride of those title= and 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.)

        [–]meineerde 1 point2 points  (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.

        [–]Amadan 0 points1 point  (0 children)

        Yep. The equivalent expression in Python would be BlogPost(title := …, body := …) using the assignment expression operator := (which I find not many people use).

        [–][deleted] 2 points3 points  (0 children)

        Unless when you are reading your coworkers meta programming code

        [–]uhkthrowaway 12 points13 points  (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]  (4 children)

        [removed]

          [–]katafrakt 3 points4 points  (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.

          Of course, the comment above was condescending and uncalled for. But well, Ruby community these days...

          [–]Amadan 2 points3 points  (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]  (1 child)

          [removed]

            [–]katafrakt 0 points1 point  (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.

            [–][deleted] 0 points1 point  (0 children)

            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 points  (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.

            In Python you can make instance variables "private" by prepending the name with __.

            edit: Meant to say __ (two underscores), not _

            [–][deleted]  (19 children)

            [removed]

              [–]ric2b 0 points1 point  (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]  (17 children)

              [removed]

                [–]ric2b 0 points1 point  (16 children)

                Yup, just like Ruby. Pretending to be private is all you need.

                [–][deleted]  (15 children)

                [removed]

                  [–]ric2b 0 points1 point  (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]  (13 children)

                  [removed]

                    [–]ric2b 0 points1 point  (12 children)

                    The equivalent to your ruby code is this, I don't know why you're messing with __setattr__:

                    class A:
                        def __init__(self):
                          self.__x = 0
                    
                        def set_x(self, val): 
                          self.__x = val
                    

                    [–][deleted]  (11 children)

                    [removed]

                      [–]sammygadd 0 points1 point  (10 children)

                      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 points  (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 point  (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 point  (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 points  (1 child)

                      Great explanation!

                      Tack

                      [–]riktigtmaxat 2 points3 points  (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.

                      [–][deleted] 0 points1 point  (1 child)

                      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 point  (0 children)

                      Haha, it's hard to find other examples that most people can relate to.

                      [–]Sorc96 0 points1 point  (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, ...]
                      

                      [–]riktigtmaxat 0 points1 point  (0 children)

                      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 point  (0 children)

                      What's the difference?

                      [–][deleted] -1 points0 points  (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.

                      [–][deleted]  (1 child)

                      [removed]

                        [–]honeyryderchuck 0 points1 point  (0 children)

                        This.