Inverse Operation of Module#include

Hi list,

Is there a built-in inverse operation of Module#include? Currently I
have:

class A
end

module B
def foo
:b
end
end

module C
def foo
:c
end
end

a = A.new

class A
include B
end
p a.foo # => :b

class A
include C
end
p a.foo # => :c

class A
include B
end
p a.foo # => :c

So if module B has already been mixed in, it cannot be re-included again
thus the foo method is not redefined to B#foo in the last include
operation. Thus occurs to me when I use Inversion of Control (or
dependency injection) to switch between various implementations of a
certain interface. I was thinking that if I can somehow “exclude” the
module and include it again then the problem would be solved, and hence
the question.

Or better yet, is there another way to achieve this kind of
implementation switching?

Regards,

Su

Maybe you want to undef the method before including a module.

I think there unfortunately is not.

It would be neat if behaviour could be reversed easily on objects.

On Dec 1, 2011, at 22:57, Su Zhang [email protected] wrote:

Is there a built-in inverse operation of Module#include? Currently I have:

My “un” gem will do the trick, but there is nothing built in

I would suggest an Adapter pattern use here. IF there is something that
has
functionality that you want to have shared, and one thing changes, I
would
make different subclasses. Example:

class Team # Base class

def play
raise “You should use a subclass of Team.”
end

end

class FootballTeam < Team # Adapter to a football team

def play
play_football
end

end

class BaseballTeam < Team # Adapter to a baseball team

def play
play_baseball
end

end

On Fri, Dec 2, 2011 at 3:24 AM, Ryan D. [email protected]
wrote:

On Dec 1, 2011, at 22:57, Su Zhang [email protected] wrote:

Is there a built-in inverse operation of Module#include? Currently I
have:

My “un” gem will do the trick, but there is nothing built in


Sincerely,

Isaac S.
Section C-4B Vice Chief, Order of the Arrow
Vice Chief of Administration, Tecumseh #65
Eagle Scout

Abstract base classes are silly in Ruby; why bother with that
inheritance? Just take advantage of duck typing.

The Team class is totally useless.

BTW, what do you want to achieve, switch interface at run-time or
switch implementation at run-time?

On 12/2/2011 2:35 AM, Yong Li wrote:

Maybe you want to undef the method before including a module.

I tried that, but that will not remove the mixed-in module from the
inheritance chain, so including that same module again still does
nothing. The methods I undef’ed will simply be marked undefined and the
caller will no longer be able to call them.

On 12/2/2011 2:51 AM, Yong Li wrote:

BTW, what do you want to achieve, switch interface at run-time or
switch implementation at run-time?

