Module philosophy

Discussion in 'Ruby' started by Leslie Viljoen, Jun 4, 2008.

  1. Sorry to beat a dead horse, but to confirm: the only way to mix a
    module into an already
    existing class it to reopen it with something (ugly) like this:

    class String; include Crc; end

    (1) Is that right?

    And then to mix a module into an instantiated object, you can use
    extend, and that
    modifies the one object. (2) Philosophically, is there any reason why
    extend can't be used
    in the same way on classes? (ie. String.extend(Crc))


    One other question (3), below is an example of my SelfCrc module. This module
    works well when included into String, but extend doesn't work because that
    only modifies the one object and .crc16_ok? below tries to call .get_crc16
    on a new string that it creates, which fails.

    I can modify it to work like so:

    def crc16_ok?
    first_part = self[0..-3]
    first_part.extend(SelfCrc)
    first_part.get_crc16 == get_terminating_crc16
    end

    ...is that the right way to make this module work properly? Or are
    some modules just not suitable for extend?


    module SelfCrc

    # Returns the CCITT CRC16 for the current object
    #
    def get_crc16
    @@crctab ||= CrcTab.new
    @@crctab.get(self)
    end

    # Converts the last two characters of this string to
    # a numeric CRC and returns it
    #
    def get_terminating_crc16
    (self[-2, 1][0] << 8) + (self[-1, 1][0])
    end

    # Calculates a CRC for the string, converts it into two
    # characters and adds them to the end of the string
    #
    def add_terminating_crc16!
    replace(self + get_crc16.to_s16)
    end

    # Removes the last two characters from the string
    #
    def remove_terminating_crc16!
    replace(self[0..-3])
    end

    # Extracts two characters from the end of the string, converts
    # them to a numeric CRC and compares that CRC to the CRC of
    # the rest of the string. Returns true if the CRC is correct.
    #
    def crc16_ok?
    self[0..-3].get_crc16 == get_terminating_crc16
    end
    end



    Thanks!

    Leslie
    Leslie Viljoen, Jun 4, 2008
    #1
    1. Advertising

  2. On Wednesday 04 June 2008, Leslie Viljoen wrote:
    > modifies the one object. (2) Philosophically, is there any reason why
    > extend can't be used
    > in the same way on classes? (ie. String.extend(Crc))


    Because String.extend(Crc) would add the instance methods of the Crc module as
    class methods of String, not as instance methods. This would mean you could
    do:

    String.method_defined_in_crc

    but not

    "hello".method_defined_in_crc

    If you don't like the idea of reopening the class, you can use include with
    send:

    String.send :include, Crc

    Stefano
    Stefano Crocco, Jun 4, 2008
    #2
    1. Advertising

  3. On 4 Jun., 15:49, Leslie Viljoen <> wrote:
    > Sorry to beat a dead horse, but to confirm: the only way to mix a
    > module into an already
    > existing class it to reopen it with something (ugly) like this:
    >
    > class String; include Crc; end
    >
    > (1) Is that right?
    >
    > And then to mix a module into an instantiated object, you can use
    > extend, and that
    > modifies the one object. (2) Philosophically, is there any reason why
    > extend can't be used
    > in the same way on classes? (ie. String.extend(Crc))


    You need to be able to distinguish between importing class methods and
    importing instance methods (see Stefano's reply).

    > One other question (3), below is an example of my SelfCrc module. This module
    > works well when included into String, but extend doesn't work because that
    > only modifies the one object and .crc16_ok? below tries to call .get_crc16
    > on a new string that it creates, which fails.
    >
    > I can modify it to work like so:
    >
    > def crc16_ok?
    > first_part = self[0..-3]
    > first_part.extend(SelfCrc)
    > first_part.get_crc16 == get_terminating_crc16
    > end
    >
    > ..is that the right way to make this module work properly? Or are
    > some modules just not suitable for extend?


    If your module expects to be present in all instances of the class
    then including is the only reasonable way to do it IMHO.

    I can think of a number of other designs which would not have this
    issue but since I do not exactly know what your module does
    (especially CrcTab which could be a kind of cache) I am reluctant to
    enumerate them.

    Assuming that you want to store strings along with their CRC's I'd
    rather have a separate class that has a String and a CRC. That seems
    more natural to me. This would also avoid the issue that you cannot
    easily determine whether a String does contain its CRC or not etc.

    Kind regards

    robert
    Robert Klemme, Jun 4, 2008
    #3
  4. On Wednesday 04 June 2008 08:49:48 Leslie Viljoen wrote:
    > Sorry to beat a dead horse, but to confirm: the only way to mix a
    > module into an already
    > existing class it to reopen it with something (ugly) like this:
    >
    > class String; include Crc; end
    >
    > (1) Is that right?


    Short answer: You'll have to mess with it dynamically, but that is far from
    the only syntax to do so. Other obvious ones:

    String.class_eval { include Crc }
    String.send :include, Crc

    And there are always stranger things like:

    "foo".class.class_eval { include Crc }

    > And then to mix a module into an instantiated object, you can use
    > extend, and that
    > modifies the one object.


    Yes, but keep in mind: "include"ing a module into a class will affect all
    existing and future instances of that class, and of any subclasses. So you're
    probably not going to extend if you include.

    > (2) Philosophically, is there any reason why
    > extend can't be used
    > in the same way on classes? (ie. String.extend(Crc))


    As others have said, they do different things -- include adds instance methods
    to a class, and extend adds methods to an object.

    It's a tricky concept, but remember that classes are objects, too. So:

    some_string.extend(Crc) # will define some_string.crc16_ok?
    String.extend(Crc) # will define String.crc16_ok?

    So, extend works on the actual object you use it on, and include works on any
    instances of it. You could do this, for example:

    Class.send :include, Crc
    # Now all classes will have a crc16_ok? class method, for example:
    String.crc16_ok?

    That's probably not what you want.

    > ...is that the right way to make this module work properly? Or are
    > some modules just not suitable for extend?


    I think that comes down to personal philosophy -- I haven't seen (or
    used) 'extend' a whole lot. It seems most useful when you'd only want to
    apply it to a single object, and then, I'd usually use instance_eval instead.

    On the other hand, including it into String means you're affecting all
    Strings, and polluting String's method namespace. It means that no one else
    can define String#get_crc16.

    The other way would be to use a separate class -- either something which
    contains both a String and a CRC (as Robert suggested), or something which
    inherits from String.

    And either way, depending on how much work you want to do, you could always
    override all methods on String which return a String, and force them to
    either return an extended String, or return a CrcString, depending on how you
    decide to do it.
    David Masover, Jun 4, 2008
    #4
  5. Holy macaroni, thanks for these replies!

    What I am trying to accomplish here is the optional modification of
    core classes. So my CRC lib can handle useful calculations, and
    optionally add convenient methods to String and Fixnum too.

    That way people can have the convenience if they like, but they must
    explicitly authorise it with String.send:)include ..). It seems like a
    good plan to me, but the lack of a public String.include() method
    makes me think this is a very rare plan.

    These strings with CRC's on the ends are coming in from sockets, and I
    have to check them, extract them, use them and then put CRC's on the
    end of the replies before sending them out. In this case it's quite
    nice to do:

    begin
    msg, sender = @socket.recvfrom(1500)
    end while (!msg.crc16_ok?)
    msg.remove_terminating_crc16!
    ...

    - but it's true that I might forget to remove that crc. So perhaps
    decend from String like you say:

    begin
    msg, sender = @socket.recvfrom(1500)
    msg = CrcString(msg)
    end while (!msg.crc16_ok?)
    (now use msg directly)

    - and I'd know immediately if I'd forgotten to construct the CrcString
    because crc16_ok? would fail.


    And then a third option would be to modify Socket:
    class Socket
    def recv_checked(n)
    CrcString(recvfrom(n))
    end
    end

    ..which I'd again attempt by providing a module that I'd
    Socket.send:)include, CrcSocket)

    Or once again I could override both String and Socket to make
    CrcString and CrcSocket which returns CrcStrings. You're never short
    on options with Ruby!

    Les









    On 6/4/08, David Masover <> wrote:
    > On Wednesday 04 June 2008 08:49:48 Leslie Viljoen wrote:
    >> Sorry to beat a dead horse, but to confirm: the only way to mix a
    >> module into an already
    >> existing class it to reopen it with something (ugly) like this:
    >>
    >> class String; include Crc; end
    >>
    >> (1) Is that right?

    >
    > Short answer: You'll have to mess with it dynamically, but that is far from
    > the only syntax to do so. Other obvious ones:
    >
    > String.class_eval { include Crc }
    > String.send :include, Crc
    >
    > And there are always stranger things like:
    >
    > "foo".class.class_eval { include Crc }
    >
    >> And then to mix a module into an instantiated object, you can use
    >> extend, and that
    >> modifies the one object.

    >
    > Yes, but keep in mind: "include"ing a module into a class will affect all
    > existing and future instances of that class, and of any subclasses. So
    > you're
    > probably not going to extend if you include.
    >
    >> (2) Philosophically, is there any reason why
    >> extend can't be used
    >> in the same way on classes? (ie. String.extend(Crc))

    >
    > As others have said, they do different things -- include adds instance
    > methods
    > to a class, and extend adds methods to an object.
    >
    > It's a tricky concept, but remember that classes are objects, too. So:
    >
    > some_string.extend(Crc) # will define some_string.crc16_ok?
    > String.extend(Crc) # will define String.crc16_ok?
    >
    > So, extend works on the actual object you use it on, and include works on
    > any
    > instances of it. You could do this, for example:
    >
    > Class.send :include, Crc
    > # Now all classes will have a crc16_ok? class method, for example:
    > String.crc16_ok?
    >
    > That's probably not what you want.
    >
    >> ...is that the right way to make this module work properly? Or are
    >> some modules just not suitable for extend?

    >
    > I think that comes down to personal philosophy -- I haven't seen (or
    > used) 'extend' a whole lot. It seems most useful when you'd only want to
    > apply it to a single object, and then, I'd usually use instance_eval
    > instead.
    >
    > On the other hand, including it into String means you're affecting all
    > Strings, and polluting String's method namespace. It means that no one else
    > can define String#get_crc16.
    >
    > The other way would be to use a separate class -- either something which
    > contains both a String and a CRC (as Robert suggested), or something which
    > inherits from String.
    >
    > And either way, depending on how much work you want to do, you could always
    > override all methods on String which return a String, and force them to
    > either return an extended String, or return a CrcString, depending on how
    > you
    > decide to do it.
    >
    >



    --
    [we need your code-fu] : www.zadic.co.za
    Leslie Viljoen, Jun 4, 2008
    #5
  6. Leslie Viljoen

    Marc Heiler Guest

    > It seems like a good plan to me, but the lack of a
    > public String.include() method makes me think this is a
    > very rare plan.


    It might be rare because in reality this is not so much a
    problem IMHO, despite some people claiming it could be. (I had
    an angry IRC "discussion" with a C# proponent over this, I
    really dislike people iterating about the "danger" of concepts
    despite others applying them for many years without any
    problem ... )

    What could be nice is to store different "states" of ruby classes
    and restore to them at user's will. (Or additionally restore the
    "start" the state of slowly "evolved" ruby classes as well).

    I mean both standard classes (more important) and user-built
    ones (less important, IMHO). It is interesting to see that
    someone like the sandbox of _why was more an afterthought
    than an initial design idea. I think there is plenty of
    more room in this direction, who knows... maybe in a few
    years. Ruby is like the OOP language that goes towards
    new paradigms - with class derived objects - the most easiest.

    Ruby is great but it is not perfect for everyone or every
    use case. And since 99% of new languages will have crappy
    syntax, the most likely language to beat Ruby will be ...

    Ruby! :)
    --
    Posted via http://www.ruby-forum.com/.
    Marc Heiler, Jun 4, 2008
    #6
  7. On Wednesday 04 June 2008 13:53:26 Leslie Viljoen wrote:
    > Holy macaroni, thanks for these replies!
    >
    > What I am trying to accomplish here is the optional modification of
    > core classes. So my CRC lib can handle useful calculations, and
    > optionally add convenient methods to String and Fixnum too.


    Probably included, then, rather than extended.

    > That way people can have the convenience if they like, but they must
    > explicitly authorise it with String.send:)include ..). It seems like a
    > good plan to me, but the lack of a public String.include() method
    > makes me think this is a very rare plan.


    Generally, people don't expect to have to do more than a require to have the
    library ready to use. So I'd do that yourself, somewhere in the library file.
    David Masover, Jun 4, 2008
    #7
  8. Perhaps people don't have this problem very often, but I once spent
    three days puzzling over a Rails app that worked fine on my computer,
    but not at the web host. A library had been installed by the host that
    created a class that was require'd somewhere down the line. That class
    had the same name as one of my models, and it totally killed my app.

    Having a dynamic base environment works fine until there's a clash. As
    the code base grows, so do the chances of a clash and also the
    difficulty in finding it.


    On 6/4/08, David Masover <> wrote:
    > On Wednesday 04 June 2008 13:53:26 Leslie Viljoen wrote:
    >> Holy macaroni, thanks for these replies!
    >>
    >> What I am trying to accomplish here is the optional modification of
    >> core classes. So my CRC lib can handle useful calculations, and
    >> optionally add convenient methods to String and Fixnum too.

    >
    > Probably included, then, rather than extended.
    >
    >> That way people can have the convenience if they like, but they must
    >> explicitly authorise it with String.send:)include ..). It seems like a
    >> good plan to me, but the lack of a public String.include() method
    >> makes me think this is a very rare plan.

    >
    > Generally, people don't expect to have to do more than a require to have the
    > library ready to use. So I'd do that yourself, somewhere in the library
    > file.
    >
    >



    --
    [we need your code-fu] : www.zadic.co.za
    Leslie Viljoen, Jun 4, 2008
    #8
  9. Leslie Viljoen

    Donald Ball Guest

    On Wed, Jun 4, 2008 at 3:20 PM, Leslie Viljoen <> wrote:
    > Perhaps people don't have this problem very often, but I once spent
    > three days puzzling over a Rails app that worked fine on my computer,
    > but not at the web host. A library had been installed by the host that
    > created a class that was require'd somewhere down the line. That class
    > had the same name as one of my models, and it totally killed my app.
    >
    > Having a dynamic base environment works fine until there's a clash. As
    > the code base grows, so do the chances of a clash and also the
    > difficulty in finding it.


    I had a similar experience a while back wherein I inadvertently
    overrode a method defined by ActiveRecord somewhere. At the time, I
    wondered if it might be a good idea to have the ruby interpreter warn
    when a method was overridden, unless either the original method was
    flagged as silently over-ridable (e..g Object.to_s) or the overriding
    method was flagged as intentional (e.g. overriding
    ActiveRecord::Base.find). It's almost certainly not worth the hassle
    even if the approach is sound, but after spending some hours digging
    through the darker corners of the ActiveRecord code, it seemed like an
    awfully attractive notion.

    - donald
    Donald Ball, Jun 4, 2008
    #9
  10. ruby -w does warn on method redefinitions!

    On 6/4/08, Donald Ball <> wrote:
    > On Wed, Jun 4, 2008 at 3:20 PM, Leslie Viljoen <>
    > wrote:
    >> Perhaps people don't have this problem very often, but I once spent
    >> three days puzzling over a Rails app that worked fine on my computer,
    >> but not at the web host. A library had been installed by the host that
    >> created a class that was require'd somewhere down the line. That class
    >> had the same name as one of my models, and it totally killed my app.
    >>
    >> Having a dynamic base environment works fine until there's a clash. As
    >> the code base grows, so do the chances of a clash and also the
    >> difficulty in finding it.

    >
    > I had a similar experience a while back wherein I inadvertently
    > overrode a method defined by ActiveRecord somewhere. At the time, I
    > wondered if it might be a good idea to have the ruby interpreter warn
    > when a method was overridden, unless either the original method was
    > flagged as silently over-ridable (e..g Object.to_s) or the overriding
    > method was flagged as intentional (e.g. overriding
    > ActiveRecord::Base.find). It's almost certainly not worth the hassle
    > even if the approach is sound, but after spending some hours digging
    > through the darker corners of the ActiveRecord code, it seemed like an
    > awfully attractive notion.
    >
    > - donald
    >
    >



    --
    [we need your code-fu] : www.zadic.co.za
    Leslie Viljoen, Jun 4, 2008
    #10
  11. On Wednesday 04 June 2008 15:20:16 Leslie Viljoen wrote:
    > Perhaps people don't have this problem very often, but I once spent
    > three days puzzling over a Rails app that worked fine on my computer,
    > but not at the web host. A library had been installed by the host that
    > created a class that was require'd somewhere down the line. That class
    > had the same name as one of my models, and it totally killed my app.


    How was it require'd, though?

    That's the thing -- yes, there will be a clash, but it'll very likely be found
    as soon as you require both of them.
    David Masover, Jun 4, 2008
    #11
  12. Leslie Viljoen

    Donald Ball Guest

    On Wed, Jun 4, 2008 at 3:48 PM, Leslie Viljoen <> wrote:
    > ruby -w does warn on method redefinitions!


    True, and I ought to have thought to try that at the time, but unless
    I missed something, there's no way to flag if your overrides are
    intentional or not.

    - donald
    Donald Ball, Jun 4, 2008
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. David Ford
    Replies:
    0
    Views:
    368
    David Ford
    Aug 16, 2003
  2. Roedy Green

    Philosophy

    Roedy Green, Sep 10, 2003, in forum: Java
    Replies:
    1
    Views:
    456
    Chris Uppal
    Sep 10, 2003
  3. zaemin

    The philosophy of exception.

    zaemin, Dec 1, 2003, in forum: Java
    Replies:
    7
    Views:
    453
    Michael Borgwardt
    Dec 3, 2003
  4. ronron

    philosophy : ! vs false

    ronron, Feb 4, 2005, in forum: Java
    Replies:
    31
    Views:
    1,071
    =?ISO-8859-1?Q?S=E9bastien_Auvray?=
    Feb 16, 2005
  5. puzzlecracker

    local class philosophy

    puzzlecracker, Jan 21, 2006, in forum: Java
    Replies:
    12
    Views:
    569
    Roedy Green
    Jan 25, 2006
Loading...

Share This Page