4 ms·
>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 m
by 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/).
- voidlogic 14y agoSide note, duck typing is not inherently slow. Some people assume since many duck-typed languages are slow that there is some causation going on. Go is way faster than Ruby and extensively uses duck typing everywhere (but is also statically typed and not interpreted-). My point is duck typing is not the reason Ruby is so slow.
- thedudemabry 14y agoInteresting point. I never considered whether duck typing was possible in a statically-typed language. I've always used it in concert with interpreted languages. I imagine it could take a significant amount of pain away from systems programming (I'm looking at you, COM).
- micampe 14y agoit's usually called structural typing in more strongly typed languages like Go or Ocaml.
- bascule 14y agoRuby decouples the method that was requested (the "message" in Smalltalk OO parlance) from the one that is executed. This allows for a number of neat patterns, like forward invocation, where one object can specify a set of messages to be sent to another object (or method!), or delegation, where an object can opt to handle a subset of messages and pass all others on to an underlying object (or method!). Delegation (especially with the extreme simplicity of SimpleDelegator) seems like the obvious solution here, at least to me, but some people prefer to use cache-busting mixins instead.