On Jan 13, 2004, at 10:39 AM, Gary Stainburn wrote:

On Tuesday 13 Jan 2004 3:04 pm, James Edward Gray II wrote:
On Jan 13, 2004, at 6:24 AM, Gary Stainburn wrote:

3) As everything else will be created from the Trainset instance, they
will have a link to it. This will be stored as $self->{_OWNER}. This will
then (hopefully) provide quick direct access to the Trainset variables
(were Class globals). I think I should be able to simply call something
like$self->{_OWNER}{_BLOCKS}

Or you could always do something like $self->{_Trainset}->get_blocks(),
which is probably a little better style. Always use methods when you
can.

This then gets back to the speed vs control discussion in the OOP perldocs.
For the sake of speed I've made the decision to stick with direct access to
variables within my code, but will eventually write methods for the external
interface.

And it's still a bad idea for you to be worrying about this problem at this point. ;) Do you see what you're doing here? You're making things harder because you're inventing problems you haven't run into yet. If you run into speed issues down the road, this might be the right place to start optimizing, but you're not there yet.


The documentation you refer to suggest using variables over method calls INSIDE THE CLASS/PACKAGE. You're using variables INSIDE OTHER CLASSES. While this isn't always wrong, it's probably not the way to go here. Trainset is the interface object. So get_blocks() should take parameters and return the exact subset of blocks you are currently interested in, nothing more.

Think good design. You'll have plenty of time to think speed later.

The example code (not tested yet) will create a long length of track
(TCB1 and > > TCB2), and a siding (S1).  It will then create a switch
 (Y-shape) point and connect that to TCB2 and S1.

It will then create a signalbox, and in that signalbox create a lever
to control the set of points.

my $tset=Trainset->new;
$tset->add_track('TCB1','TCB');              # create 1st block of track
$tset->add_track('TCB2','TCB');              # create 2nd block of track
$tset->add_track('S1','TCB');                # create Siding 1

An add_tracks() method might be handy. What's that second parameter, if I may ask?

TCB = Track Circuit Block, a block that can detect the presence of a vehicle
(via an residual eltrical current which passes through the metal axle of the
vehicle) as oposed to a normal 'Block' section.


I could reverse the parameter sequence so that the block type is first, then
allow multiple block names to be specified, thus reducing the work involved.
I'll probably make it so that it creates the links between the blocks too.

Now you're talking.


$points=$tset->add_point('GSP1','SWITCH'); # create switch point to
siding

$tset->add_link('TCB1',0,'TCB2',0);  # link TCB1 (rear) to TCB2
(advance)
$tset->add_link('TCB2',0,'GSP1',0);  # link TCB2 to points GSP1
$tset->add_link('S1',0,'GSP1',1);    # link Siding1 to points GSP1
(offset1)

Again, what are the number parameters?

To model a switch, I've got a simple block of track which has two connections
at one end, specifically an array to hold links to the adjacent blocks, so
that the onward link from TCB2 connects to position '0' on switch GSP1, while
the link from siding S1 connects to position '1' on switch GSP1. This way,
to set the route, I simply set a subscript to '0' or '1'.


I could possibly do something like:

$tset->add_point('GSP1','SWITCH',['TCB2','S1'],[]);

I definitely think you can come up with a better interface than the numbers, yes. You're exposing those nasty subscripts to the users of your code. Those should be an implementation detail I don't need to know anything about. Is order of the links even significant? Can the first one mentioned go in subscript 0, the next one mentioned in 1, etc?


I would try to refer to tracks (and everything else for that matter) by name, as much as humanly possible. Keep it simple.

In my opinion the above could probably be done in one method call,
which would make for a much nicer interface.  Heck, have it create
tracks too if the don't exist.

$box=$tset->add_signalbox('Grosmont');       # Create Grosmont signalbox
$lever=$tset->add_lever('GS1');              # Create lever GS1
$box->use_lever($lever,0);           # Put lever1 in signalbox


I could do something like:


$tset->add_signalbox('Grosmont','GS1'........);

where add_signalbox could call add_lever for any lever that doesn't already
exist (I'd still need to define the actions for the lever seperately).

Yes. Progress. You're staring to think along the right lines.


Again, too much work.  The whole point of using the Trainset object as
the code interface is to hide all these ugly details from users.  Does
a signal box always have at least one lever?  Create it in the signal
box constructor then.  Or modify add_signalbox() to accept a list of
levers to add to it.  Do all that in the Trainset code.  That's what
it's for.

# would be nice if I could replace the above with a shortcut like

#  $box=$tset->add_signalbox('Grosmont'); # create signalbox
#  $lever=$box->add_lever('GS1',0);  # create lever and put in s'box

Yes it would, but think bigger on the simplification scale. Maybe you
even leave all these low-level methods in place as there may be a time
when I need them, but give me a high-level interface that makes my life
easier most of the time.

Eventually, I intend to have:


my $tset=Trainset->new('<filename>');

and $tset->save('<filemame>');

at which point I can write a seperate route editor program, but I'm getting a
bit ahead here.

Good, but yes, thinking ahead. Let's make a good code interface first, so the need for an external editor isn't paramount.


$lever->set_use(0,$points,'TCB2');   # position 0 = select TCB2
$lever->set_use(1,$points,'S1');     # position 1 = select S1

$lever->throw(0); # throw lever

I hope that this has shown (a) what I am hoping to aim for with this
project
and (b) that I've taken on board the comments and hopefully
implemented the
suggestions correctly.

Now the new questions.

1) I've put:

use base (Trainset::Trains Trainset::Track Trainset::Signals
          Trainset::Levers Trainset::Boxes);

inside Trainset.pm. Is this the correct way to call in the other
classes?

No it's not.


use Trainset::Trains;
use Trainset::Track;
use Trainset::Signals;
use Trainset::Levers;
use Trainset::Boxes;

If  so, would this also give Trainset::Boxes access to
Trainset::Levers::add_lever to enable the shortcut I mentioned above?

After you switch to the code above sure, but I'm not sure it needs to. Trainset is the glue object. Use it that way. Trainsets' add_signalbox() should create the box, create the lever(s) and link them together. Trainset::Boxes just needs to worry about itself, in construction at least.

So basically, within the add_signalbox would simply call $owner->add_lever
asuming $owner points to the $tset object?

There is no owner object here. add_signalbox is a method inside Trainset. Trainset is the owner. Here's an example adapted from your code above:


package Trainset;

sub add_signalbox {
        my $self = shift;

        # signalbox generating code here, whatever you currently have
        my $box = Trainset::Signalbox->new();        # my example

        while (@_) {    # or something similar to process the remaining params
                my $lever = $self->add_lever( shift() );
                $box->use_lever( $lever );           # index omitted
        }
}

2) What I do with the data will obviously depend on the program using
my
object, but would probably be things like update the screen (Term, TK,
Win32), or to send instructions to a control system (e.g. throw points
on
model railway).


What is the best method to pass control back to the program from
within a
method?

I don't think I understand this question. The obvious answer to me is
return (exit the method). Control will pass back to the caller at this
point, as it always does. If I misunderstood, please try explaining it
again.

What I mean is that if e.g. a train movement updates the status of a block,
Trainset::Track::Update is called for that track object. This will update
must be given back to the calling program so that the screen can be updated.


However, exit won't work here because the original program didn't call the
update method, a train object did.


Also, updating the state of one block may also update adjacent blocks, so
Trainset::Track::Update needs to be called for each of those, again with the
updates needing repainting on-screen before returning to the train object.


Paul Johnson's suggestion of using Call-back routines looks to fit the bill,
because it then can perform whatever action is required. I'll look into
doing that.

I agree. You're talking about how TK (or whatever) will interface with your code here. Likely with some kind of call back system, yes.


Hope that helps.

James


-- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] <http://learn.perl.org/> <http://learn.perl.org/first-response>




Reply via email to