Also overriding mro() is a fun way to monkey with the inner workings.
Still, I preferred and prefer Ruby. Python has fantastic libraries, but it is a mediocre language. Ruby feels like a simpler version of Perl + Smalltalk, and it is a joy to use. Python has intentionally crippled anonymous functions plus syntactic whitespace, which often leads to long and ugly code.
I think it is a shame Guido hated functional programming and he did not embrace an Algol-like syntax with begin/do end blocks. Those two things could have vastly improved Python. Ruby's block, procedure and lambda design is a stroke of genius that yields beautiful code and makes DSLs trivial.
Hardly. Not only was it nothing great, it had many variations, making it harder to remember.
For me, the Ruby community's comfort with monkey patching was a big turn off
If it helps, the Ruby community really soured on monkeypatching in general quite a while back. You don't see it much these days and every decent book or guide warns against it.It was definitely a crazier place 10+ years ago in the early Rails days.
Yeah! It sure was.
I was around, was an early Ruby and Rails adopter, and worked on a few commercial Rails projects at that time.
That's how I know about the monkey patching issues. Faced them in real life.
I played around with Rails and Ruby when Rails first blew up. But I didn't start doing it fulltime professionally until 2014. By the time it seemed to me that the community was maturing. I think it's in a good place now.
This is surprising to me. I love ruby, but it embraces implicitness more than any other language I've used. method_missing, monkey patching internals, and other types of metaprogramming make things very implicit at the interface level
Far less true than with Perl.
In another hand, many questions I asked about Python came with various way to do the stuff. So I'm not sure about that advertisement.
Neither (except maybe the None case in Python) is really implicit, Ruby is just an expression oriented language while Python is statement-oriented.
OTOH, in Ruby the keyword “return” is superfluous except for altering control flow for an early return, while in Python it is the mechanism for supplying a return value.
I would really hate this feature in a language without strong static typing.
I don’t mean using testing as a poor man’s type system, I mean even the tests you would write in a statically typed language will quickly uncover any mistakes you could possibly make there.
I'm pretty sure I'd see multiple cases where the function would return different types depending on a code path.
Quite commonly by design, or, “why union (and sum) types are a thing”.
Something returning type “Foo | nil” is very often going to return Foo on one branch and nil on another.
Still, it's not like you're going to miss that a function doesn't return something expected. Even in statically typed languages you are going to have tests to validate that much.
> I'm pretty sure I'd see multiple cases where the function would return different types depending on a code path.
That's another problem entirely. Although even then it would be pretty hard for an errant type to not blow up your tests. Again, not tests specifically meant to check that your types or sane, just the same tests you would write in a statically typed language.