Duping a class causes error

Discussion in 'Ruby' started by Trans, Jan 27, 2005.

  1. Trans

    Trans Guest

    Maybe someone can offer me a possible reason for this. I have a set of
    classes in a module called Markers. I have a module method,
    Markers#list, that does nothing more than collects them into an array.
    Then in my program when I do:

    | markers = Markers.list

    It works. But when I do:

    | markers = Markers.list.collect { |m| nm = m.dup ; nm }

    It does not work.

    I don't understand why. Obviously my initial thought is that something
    about my Marker classes must not be shallow, but they're just classes,
    made of methods and have no state, so I don't see how that can be.
    (Actually they do have a small bit of boolean state in a class instance
    var, but I check and it is being duplicated.)
    I just don't get it. Any ideas?

    Thanks,
    T.
    Trans, Jan 27, 2005
    #1
    1. Advertising

  2. "Trans" <> schrieb im Newsbeitrag
    news:...
    > Maybe someone can offer me a possible reason for this. I have a set of
    > classes in a module called Markers. I have a module method,
    > Markers#list, that does nothing more than collects them into an array.
    > Then in my program when I do:
    >
    > | markers = Markers.list
    >
    > It works. But when I do:
    >
    > | markers = Markers.list.collect { |m| nm = m.dup ; nm }


    You can also do:

    markers = Markers.list.collect { |m| m.dup }

    > It does not work.
    >
    > I don't understand why. Obviously my initial thought is that something
    > about my Marker classes must not be shallow, but they're just classes,
    > made of methods and have no state, so I don't see how that can be.


    So Markers.list returns a list of class objects?

    > (Actually they do have a small bit of boolean state in a class instance
    > var, but I check and it is being duplicated.)
    > I just don't get it. Any ideas?


    What exactly goes wrong?

    robert
    Robert Klemme, Jan 27, 2005
    #2
    1. Advertising

  3. Trans

    Trans Guest

    Robert Klemme wrote:
    > "Trans" <> schrieb im Newsbeitrag
    > news:...
    > > Maybe someone can offer me a possible reason for this. I have a set

    of
    > > classes in a module called Markers. I have a module method,
    > > Markers#list, that does nothing more than collects them into an

    array.
    > > Then in my program when I do:
    > >
    > > | markers = Markers.list
    > >
    > > It works. But when I do:
    > >
    > > | markers = Markers.list.collect { |m| nm = m.dup ; nm }

    >
    > You can also do:
    >
    > markers = Markers.list.collect { |m| m.dup }


    Thanks. That true, but the line I ultimately want is:

    | markers = Markers.list.collect { |m| nm = m.dup ; nm.parser = self;
    nm }

    I need to pass the current parser object down to the markers themselves
    b/c I do "reentrant" pasrsing. But obviously I don't want to effect the
    Classes themselves with this state info in case they are used by
    another parser, so I'm duplicating them.

    > > It does not work.
    > >
    > > I don't understand why. Obviously my initial thought is that

    something
    > > about my Marker classes must not be shallow, but they're just

    classes,
    > > made of methods and have no state, so I don't see how that can be.

    >
    > So Markers.list returns a list of class objects?


    Yes. Here, Markers.list returns

    [MarkUps::Markers::Command, MarkUps::Markers::Verbatim,
    MarkUps::Markers::Outline, MarkUps::Markers::Document,
    MarkUps::Markers::paragraph, MarkUps::Markers::Table]

    and the dup'd collection returns:

    [#<Class:0x4033a584>, #<Class:0x4033a534>, #<Class:0x4033a4f8>,
    #<Class:0x4033a4a8>, #<Class:0x4033a480>, #<Class:0x4033a444>]

    > > (Actually they do have a small bit of boolean state in a class

    instance
    > > var, but I check and it is being duplicated.)
    > > I just don't get it. Any ideas?

    >
    > What exactly goes wrong?


    Unfortunately it is strange. The Outline Marker which tells the parser
    how to identify and parse an outline fails.

    T.
    Trans, Jan 27, 2005
    #3
  4. Trans

    Trans Guest

    Up. I figured it out.

    And take a wild guess what the problem was! There's a riddle for you:
    What gets lost when you copy a class to a variable?
    Ex-
    |
    | x = String.dup
    |

    Answer coming up....
    Trans, Jan 27, 2005
    #4
  5. Trans

    Trans Guest

    No stabs? Okay well the answer is: the name.
    x = String.dup
    p x.name
    => ""

    T.
    Trans, Jan 27, 2005
    #5
  6. "Trans" <> schrieb im Newsbeitrag
    news:...
    > Up. I figured it out.
    >
    > And take a wild guess what the problem was! There's a riddle for you:
    > What gets lost when you copy a class to a variable?
    > Ex-
    > |
    > | x = String.dup
    > |
    >
    > Answer coming up....


    The name

    robert
    Robert Klemme, Jan 27, 2005
    #6
  7. Trans

    Trans Guest

    Correct!

    Unfortunately you were a minute late on the buzzer so we can only off
    you the consolation prize --a virtual pat on the back. "pat, pat" :)

    But seriously, thanks robert, your questioning spurred me to dig in and
    find the problem. And its a good thing to remember!

    T.
    Trans, Jan 27, 2005
    #7
  8. "Trans" <> schrieb im Newsbeitrag
    news:...
    > Correct!


    Yippieh!

    > Unfortunately you were a minute late on the buzzer so we can only off
    > you the consolation prize --a virtual pat on the back. "pat, pat" :)


    Darn...

    > But seriously, thanks robert, your questioning spurred me to dig in and
    > find the problem. And its a good thing to remember!


    Glad I could help. Btw, why is it that you dup classes? It seems strange
    to me and there might some dangers, especially if those classes to be
    duped refer each other:

    >> class Foo; end

    => nil
    >> class Bar; XX = Foo; end

    => Foo
    >> Bar::XX

    => Foo
    >> Bar::XX == Foo

    => true
    >> bd = Bar.dup

    => #<Class:0x10181848>
    >> bd::XX

    => Foo
    >> bd::XX == Foo

    => true
    >> class Box; def test() Foo; end end

    => nil
    >> Box.new.test

    => Foo
    >> Box.dup.new.test


    Even Marshal doesn't help:

    => Foo>> Marshal::load(Marshal::dump(Box)).new.test == Foo
    => true
    >> Marshal::load(Marshal::dump(Bar))::XX == Foo

    => true

    Kind regards

    robert
    Robert Klemme, Jan 27, 2005
    #8
  9. Trans

    Trans Guest

    Good point. Fortunately these classes are all self contained beyond
    being subclasses of Marker.

    The reason has to do with some trouble I alsways seem to run into with
    these types of apps. Basically I have a Parser instance that gets fed
    Token classes (Markers) which contain class level information on how to
    recognize the relavent text they will parse. Here a very simple
    example:

    require 'yaml'

    s = "[test]THIS IS A TEST[b.]&tm;[test.]"

    class XmlTagToken < Parser::Token
    normal!
    def self.start( match ) ; %r{ \[ (.*?) \] }mx ; end
    def self.stop( match ) ; %r{ \[ [ ]* (#{Regexp.escape(match[1])})
    (.*?) \. \] }mx ; end
    end

    class XmlEntityToken < Parser::Token
    unit!
    def self.start( match ) ; %r{ \& (.*?) \; }x ; end
    end

    registry = Parser::Registry.new
    registry.register( XmlTagToken )
    registry.register( XmlEntityToken )

    cp = Parser.new( registry )
    d = cp.parse( s )
    y d

    The I take this further and add instance methods to the tokens to parse
    sepecialize content. Sometimes that content is "reentrant", that is to
    say I need to reparse it --like an embedded document.

    So the problem? How do I talk to my Parser instance from within an
    instance of a Token?

    If you have an elgant solution to that I'll give you more than a pat on
    the back!

    T.
    Trans, Jan 27, 2005
    #9
  10. On Fri, 28 Jan 2005, Trans wrote:

    > Good point. Fortunately these classes are all self contained beyond
    > being subclasses of Marker.
    >
    > The reason has to do with some trouble I alsways seem to run into with
    > these types of apps. Basically I have a Parser instance that gets fed
    > Token classes (Markers) which contain class level information on how to
    > recognize the relavent text they will parse. Here a very simple
    > example:

    [...]
    >
    > registry = Parser::Registry.new
    > registry.register( XmlTagToken )
    > registry.register( XmlEntityToken )
    >
    > cp = Parser.new( registry )
    > d = cp.parse( s )
    > y d
    >
    > The I take this further and add instance methods to the tokens to parse
    > sepecialize content. Sometimes that content is "reentrant", that is to
    > say I need to reparse it --like an embedded document.
    >
    > So the problem? How do I talk to my Parser instance from within an
    > instance of a Token?


    I think you need the Token to be aware of the Parser, as well as the
    Parser being aware of the Token. You need to pass the one to the
    other in both cases.

    If I have anything like a grasp on the topic of the rest of this
    sentence, then Dependency Injection may be of use here. I think
    D.I. can work like a Personal Assistant, so /s?he/ tells the
    colleague classes to arrange the meeting you want to have.
    All the arrangements are done through /h(im|er)/, so you don't have
    to worry about the details.

    I might have this wrong, and it might be Model, View, Controller
    that is needed here, because the controller mediates between the
    Model and the View. This would suggest that the ownership
    relationship is not really a factor in this communication problem,
    except in so far as it is where the problem arises. The analogy
    might be better expressed as "Bosses can get on better with Workers
    if there is a Union committed to doing something mutually beneficial
    where possible", but this is probably stretching things...!

    I have run into this problem myself, and have not seen a good
    solutoin to it. I have a suspicion that it probably means the
    separation of the two classes, in this case Parser and Token, is
    an incorrect model, because they both need access to each other.

    >
    > If you have an elgant solution to that I'll give you more than a
    > pat on the back!
    >
    > T.
    >

    Hugh
    >
    >
    Hugh Sasse Staff Elec Eng, Jan 27, 2005
    #10
  11. Trans

    Trans Guest

    > I have run into this problem myself, and have not seen a good
    > solutoin to it. I have a suspicion that it probably means the
    > separation of the two classes, in this case Parser and Token,
    > is an incorrect model, because they both need access to each
    > other.


    Hmm... I'm not sure how that can be outside of through OOP out the
    window. If I combine the Token and the Parser into a single thing then
    that will really be the only thing there is ;-)

    I'll think on it some more though.
    I take it you've looked at parser.rb then?

    T.
    Trans, Jan 27, 2005
    #11
  12. On Fri, 28 Jan 2005, Trans wrote:

    >> I have run into this problem myself, and have not seen a good
    >> solutoin to it. I have a suspicion that it probably means the
    >> separation of the two classes, in this case Parser and Token,
    >> is an incorrect model, because they both need access to each
    >> other.

    >
    > Hmm... I'm not sure how that can be outside of through OOP out the
    > window. If I combine the Token and the Parser into a single thing then
    > that will really be the only thing there is ;-)


    Yes. That's why I only consider it a suspicion, and why I say I
    haven't seen a good answer to it yet.

    Thinking out loud: What if when instance vars were created they got
    a container() method which returned the containing class? Or maybe
    have a contains keyword like attr (and friends) that sets this up
    for you. It feels like unwanted coupling, though.

    In thinking Forth (http://thinking-forth.sourceforge.net/) Leo
    Brodie says that such a case should have the commonality extracted
    into an interface, each side talking to the interface in the way
    that is most suitable. Then outsiders can get at the interface.
    [This is paraphrased from memory. Oh, just a minute...]
    "Tip
    Both data structures and the commands involved in the communication
    of data
    between modules should be localized in an interface component."
    This means you can change the interface easily later.

    This begins to look like "model, view, controller" to me.

    >
    > I'll think on it some more though.
    > I take it you've looked at parser.rb then?


    Yes, it looks good but I've not got far with it yet.
    >
    > T.
    >

    Hugh
    Hugh Sasse Staff Elec Eng, Jan 27, 2005
    #12
  13. "Hugh Sasse Staff Elec Eng" <> schrieb im Newsbeitrag
    news:p...
    > On Fri, 28 Jan 2005, Trans wrote:
    >
    >>> I have run into this problem myself, and have not seen a good
    >>> solutoin to it. I have a suspicion that it probably means the
    >>> separation of the two classes, in this case Parser and Token,
    >>> is an incorrect model, because they both need access to each
    >>> other.

    >>
    >> Hmm... I'm not sure how that can be outside of through OOP out the
    >> window. If I combine the Token and the Parser into a single thing then
    >> that will really be the only thing there is ;-)

    >
    > Yes. That's why I only consider it a suspicion, and why I say I
    > haven't seen a good answer to it yet.


    Not much time, so just a short anwer in between: I think the proper model is
    a parsing context. Part of that context could be a stack of parsers or a
    current parser that knows its ancestor. I would definitely not use classes
    here but instances.

    > Thinking out loud: What if when instance vars were created they got
    > a container() method which returned the containing class? Or maybe
    > have a contains keyword like attr (and friends) that sets this up
    > for you. It feels like unwanted coupling, though.


    Yeah, but that's the solution. The context can have factory methods for
    this.

    module ContextAware
    attr_accessor :context
    end

    class Context
    def create(cl,*a, &b)
    x = cl.new(*a, &b)
    x.context = self if ContextAware === x
    x
    end
    end

    ....

    Cheers

    robert


    > In thinking Forth (http://thinking-forth.sourceforge.net/) Leo
    > Brodie says that such a case should have the commonality extracted
    > into an interface, each side talking to the interface in the way
    > that is most suitable. Then outsiders can get at the interface.
    > [This is paraphrased from memory. Oh, just a minute...]
    > "Tip
    > Both data structures and the commands involved in the communication
    > of data
    > between modules should be localized in an interface component."
    > This means you can change the interface easily later.
    >
    > This begins to look like "model, view, controller" to me.
    >
    >>
    >> I'll think on it some more though.
    >> I take it you've looked at parser.rb then?

    >
    > Yes, it looks good but I've not got far with it yet.
    >>
    >> T.
    >>

    > Hugh
    >
    >
    >
    Robert Klemme, Jan 27, 2005
    #13
  14. Trans

    Trans Guest

    > Yes, it looks good but I've not got far with it yet.

    Great.

    FYI, I'm still improving on it. Will send update later today. I have
    made one improvement to the inteface and another bug has been rooted
    out.

    T.
    Trans, Jan 27, 2005
    #14
  15. Trans

    Trans Guest

    Sorry for delay. Struggled with a couple nasty/subtle bugs. But now it
    looks alot better. I have one more thing to do. I'm gogin to make the
    parser it self tell the tokens about it, though I wuold like to figure
    out how to copy classes and give them a name, instead of them appearing
    as numbers on #inspect.

    T.
    Trans, Jan 28, 2005
    #15
  16. Trans

    Pit Capitain Guest

    Trans schrieb:
    > (...) though I would like to figure
    > out how to copy classes and give them a name, instead of them appearing
    > as numbers on #inspect.


    c = String.dup

    def c.to_s
    "MySpecialString"
    end

    Regards,
    Pit
    Pit Capitain, Jan 28, 2005
    #16
  17. "Pit Capitain" <> schrieb im Newsbeitrag
    news:...
    > Trans schrieb:
    > > (...) though I would like to figure
    > > out how to copy classes and give them a name, instead of them

    appearing
    > > as numbers on #inspect.


    I would not do this. IMHO even from a conceptual point of view you rather
    want instances and not classes. Did you consider my remark about parsing
    context?

    > c = String.dup
    >
    > def c.to_s
    > "MySpecialString"
    > end


    I guess that's not the same as there is some magic involved with class
    names:

    >> c = Class.new

    => #<Class:0x1018ab00>
    >> c.name

    => ""
    >> Foo = c

    => Foo
    >> c.name

    => "Foo"
    >> Foo.name

    => "Foo"
    >> Bar = c

    => Foo
    >> Bar.name

    => "Foo"
    >> c.name

    => "Foo"

    Kind regards

    robert
    Robert Klemme, Jan 28, 2005
    #17
  18. Trans

    Pit Capitain Guest

    Robert Klemme schrieb:
    > "Pit Capitain" <> schrieb im Newsbeitrag
    > news:...
    >
    >>Trans schrieb:
    >>
    >>>(...) though I would like to figure
    >>>out how to copy classes and give them a name, instead of them
    >>>appearing as numbers on #inspect.
    >>>

    ...
    >>
    >> c = String.dup
    >>
    >> def c.to_s
    >> "MySpecialString"
    >> end
    >>

    ...
    >
    > I guess that's not the same as there is some magic involved with class
    > names:
    >

    ...

    Hi Robert,

    I thought Tom was talking about the textual representation of his class copies
    when calling inspect on them. My simple code was an answer to this problem.

    I didn't talk about the name of a class object as returned by the name method.
    IIRC it has been mentioned at least once on this mailing list that the name of a
    class object is the name of the first constant this class object is assigned to,
    as your code shows.

    Regards,
    Pit
    Pit Capitain, Jan 28, 2005
    #18
  19. Hi,

    Am Freitag, 28. Jan 2005, 19:05:54 +0900 schrieb Robert Klemme:
    >
    > I guess that's not the same as there is some magic involved with class
    > names:
    >
    > >> c = Class.new

    > => #<Class:0x1018ab00>
    > >> c.name

    > => ""
    > >> Foo = c

    > => Foo
    > >> c.name

    > => "Foo"
    > >> Foo.name

    > => "Foo"
    > >> Bar = c

    > => Foo
    > >> Bar.name

    > => "Foo"
    > >> c.name

    > => "Foo"


    There's nothing magic. The first constant's name that the
    class is assigned to will be the classes name.

    c=Class.new #=> #<Class:0x401e8874>
    d=c #=> #<Class:0x401e8874>
    e=d #=> #<Class:0x401e8874>
    F=e #=> F
    G=c #=> F
    c.name #=> "F"

    Bertram

    --
    Bertram Scharpf
    Stuttgart, Deutschland/Germany
    http://www.bertram-scharpf.de
    Bertram Scharpf, Jan 28, 2005
    #19
  20. "Pit Capitain" <> schrieb im Newsbeitrag
    news:...
    > Robert Klemme schrieb:
    > > "Pit Capitain" <> schrieb im Newsbeitrag
    > > news:...
    > >
    > >>Trans schrieb:
    > >>
    > >>>(...) though I would like to figure
    > >>>out how to copy classes and give them a name, instead of them
    > >>>appearing as numbers on #inspect.
    > >>>

    > ..
    > >>
    > >> c = String.dup
    > >>
    > >> def c.to_s
    > >> "MySpecialString"
    > >> end
    > >>

    > ..
    > >
    > > I guess that's not the same as there is some magic involved with class
    > > names:
    > >

    > ..
    >
    > Hi Robert,
    >
    > I thought Tom was talking about the textual representation of his class

    copies
    > when calling inspect on them. My simple code was an answer to this

    problem.

    Ah, ok. Although in that case you probably want to override #inspect.

    > I didn't talk about the name of a class object as returned by the name

    method.
    > IIRC it has been mentioned at least once on this mailing list that the

    name of a
    > class object is the name of the first constant this class object is

    assigned to,
    > as your code shows.


    Yep.

    Regards

    robert
    Robert Klemme, Jan 28, 2005
    #20
    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. Xavier Osa
    Replies:
    0
    Views:
    630
    Xavier Osa
    Jan 9, 2004
  2. E11
    Replies:
    1
    Views:
    4,749
    Thomas Weidenfeller
    Oct 12, 2005
  3. Bishop
    Replies:
    1
    Views:
    774
    Bishop
    Feb 24, 2007
  4. Eric
    Replies:
    0
    Views:
    454
  5. Dan Otterburn

    Efficiently de-duping an array

    Dan Otterburn, Aug 24, 2007, in forum: Perl Misc
    Replies:
    8
    Views:
    134
    Tad McClellan
    Aug 25, 2007
Loading...

Share This Page