secret
Last active

  • Download Gist
gistfile1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
Ruby Mistakes
=============
 
* Using blocks for looping and callbacks
* break/next/return semantics in blocks extremely bizzare
* And they have different behavior in procs vs. lambdas
* Why on earth does defined? return a string?
* throw/catch. Why!
* Inline rescue, no ability to specify what exception (and by extension, "catch
anything" behavior common in community)
* Mutable objects have a hash method and can go in Hashes. Why!!!
* Extremely complex grammar, makes barrier to entry for implementation much
higher
* Special case of flip-flop and regexp in an if statement (only if it appears
syntactically though!)
* Setting `$=` to something truthy causes all string operations to become
case-insensitive. This and other magic globals from perl are mind blowing.
* Keywords that silently override methods by the same name (defined?, on
Rubinius block_given?)
* `f {}`. Tell me what the parsing of that is.
* proc, lambda, block, method, unbound method, functions. None of which have a
clear relationship. set_trace_func exists, even though you can't pass
functions around.
* Bizzare magic::
def f
Proc.new
end
f { |x| 3 }
How does ``Proc.new`` know where the block came from?
* Ruby's module system makes namespacing optional (and off by default).
* Regexp with named matches decompose into local variables. Dear lord why.
* Encoding system is beyond broken
* Scopes: constants, class vars, instance vars, methods, locals. wtf.
* Constants aren't constant. Truth in naming.
* Thread locals are really fiber locals.
* You can change the encoding of a string. Just jesus christ wow.

As for bizzare magic part - ruby assumes implicit block argument to any function? As a pythonista I envy ruby the block system - it's a little bizarre, but very, very powerfull.
What's wrong with encoding in ruby?
Regexp named matches decomposing is indeed a disaster :)

