http://qs321.pair.com?node_id=277973

aufrank has asked for the wisdom of the Perl Monks concerning the following question:

I'm working on some OO perl code. I wrote and have been using a module to help me do some neural network simulations for the psycholinguistics lab I work in. The smallest object is a node, and each node can know its name, level/layer in the network, current activation level, previous activation level, and neighbors. Once you've got some nodes, you throw them together into a model/network object, and use methods there to define the connections between nodes and the spread of activation.

Now other people in my lab want to be able to design and run simulations, and so I'm trying to provide a way for them to specify the design of the network without ever seeing the code. I'd like to be able to read in a plain text template, and use that to generate the nodes and to define the connections between them.

A sample config file might look like:

nodes: input, n1, n2, output input => n1 input => n2 n1 => output n2 => output
There will probably be some other parameters in there, but these are the only ones that have to do with the node and network objects.

I want to be able to generate a new node object for each name specified in the first line of the file, and then to put all of those objects into a network, and use the remaining lines to define the connections between the nodes. This means being able to refer to a node object by the name specified in the file.

I'm pretty sure my question is how to generate an anonymous object, set its name attribute, and then use its name attribute to call methods on it.

I've got a connect() method of the Model class that takes two objects from the Node class as its parameters. Once it's got the two node objects, it calls connects_to() on one and input_from() on the other (both from the Node class. So ideally,after reading in lines 2-5 of the file, I would be able to do something like:

$model->connect('input','n1'); $model->connect('input','n2'); $model->connect('n1','output'); $model->connect('n2','output');
and have it call the correct methods from the Node class without actually having given it Node objects as parameters (but having given it attributes corresponding to Node objects).

I'm pretty sure that either my constructor or my name() method (or both) needs to get cleverer, but I don't know what to do with them. A pared-down version of my constructor from the Node class looks like this (all I've done is taken out a bunch of the attributes that I define for the node, like LAYER, RESTING_LEVEL, and so on):

sub new { my $class = shift; my $self = {}; $self -> {NAME} = undef; bless $self, $class; return $self; }
and here's how I set the node's name:
sub name { my $self = shift; $self -> {NAME} = shift if (@_); return $self -> {NAME}; }

Like I said above, I think what I'm trying to do is build an anonymous object, set its name attribute, and then use the name attribute to call methods on it. I'm worried that I may not have been clear enough about what I need and what I'm trying to do, so if you have any questions or would like to see any of the code I referred to but didn't post, let me know and I'll include it in the comments.

/au

Replies are listed 'Best First'.
Re: calling anonymous objects by their names
by sauoq (Abbot) on Jul 25, 2003 at 21:17 UTC
    Like I said above, I think what I'm trying to do is build an anonymous object, set its name attribute, and then use the name attribute to call methods on it.

    It seems to me that you are jumping through more hoops than you should have to... If you are going to do it like this, then I guess what you need is class variable, a hash, that holds the names of your nodes as keys and the node objects corresponding with those names as the values. Then you would need to provide a function that would dispatch a method call based on the node name (and for that, you'd need a dispatch table of some sort.)

    package Node; my %METHODS = ( somemethod => \&Node::somemethod, ); my %NODE; sub new { my $class = shift; my $name = shift; my $self = { NAME => $name }; bless $self, $class; $NODE{ $name } = $self; return $self; } sub dispatch { my $method = shift; my $name = shift; $METHODS{ $method }->( $NODE{ $name }, @_ ); } sub somemethod { my $self = shift; # ... }

    I'll repeat myself though... I doubt this is the best way to go about solving your problem. You might want to reconsider your design some.

    -sauoq
    "My two cents aren't worth a dime.";
    
Re: calling anonymous objects by their names
by perrin (Chancellor) on Jul 25, 2003 at 21:38 UTC
    I think what I'm trying to do is build an anonymous object, set its name attribute, and then use the name attribute to call methods on it.

    Well, what difference does it make to your program what the thing is called? You can deal with references, since you are creating the objects. I would probably either change the config format or parse it and generate some kind of tree structure. Then you just walk down the tree, adding the child nodes as you go. It might call for a recursive function. I've had good luck with Tree::DAG_Node and its walk_down() method.

Re: calling anonymous objects by their names
by skyknight (Hermit) on Jul 25, 2003 at 21:04 UTC

    From your description, you almost certainly will want to build up a hash of your Node objects, using their names as a key so you can quickly recall them so as to perform the linkages. Your connect routine could still take their string names as arguments, but could then look them up in the hash, and call the appropriate methods on the retrieved objects.

    Your general, high level algorithm will be as follows... Take the first line of your config file, split it up into individual node names, and for each name construct a Node object, set its name, and stuff the node object into the hash that you're keeping using the name as the key. Then for each subsequent line, split it into the "to" and "from" nodes, look those nodes up in your hash, and call the appropriate methods on them to form the connection.

    Straightforward enough, neh?

Re: calling anonymous objects by their names
by NetWallah (Canon) on Jul 25, 2003 at 22:40 UTC
    I agree with skyknight's method - just wanted to OO-ify it a bit.

    Refer to "Class Data" in perltoot. You can store you %nodelist in the class (Not individual objects). Your object "new" method adds an object reference by doing:

    $nodelist{$NewObjectName}=$self;
    Your "connect" method can then easily access a named object and do something like:
    $self->{LEFT_LINK} = $nodelist{$NameOfLinkedNode};