The latter. In my example code the interface `foo’ is not changed but
there exists several implementations.

On 12/2/2011 3:24 AM, Ryan D. wrote:

My “un” gem will do the trick, but there is nothing built in

That’s good to know, I will definitely give it a try :slight_smile:

The way I have it implemented, but if it were to have a lot of
functionality, it may be worth using this pattern.

However, I am a noob, and I am inclined to differ to you.

On Fri, Dec 2, 2011 at 7:49 AM, Steve K.
[email protected]wrote:

Abstract base classes are silly in Ruby; why bother with that
inheritance? Just take advantage of duck typing.

The Team class is totally useless.


Sincerely,

Isaac S.

On Fri, Dec 2, 2011 at 1:49 PM, Steve K.
[email protected]wrote:

Abstract base classes are silly in Ruby; why bother with that
inheritance? Just take advantage of duck typing.

The Team class is totally useless.

Steve,

Could you point to an example or description of why you consider
abstract
base classes pointless?

I was under the impression that it does make sense to have an abstract
base class that has a number of generic methods and then derived
classes:

  • add some specific methods
  • add some specific attributes
  • override some of the inherited methods

I have a specific example I was just implementing with an abstract
base class for an “account” (think “bank account”). There are different
derived classes, e.g. for simple money, but also for credits. Certain
functions are generic (e.g. balance), but certain functions are specific
(e.g. put funds on the account will use decimals for “money”, but only
accept integers for “credits”). I have put some demo code below.

Very curious to hear how this design could be improved with duck typing.

Many thanks,

Peter

+++++++++++++++++++++++
demo code:

$ cat derived.rb
class Account

require ‘bigdecimal’

def initialize
@balance = 0
end

def balance
@balance
end

def put(amount)
# do some locking
@balance += amount
# release lock
end
end

class MoneyAccount < Account
def put(amount)
raise “you can only put decimal amounts in a MoneyAccount” unless
amount.is_a?(BigDecimal)
super
end
end

class CreditAccount < Account
def put(amount)
raise “you can only put integer amounts in a CreditAccount” unless
amount.is_a?(Integer)
super
end
end

$ irb
1.9.3p0 :001 > require ‘./derived.rb’
=> true
1.9.3p0 :002 > ma = MoneyAccount.new
=> #<MoneyAccount:0x9d3b9f0 @balance=0>
1.9.3p0 :003 > ma.put 3.14
RuntimeError: you can only put decimal amounts in a MoneyAccount
from /home/peterv/data/derived.rb:23:in put' from (irb):3 from /home/peterv/.rvm/rubies/ruby-1.9.3-p0/bin/irb:16:in
1.9.3p0 :004 > ma.put(BigDecimal.new(“3.14”))
=> #BigDecimal:9c2fd90,‘0.314E1’,18(36)
1.9.3p0 :005 > ma.balance
=> #BigDecimal:9c2fd90,‘0.314E1’,18(36)
1.9.3p0 :006 > ma.balance.to_s
=> “0.314E1”
1.9.3p0 :007 > ca = CreditAccount.new
=> #<CreditAccount:0x9c2591c @balance=0>
1.9.3p0 :008 > ca.balance
=> 0
1.9.3p0 :009 > ca.put(BigDecimal.new(“2.71”))
RuntimeError: you can only put integer amounts in a CreditAccount
from /home/peterv/data/derived.rb:30:in put' from (irb):9 from /home/peterv/.rvm/rubies/ruby-1.9.3-p0/bin/irb:16:in
1.9.3p0 :010 > ca.put(36)
=> 36
1.9.3p0 :011 > ca.balance
=> 36

On 12/2/2011 6:22 AM, Isaac S. wrote:

end
Hi Issac,

What if Team inherits from Group, and both FootballTeam and BaseballTeam
depend on some common interface defined in both Team and Group, and I
want to alter the implementations for Group at runtime?

For example:

class Group
def cheer
# drink_beer or have_barbecue?
end
end

class Team < Group
def consult
analyze_tactics
end
end

class FootballTeam < Team
def cheer
super
shout
end
end

class BaseballTeam < Team
def cheer
super
roar
end
end

team = FootballTeam.new
team.cheer
team.consult

team = BaseballTeam.new
team.cheer
team.consult

Both types of team share the common Team#consult method, but I cannot be
sure if I should do drink_beer or have_barbecue in Group#cheer until
runtime, and I want to separate them as different implementations. With
module mixin, all the implementations are nicely injected into the
inheritance chain. If we derive from Group, the derived class will not
be on the same inheritance chain as FootballTeam or BaseballTeam.

Su

Peter V. wrote in post #1034787:

Very curious to hear how this design could be improved with duck typing.

Correct me if I’m wrong, but I think Steve was trying to say that using
abstract base classes with purely abstract methods are useless. I
mean, it’s just there to raise
an exception, but the exception would have been raised anyway (a
NotMethodError). In Ruby, interface is everything, so instead of seeing
if something is a kind_of? Team, just check if it responds_to? :play and
code the interface that way.

In your case, the base class is taking care of things that all accounts
do. In my view, this is a fine, and it’s not really a ruby abstract
base class because you’re not raising explicit exceptions on abstract
methods (you have no abstract methods), and you can still instantiate
that class. In your case, this is just a base class, not an ‘abstract’
base
class. If however, you’re providing real implementation
through actual methods that do stuff, I think Steve would agree that we
should move base implementations to a superclass.

Ruby seems to promote polymorphism through duck-typing more than
checking i f something belongs to a certain base class.

As for passing through the module chain, i came up with a quick hacky
way of doing it after reading through this thread.

class A
end

module B
MODULE = :b
def foo(mod=nil)
if respond_to? :passable?
return(super) unless mod == MODULE
end
‘from module B’
end
end

module C
MODULE = :c
def foo(mod=nil)
if respond_to? :passable?
return(super) unless mod == MODULE
end
‘from module C’
end
end

a = A.new

class A
include B
end

p a.foo => ‘from module B’

class A
include C
end

p a.foo => ‘from module C’

module Passable
def passable?
true
end
end

a.extend Passable

p a.foo :b => ‘from module B’
p a.foo :c => ‘from module C’

Pretty straightforward, and could be rewritten fairly easily to pass all
methods on to super if that were required. Tell me what you guys think.
I think undef’ing a method is fairly brutal in this situation.

-Luke

On Fri, Dec 2, 2011 at 7:47 PM, luke gruber [email protected] wrote:

Aha, thanks for the detailed reply.

Now, just for my understanding of duck typing, assume both derived
classes
(BaseballTeam and FootballTeam) have a method with the name :play, but
they require a different argument signature (like in my put example
where
MoneyAccount#play needs a BigDecimal and CreditAccount#play needs an
integer). Should I then still use the class to determine how to call the
method, or should I better name these 2 methods differently?

In your case, the base class is taking care of things that all accounts
do. In my view, this is a fine, and it’s not really a ruby abstract
base class because you’re not raising explicit exceptions on abstract
methods. In your case, this is just a base class, not an ‘abstract’ base
class. Abstract base classes have purely abstract methods that are just
useless in ruby. If however, you’re providing real implementation
through actual methods that do stuff, this isn’t an abstract base class
but just a base class.

OK, got it. So on the criterion of actual functionality, it is not an
abstract
base class, but still, it is not the intention to ever create an
instance
of the Base class, only of the derived classes.

Thx,

Peter

If you want to redefine a function, and the adapter pattern does not
seem
like a fit, I might use something like this:

Group.class_eval do
def cheer
# Then you can redefine your method here.
end
end

Then, you probably can consider making different implementations as
“objects” and switch these objects in A at run-time.

class A
def setImpl(implementation)
@impl=implementation
end

def foo
impl.foo
end
#other methods of the interface
end

class ImplB
include B
end
class ImplC
include C
end

#at run-time
a = A.new
a.setImpl(ImplB.new)
a.foo #=> call b.foo

a.setImpl(ImplC.new)
a.foo #=> call c.foo

a.setImpl(ImplB.new)
a.foo #=> call b.foo

of course, you may need further modifications if module B accesses A’s
private methods

On Sat, Dec 3, 2011 at 1:54 AM, Su Zhang [email protected]
wrote:

On 12/2/2011 2:51 AM, Yong Li wrote:

BTW, what do you want to achieve, switch interface at run-time or
switch implementation at run-time?

The latter. In my example code the interface `foo’ is not changed but there
exists several implementations.


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Li, Yong
Fushan Road 450, Room 9A
Pudong New Area,
Shanghai, 200122
P.R.China

