4 ms·
I'm not a Ruby programmer, so maybe I'm misunderstanding the article -- are we talking about changing an object's class hierarchy after it's already been instan
by minimax 14y ago
I'm not a Ruby programmer, so maybe I'm misunderstanding the article -- are we talking about changing an object's class hierarchy after it's already been instantiated and then complaining that it's the performance aspect that is pathological? That sounds like a completely insane way of writing software to me.
- FooBarWidget 14y agoYes, that is what the author is talking about. I'm not sure what his point is though. This fact has been known for years and if you care about performance, you simply don't modify the class hierarchy.
- urbanautomaton 14y agoIt doesn't seem to be widely acknowledged amongst people promoting this particular style of DCI as a good way to write Rails app, so I'd say the point is valid, even if the title is overstated. There are also quite a few other very popular gems that make heavy use of #extend at runtime for non-DCI purposes, including Haml and Paperclip, so I don't think it's fair to say that this is common knowledge (at least in the Ruby community).
- lnanek2 14y agoIt isn't so odd in Ruby. Ruby has always been a duck typing land. If it quacks, it is a duck. There's even a method missing handler so you can respond to any method call whatsoever. People can and do add methods directly to even built-in classes as well, the equivalent of modifying the class prototype in Javascript. So method calls are considered more messages in Ruby and saying a class will respond differently to a message after it has more data about what it is, a certain blog for example, isn't so strange to Ruby programmers.
- cube13 14y ago>It isn't so odd in Ruby. Ruby has always been a duck typing land. If it quacks, it is a duck. There's even a method missing handler so you can respond to any method call whatsoever. What's the benefit of this kind of typing, though? I'm pretty much just a C hacker these days, so I'm pretty ignorant about Ruby, but does this apply to the object or to the class? It seems simpler, especially on a conceptual level, to just initialize the the duck with everything it could possibly need to be a duck, rather than adding things dynamically.
- cdcarter 14y agoYou could do it on the object level or the class level. Metaprogramming like this generally is most useful for powering "DSLs" and other ways of expressing not-quite-imperative-code in Ruby.
- rahoulb 14y ago>It seems simpler, especially on a conceptual level, to just initialize the the duck with everything it could possibly need to be a duck, rather than adding things dynamically. Yes, it is simpler conceptually. But, in Rails especially where there is a tradition of moving all your application functionality into the "model" layer, you could end up with a single class that is thousands of lines of code long. For example, a User class, with a load of code about resetting passwords, that is only used in one relatively rare circumstance. So instead, DCI says you should separate the password-reset stuff into a separate module and only add it in when needed. Both User and PasswordReset are simpler and easier to understand and only come together when needed. (As I said elsewhere, I prefer to wrap a decorator around the User to achieve the same thing).
- nevinera 14y ago>It seems simpler, especially on a conceptual level, to just initialize the the duck with everything it could possibly need to be a duck, rather than adding things dynamically. It is simpler, on a conceptual level. On an implementation level however, it quickly becomes non-simple. One of the fundamental modularity concepts is 'separation of concerns' - this isn't something you always need to do, but when a concern (a scoped set of functionality) grows large, it should be implemented separately, to keep the conceptual complexity of individual abstractions and implementations minimal. If I implement all of the logic for handling conditions, importing data, extracting reports, managing permissions, serialization, and resource handling in the same object, it's a very complicated object. I have no way without getting a full mental model of the thing in my head that changing X about it won't break Y, or what parts of code depend on the structure of the results of calling Z. There are plenty of ways to skin that cat, and different ones are more appropriate in different places. Often it's correct to extract the logic into a generalizable mixin, which in Ruby would be a module, and then include it into the class. Sometimes it's better to extract the logic and the concept it represents into another class that has a relationship with the original one. And sometimes it's better to separate the logic and code into a 'context' as DCI describes - I generally prefer Decorators for this, but the Rails community seems to lean toward using modules here also, largely on the weight of DHH's opinion (app/concerns/).
- louischatriot 14y agoThat's something that happens a lot in the JS/nodejs world too. It has the potential to be disastrous if you're not rigorous, that's for sure. But it still enables very concise and maintenable code.
- rahoulb 14y agoIt depends. Is your app CPU-bound? If so, then DCI probably isn't a great idea for you. In fact, building it in Ruby may not be the best idea. But if your app is IO-bound (like most Rails apps), huge and it takes new developers weeks to get up to speed, then the gains from having a simple, modular code-base should save you developer-time (and hence salaries), which are much more expensive than CPUs. Having said that, I tend to use SimpleDelegator instead of dynamically injecting stuff into objects. EDIT: added 'ruby not being the best idea if CPU bound'
- mbetter 14y agoThis DCI stuff sounds like a quick way to make an app CPU-bound, if it wasn't already.
- rahoulb 14y agoRuby may be slow but my apps still spend more time waiting on complex database queries than anything else (unless I'm using the Jbuilder gem to build JSON outputs, in which case I might as well make a cup of tea waiting for a call to return)
- jjwiseman 14y agoThis also has a precedent in Lisp, see change-class: http://clhs.lisp.se/Body/f_chg_cl.htm http://clhs.lisp.se/Body/f_chg_cl.htm There's even a protocol for notifying instances that their class has changed so they can make any necessary adjustments: http://clhs.lisp.se/Body/07_bb.htm http://clhs.lisp.se/Body/07_bb.htm