3 ms·
Of the many models of “composition” that are possible I think Ruby’s free-for-all blend of mix-ins and monkey patches is the only one that can drive a maintenan
by emodendroket 3y ago
Of the many models of “composition” that are possible I think Ruby’s free-for-all blend of mix-ins and monkey patches is the only one that can drive a maintenance programmer more insane than a deep hierarchy of inheritance of Java classes.
- shagie 3y agoirb(main):001:0> "bar".foo Traceback (most recent call last): 4: from /usr/bin/irb:23:in `<main>' 3: from /usr/bin/irb:23:in `load' 2: from /Library/Ruby/Gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>' 1: from (irb):1 NoMethodError (undefined method `foo' for "bar":String) Did you mean? for irb(main):002:0> class String irb(main):003:1> def foo irb(main):004:2> "foobar!" irb(main):005:2> end irb(main):006:1> end => :foo irb(main):007:0> "bar".foo => "foobar!" irb(main):008:0> Yes! Let's modify the core library String class on the fly to add new functions to it. There are things about ruby that truly scare me if my goal was to write secure and reasonable code.
- emodendroket 3y agoRight, that’s monkey patching. You run into the real problems when you have multiple people wanting to add them. Ruby isn’t alone in supporting this functionality (you can fiddle with JavaScript prototypes, for instance), but I think it is unique how much it is encouraged (at least in Rails world). I think extension methods are a much better model to achieve something similar.
- shagie 3y agoThere are also some really weird/powerful/voodoo things that you can do when that is combined with the first class environments. The "why Scheme didn't do this": First-class environments - http://funcall.blogspot.com/2009/09/first-class-environments.html http://funcall.blogspot.com/2009/09/first-class-environments... why Ruby did (and wasn't a good idea): Ruby Conf 2011 Keeping Ruby Reasonable https://youtu.be/vbX5BVCKiNs https://youtu.be/vbX5BVCKiNs Consider where you can slip in a block invocation and the following code: def mal(&block) block.call block.binding.eval('a = 43') end a = 42 puts a mal do puts 1 end puts a and that that means that you've got full access to be able to inspect and manipulate all of the variables in scope at the time of the invocation. While that example is rather obvious, it can be done much more subtly too. The power of ruby to do meta programming and by extension some really neat DSLs also provides it with some dangerous tools that are otherwise rather difficult to track down.
- projektfu 3y agoThis is the Smalltalkiness of Ruby. Why have a separate place to put a function that operates only on strings when you can put it in String? Of course, in Smalltalk you might have #trim defined by two different packages and they might conflict. Then what? Maybe you have to manage that complexity. However, it's not much different from having conflicting functions in the global namespace in C, but actually easier to resolve in a given situation.
- emodendroket 3y agoWell, I suppose that's compelling if you're one of the many programmers trying to decide if you will implement your project in Ruby or C.
- projektfu 3y agoYeah, more modern Smalltalks are able to put things in various namespaces so they don't conflict but still generally work as expected. In Smalltalk, adding methods doesn't weigh down a class like in other languages, because method lookup is on-the-fly like in Objective-C, not precalculated and placed in a table.
- psychoslave 3y agoThis doesn’t leverage on the more subtle but all the more elegant type system that Ruby provides. As told just above, since all object also have their own class instance you can extend this instance specific class without polluting the general class it derives from. irb(main):001:1* module Awesomeness irb(main):002:1* def awesome? = :yes irb(main):003:0> end => :awesome? irb(main):004:0> ?Ô.awesome? (irb):4:in `<main>': undefined method `awesome?' for "Ô":String (NoMethodError) from /Users/someone/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/irb-1.4.1/exe/irb:11:in `<top (required)>' from /Users/someone/.asdf/installs/ruby/3.1.2/bin/irb:25:in `load' from /Users/someone/.asdf/installs/ruby/3.1.2/bin/irb:25:in `<main>' irb(main):005:0> ?Ô.extend(Awesomeness).awesome? => :yes irb(main):005:0> ?Ô.awesome? (irb):5:in `<main>': undefined method `awesome?' for "Ô":String (NoMethodError) from /Users/someone/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/irb-1.4.1/exe/irb:11:in `<top (required)>' from /Users/someone/.asdf/installs/ruby/3.1.2/bin/irb:25:in `load' from /Users/someone/.asdf/installs/ruby/3.1.2/bin/irb:25:in `<main>'