phone: +86-15021003368
email: [email protected]
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

On Fri, Dec 2, 2011 at 6:57 AM, Su Zhang [email protected]
wrote:

Hi list,

Is there a built-in inverse operation of Module#include? Currently I have:

[snip code]

Regards,

Su

You could do this:

#!/usr/bin/env ruby
class A
end

module B
def self.included(other)
other.class_eval {
def foo
:b
end
}
end
end

module C
def self.included(other)
other.class_eval {
def foo
:c
end
}
end
end

a = A.new

class A
include B
end
p a.foo # => :b

class A
include C
end
p a.foo # => :c

class A
include B
end
p a.foo # => :b

Regards,
Sean

On Sun, Dec 4, 2011 at 7:23 PM, Robert K.
[email protected]wrote:

  • add some specific methods
  • add some specific attributes
  • override some of the inherited methods

=> Template method pattern

Thx for that pointer. I am still not clear what Steve exactly meant with
his comment.

case
end
end

class MoneyAccount < Account
def ensure_proper_amount(amount)
raise “you can only put decimal amounts in a MoneyAccount” unless
BigDecimal === amount
end
end

If I understand correctly the improvement in your version is that you
only
override exactly that part that is different for the derived class vs.
the
generic
class (the “ensure_proper_amount” validation). Nice, thanks.

With respect to the locking strategy you propose. I am actually reading
and
writing the amount from an SQL database with ActiveRecord, from
potentially
multiple parallel processes (multiple Rails processes from passenger,
potentially even on different servers). Am I correct that this locking
strategy with
MonitorMixin would not be relevant (default Rails passenger set-up with
multiple processes, but no multi-threading inside a process). I believe
a
different locking strategy would be required, e.g. acquiring a lock from
the
database or from another source of locking that is shared between the
different processes (multiple processes per server and multiple
servers).

Thanks,

Peter

On Sun, Dec 4, 2011 at 8:04 PM, Peter V.
[email protected] wrote:

I was under the impression that it does make sense to have an abstract

Not really duck typing, but this is how template method could look in this
case

If I understand correctly the improvement in your version is that you only
override exactly that part that is different for the derived class vs. the
generic
class (the “ensure_proper_amount” validation). Nice, thanks.

Correct. That’s what template method pattern is about: you have a
method which gives the overall structure and sub classes fill in only
missing methods (which would be abstract in a language like Java).

You’re welcome!

With respect to the locking strategy you propose. I am actually reading and
writing the amount from an SQL database with ActiveRecord, from potentially
multiple parallel processes (multiple Rails processes from passenger,
potentially even on different servers). Am I correct that this locking
strategy with
MonitorMixin would not be relevant (default Rails passenger set-up with
multiple processes, but no multi-threading inside a process). I believe a
different locking strategy would be required, e.g. acquiring a lock from the
database or from another source of locking that is shared between the
different processes (multiple processes per server and multiple servers).

Yes, of course. Since there was no concrete hint I chose thread
synchronization as a (hopefully) well known pattern.

Kind regards

robert

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs