Duping a class causes error

T

Trans

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.
 
R

Robert Klemme

Trans said:
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
 
T

Trans

Robert said:
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.
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:

[QUOTE="# said:
(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?[/QUOTE]

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

T.
 
T

Trans

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....
 
R

Robert Klemme

Trans said:
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
 
T

Trans

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.
 
R

Robert Klemme

Trans said:
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:

Even Marshal doesn't help:

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

Kind regards

robert
 
T

Trans

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.
 
H

Hugh Sasse Staff Elec Eng

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.
 
T

Trans

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.
 
H

Hugh Sasse Staff Elec Eng

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.
Hugh
 
R

Robert Klemme

Hugh Sasse Staff Elec Eng said:
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.
Hugh
 
T

Trans

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.
 
T

Trans

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.
 
P

Pit Capitain

Trans said:
(...) 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
 
R

Robert Klemme

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:
=> "Foo"

Kind regards

robert
 
P

Pit Capitain

Robert said:
...

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
 
B

Bertram Scharpf

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:

=> "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
 
R

Robert Klemme

Pit Capitain said:
..

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top