First off: ZOMG BBQ PONIES! WHY!!! (dude, tone/attitude - way off)

  • throw/catch: flow control. rarely useful, but useful nonetheless. remember: the world doesn't revolve around your personal use cases
  • Mutable objects have a hash method and can go in Hashes: so? again, the world doesn't revolve around your use cases. E.g. Arrays as hash keys are nice. And you can freeze your objects if you need the hand-holding.
  • Extremely complex grammar: yes, ruby's focus is the user of ruby. get over it. If you want to implement a language that is easy on implementers, go assembly.
  • [EDIT, credits @ Hanmac] Setting $= to something truthy: $= and some others do not work anymore in newer rubies (didn't know that since I simply avoid $= and friends) [/EDIT]
  • Keywords that silently override methods: they don't override. you can still call them. it's similar as how local variables take precedence over methods if you aren't explicit.
  • Regexp with named matches decompose into local variables: incomplete/incorrect statement. it's far less worse than you make it. the decomposition only happens in a very restricted case (LHS regex, no interpolation).
  • Encoding system is beyond broken: hurray for proper arguments?
  • Scopes: constants, class vars, instance vars, methods, locals: what's your problem with it?
  • You can change the encoding of a string: and that's bad why? A string is mutable, so is its encoding. It has practical applications.

If you want to go all ZOMG JESUS WOULDN'T HAVE DONE THAT, then at least get your facts together or make proper arguments. Sheesh…

I strongly recommend this talk by Katz: http://www.everytalk.tv/talks/863-RuPy-Tradeoffs-and-Choices-Why-Ruby-isn-t-Python . Explains why some of the things OP mentions were put into the language, the lambda/proc dichotomy in particular.

It would be nice to have this worked into a full blog post (or even a series of posts) by someone, to provide some context and explanation for us non-Rubyists.

While I also find block loops confusing in Ruby, it seems to me that Rust gets them right. They pretty much always do what I expect them to do. Small changes to Ruby's would make them a lot saner, but that's probably unlikely.

@apeiros
Hashable mutable objects is extremely error-prone. You can't always know that the things you call will not try to mutate your data. The default is wrong, it should only work for frozen objects.
The extremely complex grammar is extremely confusing for beginners.

You can change the encoding of a string. Just jesus christ wow.

Not really, if you dive in you'll realize it's just creating a new String and setting the String you're encoding (I believe with encode!) to that new content. Just like Object.to_s doesn't change the Object into a String, it returns a String representation of that Object. I'm pretty sure that's how that works, but I'm not a Ruby expert...

This and other magic globals from perl are mind blowing.

Don't use them? They're designed to be annoying and hard to use, because you're not supposed to use them except in dire circumstances, or you really know what you're doing.

Ruby's module system makes namespacing optional (and off by default).

What the hell does this even mean?

Constants aren't constant. Truth in naming.

Convention over configuration. Constants are treated as constant, you can change them but people don't if they're not an idiot.

One thing I will add to this

  • Why the fuck are and and or only for control flow? Why can't Ruby figure out that I'm in a boolean expression or I want to assign something based on a boolean expression? It would make me so happy to write if @x.present? and @y.blank? rather than typing &&, which I've always hated.

But whatever, it's not the end of the world. :)

I don't think this is a very constructive criticism. It seems that half of it are just small quirks that you can easily avoid, and the rest touches the core concepts that defines Ruby.

My comments below:


Using blocks for looping and callbacks

Mistake? Smalltalk would like a word with you…

Why on earth does defined? return a string?

Does it matter?

Personally, I think this issue is way more confusing:

# Guess what each of these lines return/do:
defined?(exit!)
defined?(exit.foo)
defined?(exit!.foo)

throw/catch. Why!

Because it's useful to longjmp without the overhead of creating an exception.

Inline rescue, no ability to specify what exception
Setting $= to something truthy causes all string operations to become case-insensitive. This and other magic globals from perl are mind blowing.
Special case of flip-flop and regexp in an if statement (only if it appears syntactically though!)

Yeah, matz designed Ruby as a Perl alternative, so there's still some cruft left. In hindsight, it turns out that Ruby didn't replace Perl's one-liners. But still: Just can just ignore these and everything will be alright. If you want to crunch out one-liners you can use them.

("catch anything" behavior common in community)

Really? I thought we pretty much decided that "catch anything" is bad 5-10 years ago or so? Why do you think Rails has try??

f {}. Tell me what the parsing of that is.
Extremely complex grammar, makes barrier to entry for implementation much higher

And for some people it makes the barrier to start learning and writing Ruby easier.

proc, lambda, block, method, unbound method, functions.
Scopes: constants, class vars, instance vars, methods, locals.

(There's no functions btw.)

I agree, class variables were a mistake. The rest are just different concepts for different tasks.

How does Proc.new know where the block came from?

I think this was added together with the &blk-syntax as a way to write backwards-compatible code. Not quite sure though.

Encoding system is beyond broken

Location: San Francisco. Right. Maybe you should try to introduce a programming language in Japan and see how far UTF-8-everywhere? Being able to use other internal encodings than UTF-8/16/32 is useful when you're only dealing with a certain type of strings.

Ruby 1.8 didn't have any encoding system. Ruby 1.9's encoding system was added based on matz' experiences with encodings in Japan.

Thread locals are really fiber locals.

Backwards compatibility. Not a mistake per-se; just a trade-off. But yeah, real thread locals would be nice.

Ruby's module system makes namespacing optional (and off by default).
Constants aren't constant.
Mutable objects have a hash method and can go in Hashes. Why!!!
You can change the encoding of a string.

It's a mutable language. Ruby has never been about preventing yourself to shoot yourself in your foot.

  • Using blocks for looping and callbacks
    • break/next/return semantics in blocks extremely bizzare
    • And they have different behavior in procs vs. lambdas

Is it? Personally I prefer ruby's use of blocks for iteration. Non-local return has quite a few solid use cases. I don't see how break/next semantics are so bizarre, could you please explain your argument better?

  • Constants aren't constant. Truth in naming.

Well of course it wouldn't be Ruby if constants were truly constant. Nothing in Ruby is constant. You may call this a mistake, but there are good use cases for even this (eg. Rails' reloading)

  • Regexp with named matches decompose into local variables. Dear lord why.

As @apeiros mentioned, this only happens in a very specific case. I haven't actually used this feature before (I wasn't aware of it), but this does seem extremely useful for short scripts (one of Ruby's undeniable strengths - this also justifies flip flops and regexps in if statements.

  • Mutable objects have a hash method and can go in Hashes. Why!!!

Why not? Ruby doesn't really believe in artificial limitations so much. Ruby will allow you to do all sorts of crazy things if you choose. Nobody is forcing you to put mutable objects in Hashes.

@tubbo: The only difference between and/or and &&/|| is the precedence.

@alex: Ah so you're a Python person?

Let's talk about __iadd__ and friends :wink:. Then we can discuss other things in a passive aggressive manner.

I just found myself love mistakes...

some 1.9 points:
$= does not work on newer ruby anymore
block variables are now realy block variables and do not overwrite the local variables anymore

@charliesome

though I don't like __iadd__, there's nothing wrong with special methods/protocols

I guess that you dislike the underscores, but that's just part of the language: it's syntax and convention

It's no more of a burden than parentheses in lisp, or begin end in ruby...

I loathed parentheses until I dabbled more with lisp, and I dislike begin end, but I'm sure that I'd get used to them if I used ruby (or pascal, or ada) more

@lucian1900
You don't want mutable hash keys? Then just. don't. use. mutable objects as hash keys. Nobody forces you to.
And again, you can also freeze your hash keys if you want.
And experience disagrees strongly with your "extremely error prone". Reality shows that mutable hash keys are rarely ever the reason for a bug.

* break/next/return semantics in blocks extremely bizzare
* And they have different behavior in procs vs. lambdas

Yehuda's article here might be helpful for understanding this:

http://yehudakatz.com/2012/01/10/javascript-needs-blocks/

Constants aren't constant. Truth in naming.

This is really a philosophy difference. Ruby lets you do whatever you want. You can redefine constants, access private methods, and modify core classes. All "restrictions" are advisory; the programmer is given both great power and great responsibility.

@nathanl Yep, came here to say just that. The almost anarchic style of Ruby is why I love the language. So much respect and autonomy for the user.

My 2 cents as a ruby newb:

This gist indeed is written in a confrontational style, but since it's "secret"... I wouldn't really complain about that: I'd guess that it simply wasn't meant to be distributed as is.

I like the information contained in it btw, while some things are indeed just a matter of taste/philosophy:

Like the unconstantness of constants: in python it's the same, but python doesn't advertise any sort of constants

So one could say: "if you cannot guarantee it, just don't put it in the syntax!" or "we're consenting adults, if you modify what should stay constant, be aware of the consequences"... both views are fine imho

Other things are plainly broken, and the fact that they're being dealt with in newer releases is both a demonstration of it and a blessing for present and future ruby developers :)

(like Hanmac said: $= and block variables, and possibly encoding from what I read about ruby2.0)

Hashing mutables seem like a defect, but still... if the class we're talking about is mostly similar to java "beans" and methods don't meddle with the state, so that you can guarantee that the state won't change on its own... it's sorta sensible to allow it

The issue is probably that purists say that you cannot really prove that it behaves like that (even if ruby wasn't dynamic, it's probably undecidable), and so you shouldn't allow it... while rubysts feel that having concise code and being pragmatic is worth the risk

Then, "Encoding system is beyond broken" isn't really helping: ranting is fine, but you should at least point out exactly what isn't working

As a newbie, I don't get the deal with throw/catch, I assume that it's just another raise/rescue like explained here ?
But with the fact that by convention it's used for flow control instead of error handling?

If so: that's a classic TMTOWTDI vs TSBOOWTDI choice... I'm with the latter, but I understand the idea

one last thing:

@apeiros

Extremely complex grammar: yes, ruby's focus is the user of ruby. get over it. If you want to implement a language that is easy on implementers, go assembly.

That misses the point imho: for a language that's easy on implementers and is still powerful you should think about lisp

In fact for many of those powerful features, it shouldn't be really needed to have a complicated grammar...

It's not something that shows day-to-day, but I think we all agree that a complicated grammar (and worse a context-dependant like C++ or Perl I guess) is a bad thing... and obviously you can build great things out of bad things, but that doesn't excuse it :)

peace

Answer to all the whys: ruby has some beautiful flexibility. Now I'm off to watch cat videos.

Those are not so much mistakes. They may be really odd design decisions with hard-to-grasp semantics. They may be problematic because they make it hard to write efficient interpreters and/or compilers. They may be a problem to compiler implementors to the point where it is almost impossible to get the language right. But I do not think they are outright mistakes.

That said, what makes Ruby so appealing to others certainly does not appeal to me. It is not an aesthetic language to me, but to others it seems to be. I think this can be compared to a discussion about paintings: if you don't like the impressionistic style, then you don't like it.

And the compiler thing is real. If constants are not constants, then the compiler cannot propagate constant values and hence performance will suffer. And this is just one example of such.

@apeiros You can never be certain that the the hash key you pass to a function won't be mutated. Thus, the default of only allowing immutable (or at least frozen) keys is much less dangerous. Hash could even freeze the keys on the way in itself.

I see a fair about of people already argued by the majority of things in the list, so I'll just leave it there. I will make an addition to the statement about inline rescue though.

Inline rescue, no ability to specify what exception (and by extension, "catch
anything" behavior common in community)

@avdi talks about inline rescue in episode 22 of Ruby Tapas. Inline rescue might come handy if you want to evaluate the exception and act upon it. This can be done by making use of the $! variable.

Inline rescue, no ability to specify what exception (and by extension, "catch anything" behavior common in community)

This is the worst IMHO; the others are not so bad (the one of the Regexp with named matches is bad, but is not so common), and some are just "not bugs but features" (f.e. the fact that you can change the encoding of a string).

Python guy complaining that Ruby isn't Python. It shouldn't be "Ruby Mistakes". It should be "Things about Ruby I don't understand because it doesn't work the same way as in a language I'm used to".

@cogweh If it should be "Things about Ruby I don't understand..." than could you be so kind to share a part of your genuine experience with ruby and explain those things to us, python/javascript/lisp/whatever guys.

A corresponding Python Mistakes gist :)
https://gist.github.com/4558963

This reminds me of the blub paradox...

@Nek selective context "...because it doesn't work the same way as in a language I'm used to" This is basically frivolous bickering about the language which we shouldn't be having. The OP is clearly trying to point out what he perceives as flaws in a language without much basis. It's the same thing as saying "that car is red so it must be horrible."

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.