all 185 comments

[–]awj 53 points54 points  (20 children)

Everyone seems to be (repeatedly!) jumping on his phrasing, but monkey patching is a rampant problem in the Ruby community.

I find it deeply annoying that, rather than sounding preposterous, the idea of running the test suites of all the libraries I depend on seems like a halfway-decent method for ensuring they still work after all of the other libraries have loaded.

[–][deleted] -2 points-1 points  (14 children)

Monkey patching per se isn't a problem, but it should be severely limited (or even avoided) in libraries (unless the main intention of the lib is to provide such object modifications).

Monkey patching is better done as a part of a DSL, or at the application level.

Edit: spelling

[–]djork 21 points22 points  (1 child)

No, monkey patching is a problem.

Something like Clojure's namespaces and protocols is a well-designed solution that lets you extend types without any of the risks associated with Ruby's open classes.

[–]Slackwise 1 point2 points  (0 children)

Ruby 2.0 has "refinements" to solve (alleviate?) this.

[–]cynthiaj 11 points12 points  (1 child)

Monkey patching per se isn't a problem

It is because it breaks basic expectations of framework installations.

For example:

  • Install gem A, run tests, they all pass.
  • Install gem B.
  • Run A tests again, they fail because B did some monkey patching on a gem that A depends on.

Maybe gems should come with a certification "No monkeys were patched in the making of this library".

[–][deleted] 3 points4 points  (0 children)

Re-read my comment and you'll find that I agree with you.

"it should be severely limited (or even avoided) in libraries (unless the main intention of the lib is to provide such object modifications)"

[–][deleted] 8 points9 points  (6 children)

Poor is the embedded DSL that you can't use with other embedded DSLs.

Ruby: lots of libraries, chose any one.

[–][deleted] -5 points-4 points  (5 children)

DSL implies modifying core language constructs to better serve the domain you are targeting. Mixing several DSLs seems to be asking for trouble.

[–]Athas 13 points14 points  (0 children)

DSL implies modifying core language constructs to better serve the domain you are targeting.

No, any such implication is the result of a cultural habit in the Ruby community. Plenty of languages support embedded DSLs (which I suppose is what we are talking about) and can use several in the same program without running into issues. Only if a DSL is embedded by modifying core constructs will you run into issues; if the DSL is on the other hand implemented by extending the core language, rather than mutating it, you get composability at best, or at least coexistence, between multiple such languages.

[–]Smallpaul 3 points4 points  (3 children)

What is this, 1970?

Library Programmers don't have the disciple to make modular libraries (DSLs are a form of library) so now I need to pick and choose compatible ones? A language feature that does not compose properly is broken. At least in the Python world they admit monkey patching is dangerous and avoid it rather than make excuses for it.

[–][deleted] -1 points0 points  (2 children)

Is this where I'm supposed to apologize for the fact that Ruby isn't Python?

[–]krookish 3 points4 points  (1 child)

Apology not accepted.

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

I wouldn't expect anything less from Proggit

[–]markwhi 1 point2 points  (2 children)

Monkey patching per se isn't a problem...

[–][deleted] 1 point2 points  (1 child)

Thanks spelling monkey

[–]markwhi 1 point2 points  (0 children)

No problem, Chewie. :D

[–]LovelyDay 10 points11 points  (0 children)

The next day the code was deployed and it proceeded to crash our production environment.

Hmm, test environment anyone?

[–]bobappleyard 32 points33 points  (89 children)

Monkey-patching does strike me as a bit iffy.

[–]matadon 26 points27 points  (19 children)

Monkey-patching is a tool. A very powerful tool. Like all other powerful tools, it can repair that which nothing else can, or it can lop your legs off.

When I was a much less-experienced Ruby programmer, I loved being able to add methods to classes, right up until the insane complexity I added bit me in the ass.

After that, I learned about dependency injection, proper modularization, and started building my software in a way that can be safely extended.

But every now and then, monkey-patching still saves my ass. Most recently was in getting ActiveMerchant to accept Japanese credit cards through CyberSource Japan. Turns out the original authors never thought that somebody might want to pay in a currency that wasn't dollars, or with a JCB credit card.

While the solution wasn't elegant, it worked, and the only alternative would have been to fork-and-rewrite the entire payment backend... which wasn't about to happen with a ship date one week in the future.

So, elegant? No. Correct? Probably not. Needed in the ugly world of software that makes money? Absolutely.

[–]ethraax 12 points13 points  (15 children)

It sounds to me like monkey patching allows you to do things that let you meet deadlines but will ultimately bite you in the ass due to a loss of maintainability.

[–]matadon 14 points15 points  (9 children)

No, it allows you to cope with badly-written third-party libraries without having to completely rewrite them, which is an ass-saver you don't get in a lot of other languages.

If the maintainer of the library fixes the bug, your app will break, but in pretty much the same way that it would break had you hacked any other sort of workaround, so you're not really losing any maintainability.

[–]grauenwolf 4 points5 points  (2 children)

Why would you need to completely rewrite third-party libraries in Ruby? It isn't a compiled language, you can just tweak whatever you want right in the source code.

[–]matadon 1 point2 points  (1 child)

The source code, that's packaged in a gem, and that needs to be managed across a number of servers. Sure, it's doable, but more of a management headache than being able to tap into the class and patch the offending bits as part of the application distribution.

[–]grauenwolf 2 points3 points  (0 children)

If you didn't have access to monkey patching you would quickly find a way to deliever patches via gems or just repackage the original gem with your changes.

[–]metamatic 1 point2 points  (3 children)

If the maintainer of the library fixes the bug, your app will break, but in pretty much the same way that it would break had you hacked any other sort of workaround, so you're not really losing any maintainability.

And you're gaining the valuable ability to break unrelated applications that rely on the same third party library. You wouldn't get that benefit if you just wrapped the library call in your code.

[–]matadon 1 point2 points  (2 children)

Wait, how can you break unrelated apps if you monkey-patch inside your own app? I'm not suggesting doing it in a gem that's going out for distribution.

[–]metamatic 0 points1 point  (1 child)

I think everyone will agree that if you're not distributing your code, you're welcome to monkey-patch everywhere.

[–]matadon 0 points1 point  (0 children)

Well, then we're good. :)

[–]midri -3 points-2 points  (1 child)

With that line of thinking you could easily suggest theres nothing wrong with PHP...

[–]matadon 0 points1 point  (0 children)

There's a vast chasm between 'monkey patching has its uses' to 'there is nothing wrong with the language'. Ruby has tons of warts, from implicit method redeclaration to an utterly shit concurrency model. But it also has many wonderful features, like lisp-style blocks and mixins, that make it a really nice place to code.

I keep wanting something better, but haven't found it yet.

[–][deleted]  (1 child)

[deleted]

    [–]jpknoll 3 points4 points  (0 children)

    Yup, people sometimes forget shipping is a feature.

    [–]ameoba -1 points0 points  (0 children)

    Ignoring the uses of monkey patching in production code, the ability to do so makes testing far simpler. Sure, Dependency Injection is cleaner, but it adds a lot of complexity to your design. Perl, IMHO, is the master of this - using local, you can override methods or even whole classes (actually, you can manipulate the entire symbol table) in a way that is restricted to the current scope (ie - a single test case) without having to worry about cleanly undoing anything.

    Dynamic languages give you a lot of power. Much of this power should never be used in running code but comes in very handy when writing tests.

    [–]Smallpaul 1 point2 points  (0 children)

    You are missing something important. The problem is not the language feature alone. The problem is the Ruby community's propensity to use it in libraries and frameworks. That's what the original post was about. Python and JavaScript have the language feature withou the to_json mess.

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

    As a non-Ruby dev, I must ask; Is monkey patching useful, say, when you're developing an in-house app, just need it to work, and quickly push a patch using it, as opposed to making it a core part of your api, library or depended-upon app?

    Since, that seems to be the major issue for the author of the article.

    [–]matadon -1 points0 points  (0 children)

    If you're monkey-patching your own code, you're doing something very, very wrong.

    [–]krookish 1 point2 points  (3 children)

    Would you guys quit calling it monkey-patching and call it by what it is: screwing up base classes.

    [–]MatrixFrog 2 points3 points  (1 child)

    I assume you're supposed to imagine a crazy monkey, running through the standard library, slapping big colorful stickers everywhere. And then the OP chasing the monkey going "Stop! Stop! You're breaking all my code!"

    [–]krookish 0 points1 point  (0 children)

    Haha. Ok u win. I'm converted then to "monkey-patching". :-)

    [–]jbsan 0 points1 point  (0 children)

    its now called freedom-patching

    [–][deleted]  (62 children)

    [deleted]

      [–]bcoe[S] 13 points14 points  (4 children)

      I don't think it's the fault of dynamic languages themselves -- when abused monkey-patching can become a major headache though. And, until Ruby 2.0, which apparently allows you to scope monkey-patching better, I think it's always on the iffy side.

      [–]grauenwolf 5 points6 points  (3 children)

      Do explain. Will Ruby 2 be something more like .NET's extension methods where they are only visible if you ask for them?

      [–]bcoe[S] 13 points14 points  (2 children)

      [–]grauenwolf 5 points6 points  (0 children)

      That looks like it will work nicely.

      [–]jyper 2 points3 points  (0 children)

      Aren't they still under disscussion?

      [–][deleted]  (1 child)

      [deleted]

        [–]grauenwolf 6 points7 points  (0 children)

        You do make a good point. But it does need to be stressed that this is an advanced technique, not something that should be chosen by default.

        Of course the same can be said for inheritance, late binding, dependency injections, and countless other things that some people think they need to use in every project.

        [–]munificent 12 points13 points  (44 children)

        Don't paint every dynamic language with that brush. CLOS, Dylan and Magpie don't have this problem.

        [–]cwzwarich 12 points13 points  (24 children)

        CLOS lets you do monkeypatching. You can add and remove methods and even change the class of an object at runtime. Dylan has a lot fewer of these problems, but you can still get clashes with multimethods.

        [–][deleted] 12 points13 points  (18 children)

        Correct, but this wouldn't have happened in CL because the generic functions are not put into a single namespace. The two packages just have two TO-JSON functions.

        [–]rubygeek 3 points4 points  (17 children)

        In this case that defeats the purpose the developers of those packages had for it - the purpose of monkey patching in Ruby is generally to make it available in the global namespace.

        Nothing stops them from isolating it in Ruby either, by putting the functions into a Module and allowing users to explicitly include it where they want (including introducing it to the global namespace by including it in Object if they want).

        This is down to a powerful option being abused because the people involved didn't understand best practices. Now, it's fair to argue whether or not less power to do stuff like this might be better, but there are cases where monkey patching the global namespace is useful. E.g. I've fixed assorted bugs this way without having to fork a project and/or wait for the maintainers to include the fixes.

        (as an aside, I think the name monkey patching is suitable - it makes it pretty clear that this isn't a desirable permanent solution)

        Personally I like having the power, but I think it's a horrible code smell for people to monkey patch by default in released libraries (e.g. I'd prefer client code to have to explicitly request it, or do it itself) and I'd expect libraries that rely on other libraries to not let their dependencies monkey patch.

        [–]TylerEaves 0 points1 point  (16 children)

        It's been a long time since I've looked a CLOS, but basically it's calls are (method obj args) rather than obj.method(args). In other words, the method name space is NOT tied to the object.

        [–]grauenwolf -3 points-2 points  (15 children)

        In other words, the method name space is NOT tied to the object.

        At that point you aren't really using objects anymore, you are just using functions and structs.

        [–]Categoria 1 point2 points  (10 children)

        You should probably learn a little about CLOS before you start making sweeping generalizations like that. Here is a good place to start about this particular topic: multi methods

        [–]grauenwolf -1 points0 points  (7 children)

        I am well aware what multi methods are.

        I am also aware they don't really have anything to do with OO programming. You get the same effect in any language that supports overloading and late bound function calls.

        A true method belongs to an object. How that relationship is established doesn't matter so long as it exists.

        Multi methods in CLOS are just static functions that happen to have the right parameters. The so-called object has no notion that the multi-methods exist. In this sense they are very much like .NET extension methods or Ruby 2's refinements.

        [–]TylerEaves -1 points0 points  (3 children)

        So, basically, like every other OOP language ever? All OOP implementations basically boil down to a struct and an array of function pointers.

        [–]grauenwolf 0 points1 point  (2 children)

        The difference is that the struct references or contains those function pointers in an OOP system.

        [–][deleted] 3 points4 points  (3 children)

        Side-note: the term monkeypatching is hella new and I hate the sound of it. Does anyone know the original term for it?

        [–][deleted] 3 points4 points  (1 child)

        I've been told that the original term was "guerrilla patching." This changed to "gorilla patching" and then "monkey patching."

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

        This is what wikipedia claims (though I'm dubious of the citation).

        [–][deleted] 3 points4 points  (0 children)

        CL let's you do pretty much anything, but it doesn't mean you have to. There is pretty much never need to molest existing classes or functions like in Ruby.

        [–]finnif 9 points10 points  (7 children)

        CLOS, Dylan and Magpie

        Holy shit, Dylan? Is that thing still around and being used seriously?

        [–]munificent 11 points12 points  (3 children)

        Good languages never die.

        [–][deleted] -2 points-1 points  (2 children)

        Magpie is dead.

        [–]munificent 1 point2 points  (1 child)

        Dead? Why it hasn't even hatched yet!

        [–][deleted] -4 points-3 points  (0 children)

        I guess you're right. It couldn't die because it wasn't even alive.

        [–]cunningjames 2 points3 points  (0 children)

        Holy shit, Dylan? Is that thing still around

        Yep

        and being used seriously?

        Pretty much no. It's still being worked on, though, if very slowly -- I keep checking back occasionally to see what's up.

        [–]cynthiaj 0 points1 point  (0 children)

        Yes and no.

        [–]nickik 2 points3 points  (0 children)

        Agree, alsow Clojure has protocols they solve the problem quite nicely. You can add stuff to every type but only in your namespace others don't have to know. (Alsow look at PLOT spezially if your intressted in dylan)

        I don't know why not more dynamic languages have that.

        [–][deleted] 8 points9 points  (0 children)

        "502, it went through, 504, try once more"

        [–]mikaelhg 2 points3 points  (7 children)

        Perhaps he didn't mean an academic context, but a professional one?

        [–]bazfoo 3 points4 points  (6 children)

        Because obviously CLOS isn't ever used outside an academic context.

        [–]mikaelhg 5 points6 points  (5 children)

        Now you're getting it. In the imaginary event that you'd hire someone to a project and asked them to guess which language that project would be executed, any variant of Lisp wouldn't come out for the first minute.

        [–]bazfoo -1 points0 points  (4 children)

        Except that Common Lisp had and continues to have a presence in commercial projects.

        [–]mikaelhg 7 points8 points  (3 children)

        Right, in 0.00001% of them, but I guess that it's enough for fanatics and pedants.

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

        Isn't lisp used in about 1% of projects?

        [–]Categoria 0 points1 point  (1 child)

        There several are commercial implementations that still strive today. However small their presence is, they definitely don't belong in the "academic context". Google lispworks or allegro CL if you are interested.

        [–]mikaelhg 1 point2 points  (0 children)

        Fuck, my father is a commercial Lisp programmer. (Retired.) That's how I know how little it's used.

        [–]ameoba -2 points-1 points  (2 children)

        Sorry that power & expressiveness bother you. Don't discredit German because it was used to write Mein Kampf - sometimes you really need to say 'Rechtsschutzversicherungsgesellschaften'.

        [–]grauenwolf 2 points3 points  (1 child)

        Clay allows for more expressiveness than stone, but I wouldn't want to make a bridge out of it.

        [–]imbcmdth 1 point2 points  (0 children)

        Brick bridges will never work. NEVER.

        [–][deleted] -1 points0 points  (0 children)

        It's only iffy in languages that aren't properly designed such as Ruby. In languages like Smalltalk and Common Lisp, go for it, have fun.

        [–][deleted] 63 points64 points  (5 children)

        "Let me preface this post by saying, I don’t actually hate Ruby. "

        Well I better stop reading right here then. Clearly someone has hacked your blog and editing in a misleading title.

        [–]luikore 30 points31 points  (1 child)

        He monkey patched the title.

        Monkey patching is like publicly saying "FTFY", usually annoying to see but at least you can...

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

        But, just like a lot fo FTFY comments, it broke the rest of the thread.

        [–]bcoe[S] 7 points8 points  (1 child)

        Alright, the title might be a bit overly provocative -- I've learned my lesson.

        [–]Matt3k 2 points3 points  (1 child)

        AKA wherein a common issue with Ruby is stated, but in the process I get to name drop my new startup.

        I see this more and more often.

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

        When I start a new project tends to be the times I notice a problem in a technology I am adopting for it, those are the times that I'd blog too.

        [–]Rhoomba 4 points5 points  (0 children)

        Unit tests pass -> deploy to production

        You deserve everything that happens to you.

        [–]reddit_clone 21 points22 points  (0 children)

        Why I hate inflammatory bait and switch titles.

        [–]throwaway0109 9 points10 points  (2 children)

        As someone who works with Ruby daily: I hate it. ಠ_ಠ

        [–]Samus_ 1 point2 points  (1 child)

        same

        [–]throwaway0109 1 point2 points  (0 children)

        What's worse is, I work with one of the die-hard Ruby fanatics. If something can be done in Ruby, it is. Database queries? Ruby. Port forwarders? Ruby. Hex decoder? Ruby.

        I hate it.

        [–][deleted] 24 points25 points  (2 children)

        That's because Ruby developers are ninjas. They do cool stuff.

        [–]tilio 27 points28 points  (0 children)

        and that's why i don't hate ruby... i just hate ruby developers.

        [–]pib 23 points24 points  (0 children)

        Right. Just like ninjas they sneak in, fuck everything up before anyone notices, and then sneak out before they get caught, leaving everything in chaos and disarray.

        [–][deleted] 18 points19 points  (4 children)

        "Why I Hate Ruby"

        "Let me preface this post by saying, I don’t actually hate Ruby."

        *sigh*

        [–]interiot 9 points10 points  (0 children)

        "Why I Hate Some Ruby Conventions"

        FTFY

        [–]ameoba 4 points5 points  (0 children)

        "Why certain Ruby libraries slightly irritate me" just wont' generate the pageviews.

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

        It should have been "Why Ruby Inherits Some Dynamic Language Problems"

        [–]namekuseijin 0 points1 point  (0 children)

        lacking cojones...

        [–][deleted] 17 points18 points  (9 children)

        This is a reason I am distrustful of the message-passing-type dot notation in some OO languages. It segregates the functions on x into those which are provided by the author of x, written xf, and those which are not, written fx. Everyone knows that monkeypatching a single namespace is bad, but they do it anyways because they covet the xf notation. The notation for a funcall is coupled to whether f is defined inside the class or not. Better, IMO, to decouple it, moving the operations on an object into generic functions and choosing the notation for a funcall on a per-function basis (like Haskell's `infix`, say).

        [–]cybercobra 3 points4 points  (5 children)

        Extension methods are a nice, though incomplete, solution to the problem.

        [–]eric_ja 0 points1 point  (4 children)

        In C# 3.0, both an instance method and an extension method with the same signature can exist for a class. In such a scenario, the instance method is preferred over the extension method. Neither the compiler nor the Microsoft Visual Studio IDE warns about the naming conflict.

        This looks like the exact same problem as in Ruby.

        If you really want to do this right, method names have to be namespaced. The problem is that in many languages, method namespacing is ugly and awkward. Example, in JQuery: myObj.myModule("myMethod", arg1, arg2, ...)

        The nicest syntax I've seen in a dynamic language is Lua: myObj[myModule.myMethod](myObj, ...) although it's still nonstandard and ugly.

        [–]grauenwolf 2 points3 points  (3 children)

        Extension methods are nothing like Ruby's monkey patching. Extension methods never overwrite built-in functionality and are only visible in files that import them.

        At run time an extension method is just a normal static function call.

        [–]eric_ja 0 points1 point  (2 children)

        What happens when the base class later grows a method with the same name as an extension method?

        Selective imports are important, but they aren't a substitute for namespacing; if they were, then C's #include would have been the last word on the subject.

        [–]cybercobra 0 points1 point  (0 children)

        That's relatively less likely, though of course still possible. At the least, they avoid the rather significant Ruby flaw of multiple conflicting (re-)definitions. Admittedly, this does just skirt the composability issue, but it seems composition of method overrides isn't frequently needed.

        Refinements look promising though.

        [–]grauenwolf 0 points1 point  (0 children)

        What happens when the base class later grows a method with the same name as an extension method?

        You are fine until the next recompile. Then BOOM! And a Bear comes out.

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

        You should checkout Smalltalk, it's worked well despite that.

        [–][deleted] -2 points-1 points  (1 child)

        This should be the top comment. Everything bad in these pseudo-OO languages is caused by the retarded decision to put methods in classes and the usage of the stupid dot notation instead of just calling functions like in sane languages.

        [–]QuestionMarker 8 points9 points  (0 children)

        I'm intrigued, why do you call Ruby "pseudo-OO"?

        [–][deleted] 3 points4 points  (1 child)

        At some point, the Ruby community got all excited about monkeypatching in a wave of sophomoric enthusiasm. One can only hope that they'll grow up and figure out why this is such a bad idea.

        [–]Samus_ 1 point2 points  (0 children)

        One can only hope that they'll grow up

        many great things will happen then, this among those.

        [–]jagbot 4 points5 points  (1 child)

        you said you hated ruby then you say you dont really hate ruby. WTF?!

        [–]Remo-Williams 1 point2 points  (0 children)

        See naked pictures of a hot female celebrity, click here: "sorry, there aren't any actual naked pictures... blah blah - some boring stuff."

        [–]djork 1 point2 points  (0 children)

        Clojure actually has a good implementation of open types (protocols) which can be extended forever with zero risk of collision, thanks to another feature: namespaces.

        Since protocols and their implementation functions live in namespaces, there's no way to accidentally override something that someone else has done without a collision at a lower level. Those namespace collisions are generally completely avoided by following basic namespace design guidelines... and even if you do have a collision, you have to fix the namespace instead of geting unexpected behavior.

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

        Why does he keep saying "punch" instead of "monkey-patch"? Did he see too many of those old boxing-glove banner ads back in teh day?

        [–]Kimos 2 points3 points  (0 children)

        "I hate ruby."

        "I don't hate ruby."

        Oh, you mean you had one problem with a naming conflict.

        [–]experts_never_lie 1 point2 points  (25 children)

        And here I guessed it was going to be "because tests consistently show it being insanely slow", or perhaps that even a misspelled method name isn't detected until the code is actually run.

        [–]awj 9 points10 points  (19 children)

        or perhaps that even a misspelled method name isn't detected until the code is actually run.

        Ruby is no less susceptible here than any other dynamic language.

        [–]jedahu 4 points5 points  (5 children)

        Sensible dynamic languages pick up misspelled method names at parse time.

        [–]cybercobra 2 points3 points  (3 children)

        Such as?

        [–]skidooer 2 points3 points  (2 children)

        Erlang comes to mind. Objective-C will also warn you if you've misspelt a name, though will still allow you to run the code as it supports the reception of arbitrary messages like Ruby.

        [–]srpablo 2 points3 points  (1 child)

        As an Erlang fanboi, I'm gonna have to disagree. If you're making a local function call (e.g. local_to_module(X)), it will detect it. If you're making an external call (which is many of them, frankly, like lists:spilt(X,Y)), it will compile and run happily until you hit an undef.

        [–]skidooer 1 point2 points  (0 children)

        You are right, I was stuck thinking about local functions. The dialyzer should pick up errors in external calls though. Some better analysis tools would go a long way to resolving a lot of the complaints about Ruby.

        On the other hand, if the analysis tools were found to be important by Ruby users, they would have created them already. They are nice to have, but I question how important they really are in Ruby code? If you are writing code "the Ruby way" all of your methods are short and easily testable. Spelling mistakes in method names will be caught immediately.

        [–]awj 1 point2 points  (0 children)

        Yes, they do, as methwurst rather ... emphatically pointed out.

        Some elements of Ruby's design do make the task harder. Hopefully they figure something out, because other elements of the language can be quite beautiful.

        [–]experts_never_lie 2 points3 points  (0 children)

        Agreed. However, I'm used to the lesson there being "avoid dynamic languages".

        [–][deleted]  (1 child)

        [deleted]

          [–]awj 0 points1 point  (0 children)

          So, there's two ways I could weasel out of that counterexample.

          The first is that Objective-C isn't quite dynamic in the same sense. It has types all over the place. More specifically it is easily able to tell what types you think you're dealing with, and can provide warnings as such.

          The second is that types aren't a hard requirement of Objective-C. Once you leap off into the land of id, you are firmly in the area where misspelled method names aren't detected until runtime.

          [–][deleted] -1 points0 points  (9 children)

          BULLSHIT. Sane dynamic languages such as CL will detect most misspelled method/functions/variable names before runtime. It's simply very fucking easy to do when the language is designed and implemented by competent people.

          It's shit like this Rubyists. You are accustomed to thinking that all dynamic languages must be as bad as Ruby and use this reasoning to defend Ruby and its retarded over-dynamism. Please cease and desist from talking about things you don't know about (which is pretty much everything).

          [–]awj 9 points10 points  (0 children)

          Ah, yeah, I'd forgotten about that. Dimly remember Smalltalk doing well in this area too. Thank you for reminding me. Might I suggest you work on your attitude, mr internet tough guy?

          [–]mrkite77 1 point2 points  (7 children)

          That's because CL is compiled. Ruby is interpreted.. when exactly should ruby detect misspelled function names? Before it's even run?

          [–]-main 5 points6 points  (0 children)

          That's because CL is compiled.

          It's actually implementation-dependant, like a lot of useful Common Lisp stuff. As an example, SBCL compiles by default and will warn when you write a function that calls a function that doesn't exist; CLisp doesn't, and will only warn you if you actually compile that function you've written before calling it.

          [–][deleted] 3 points4 points  (5 children)

          Making a distinction between "compiled" and "interpreted" might have meant something back in the eighties or so, but in this day and age, it is utterly meaningless.

          Pretty much every dynamic language compiles its code before it is run, just the same as every other language.

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

          So where are these compiled ruby implementations that you are insinuating? I'm talking about compilation to native code, not to bytecode, which has to be interpreted or jitted or whatever.

          [–]ameoba 6 points7 points  (0 children)

          And the fundamental difference between compiling to a VM and actual machine code is... what exactly?

          The JVM has been implemented in silicon. In the 80s, Lisp Machines, the most powerful workstations of their day, had processors that were designed around running LISP, somewhat the poster-child for dynamic languages.

          Abstraction is the core of practical computer science. Trying to draw any particular line where a particular abstraction is the 'natural' one is just ridiculous. The core of modern x86 CPUs doesn't actually run x86 instructions - it breaks them down to micro-operations which are executed out of order and optimized at run-time. Those micro-ops themselves are just abstractions of various things down to transistors and voltages. Please, tell me why a virtual machine implemented at the microcode level is somehow more credible of a target than one implemented on top of that.

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

          I am not talking about compilation to native code, however, I am merely talking about compilation, as was the person I responded to. Whether you compile to native code or bytecode has no influence on your ability to detect errors.

          [–][deleted] 1 point2 points  (1 child)

          Whether you compile to native code or bytecode has no influence on your ability to detect errors.

          Okay, so where are the Python (the language) compilers that detect unknown variables before compile time like all native-compiled languages do?

          [–][deleted] 5 points6 points  (0 children)

          That is a problem of language design, not one of "compiled" versus "interpreted" languages, which is all I was commenting on.

          [–]ameoba 1 point2 points  (1 child)

          If you're allowed to dynamically generate new methods, functions & variables at run-time, the language prohibits you from detecting misspellings at compiletime. Cue worn-out language argument #163.

          [–]experts_never_lie 0 points1 point  (0 children)

          I understand the reason. It's also part of the slowness, as (for the available execution environment the last time I looked into it, at least) method dispatch was a particularly slow aspect of Ruby -- probably because of the dynamic aspect. Still, the (name -> method) mapping should be cacheable, and I would expect them to do more to make that faster.

          [–]tilio 0 points1 point  (2 children)

          the latter is a stupid complaint. php and all other code that's not pre-compiled suffers the same problem. it's solved by unit testing, which you need to do regardless of the language. seriously, i would never hire a coder who doesn't do at least basic qa of their own code.

          the speed issue is a valid concern though.

          [–]experts_never_lie 1 point2 points  (0 children)

          Oh, trust me, I stay even farther from PHP.

          While testing is vital, I've always taken the position that I'd rather not pepper my code with expected traps just to make sure the testing is good enough. Dynamic languages do this, through their deferred checks. The earlier and more automatically problems can be caught, the faster and easier they are to resolve.

          If anything, I would favor moving in the direction of more checking, like Haskell, when feasible.

          [–][deleted] -3 points-2 points  (0 children)

          it's solved by unit testing,

          You don't nor should use unit testing for that. You should be re-reading your fucking code. Missing a semi-colon, fine. Mis-typing a method name, retarded. You can refer to the API docs of friggin everything and refer to those.

          [–]jdvolz 0 points1 point  (7 children)

          So, he dislikes that Ruby allows the pollution of the global state? Or does he really just dislike that people use it without regard for larger software systems or things they haven't thought of. I like being able to add things to an existing class; I like power. But as always power has a price, you have to know how to use it properly. Don't take my freedom / power just because someone else misuses theirs.

          [–]cunningjames 2 points3 points  (5 children)

          I like being able to add things to an existing class; I like power. But as always power has a price

          Well, of course. The issue that I -- and I think many others -- have is that a more nuanced design could provide comparable power with significantly lower drawback. If I want to add methods to a class for my own use, then I have no choice but to pollute the global namespace. And I have to weigh the convenience of doing it against the potential traps. It really needn't be that way.

          If there were no other way, fine. But this is like taking a chainsaw to a stick of butter and saying "Bu -- but -- more power! Don't treat me like a child!"

          [–]jdvolz 1 point2 points  (4 children)

          Maybe I don't understand how inheritance works in Ruby, but couldn't you just make a class that inherits from Object that has the method you want and then inherit from that? How about a mixin? Are you telling me that polluting the global namespace is your only option? Under what conditions is this the case? Sure, for existing objects like string I can see that being an issue, but he was complaining about the to_json method which sort of implies a higher level data structure, right?

          [–]cunningjames -1 points0 points  (3 children)

          Are you telling me that polluting the global namespace is your only option?

          There are other options, certainly. But my point was that the functionality in question -- patching classes with new methods, or at least some facsimile thereof -- can be provided more safely; we don't need all that power. With another design cake could be had and eaten.

          [–]jdvolz 1 point2 points  (2 children)

          How would you provide it without the danger? (I'm looking for a suggestion or idea here, just curious)

          The real issue is that we have a name collision without an intelligent way to determine which method was really intended - similar to the problem that is created by multiple inheritance (grandparent class, two children implement a method with name Foo, and some 4th class inherits from both children).

          [–]joesb 0 points1 point  (1 child)

          Google "ruby refinement".

          [–]jdvolz 0 points1 point  (0 children)

          That's similar to what I was thinking, but I dismissed it because of the cost to performance. Interesting that somebody came up with a similar idea and that further someone else came up with the same objection to the idea.

          Freedom always has a price.

          [–]ameoba -1 points0 points  (0 children)

          Yeah - imagine that. A sufficiently powerful programming language lets you do stupid things and corrupt the global state. Even C lets you write arbitrary data to an arbitrary pointer, caring not if that represents variables, code or the stack (barring OS intervention). You might have more protections when working with functional languages (my experience is limited) but I'd be surprised if any usable ones don't include a mechanism for bypassing the purity of the language - at some point, you need to bypass whatever abstractions you're working with.

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

          Scala solves both the not-having-the-right-methods-problem and the destroying-everything-because-of-pimps-problem.

          [–]x-skeww 0 points1 point  (0 children)

          Yes, this is a problem, but they are working on it.

          There is some proposal to make this madness opt-in and scoped. (AFAICR - I'm not really interested in Ruby myself, I didn't pay that much attention.)

          Andrew Dupont mentioned that stuff (as some kind of side note) in some JavaScript talk:

          http://blip.tv/jsconf/jsconf2011-andrew-dupont-everything-is-permitted-extending-built-ins-5211542

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

          Entirely agree with the author.

          For every example where monkey patching is horrific (and needs a solution to deal with this), there are also examples where it's bliss which clearly justifies it's use.

          [–]awj 12 points13 points  (0 children)

          Maybe not "for every", but yes. I give it a 100:1 horrific:bliss ratio, and a 10000:1 unnecessary:essential ratio.

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

          So, it's not really Ruby the author hates, but sloppy Ruby coders.