Jump to content

The Tube Knows…


Recommended Posts

Just add a bit for us non-POOP heathens.

Erm... you do realize this is an OOP forum, right? :P

Additional channels can be created in your application by a simple Save As operation on an existing channel class.

And doing a Save As on the Channel_StopMsg class and any other messages you want to copy... followed by changing all the new message classes so they inherits from the new channel class. (Hint: Wrap each channel in a lvlib and put it in it's own directory and you can simply copy the folder on disk to create a duplicate channel.)

And, if you misspell the message command text [in string-based messaging systems], it will not work.

This is a question of strict type safety versus rapid development. Strict type safety is safer in that it eliminates potential bugs, but it also really slows down your development. The trick is to find the right balance. I use strings to define the message name, but I try to keep all instances of that string contained within a single project library so it's easier to do a search and replace. Ideally, code outside the library isn't even aware of the message's real name.

But, if you have a better solution, I am interested.

Nope, I don't. It does what you outlined in your requirements so call it good and move on. (The tickling in the back of my head is wondering what drove the requirement to have a messaging system that uses dynamic dispatch to auto route messages.)

Anyways, my original goal was to implement an architecture replacement for the common producer-multiple consumer design I have used in the past. And to eliminate the need to pass a cluster of queue refs to each consumer (forcing me to update all of them if I add a new consumer and its queue ref). Also, to eliminate the need to have a type-def controlled enum and variant as the payload for each consumer to control execution. Meaning I would have to update the enum to add a message. Which in turn changes the type of the queue, which changes the cluster of queue refs which causes another recompile of the whole project practically... Not fun when using source control...

The problem isn't with the producer-consumer pattern; the problem is in not properly encapsulating the subsystems or managing the dependencies between the subsystems.

In my architecture, I have multiple parallel loops (processes) doing specific jobs. They each have their own unique set of actions. For example, one might be processing calls to a database. Another might be updating a UI display. Another might be launching plug-in VIs. And another might be receiving messages from the plugin VI and then messaging the other processes to write to the database or update the display or...etc...

One thing worth pointing out in your example is that neither of your channel loops have any data associated with them. In fact the command pattern, which this is based on, doesn't provide a good way for a message to obtain data from the channel loop when the message is executed.** Each message has to be given all the necessary data for it to execute prior to being put on the queue. That means...

1. Your producer loop has to maintain all the information about the entire application rather than allowing subcomponents to be responsible for their own information. Better to delegate the responsibility for certain bits of knowledge to the subcomponent (channel) itself.

2. Since using this pattern prevents a loop from "owning" its own data, all your channels are simply identical remote execution threads. Why do you care which loop a message gets sent to? Why not just send it to the first loop available to process it? In this particular case, defining routing based on class hierarchy hinders your ability to be flexible in balancing message load.

(**You could add an abstract Channel_Data class and put and input and output on the MessageQ:ExecuteMessage method, derive a concrete data class for each channel you implement, and provide all the accessors so the messages can access the channel data when it is executed... but you're really getting into obscure code for very little gain.)

I am wondering if I can't simplify this code some more. If I pass a child object on a parent wire to a create queue function, will I get a queue of type child or parent?

Parent. Queues are based on the wire type, not the object type.

Link to comment

And doing a Save As on the Channel_StopMsg class and any other messages you want to copy... followed by changing all the new message classes so they inherits from the new channel class. (Hint: Wrap each channel in a lvlib and put it in it's own directory and you can simply copy the folder on disk to create a duplicate channel.)

Why would I want to bring the messages from one channel over to another? The whole point of this is each channel responds to unique messages. If you create a new channel, you then need to create the unique messages for it.

Nope, I don't. It does what you outlined in your requirements so call it good and move on. (The tickling in the back of my head is wondering what drove the requirement to have a messaging system that uses dynamic dispatch to auto route messages.)

Is there a better solution to eliminate the need to modify the architecture to extend it?

One thing worth pointing out in your example is that neither of your channel loops have any data associated with them. In fact the command pattern, which this is based on, doesn't provide a good way for a message to obtain data from the channel loop when the message is executed.** Each message has to be given all the necessary data for it to execute prior to being put on the queue. That means...

1. Your producer loop has to maintain all the information about the entire application rather than allowing subcomponents to be responsible for their own information. Better to delegate the responsibility for certain bits of knowledge to the subcomponent (channel) itself.

2. Since using this pattern prevents a loop from "owning" its own data, all your channels are simply identical remote execution threads. Why do you care which loop a message gets sent to? Why not just send it to the first loop available to process it? In this particular case, defining routing based on class hierarchy hinders your ability to be flexible in balancing message load.

This is easily remedied. All I need to do is pass the channel object thru the execute and store it in a shift register. Here is an updated version of the project that does this.

MessageQ.zip

Now, if I need state data preserved on a channel, I can add the variables to the channel's private data and create accessors that the message classes can use.

Parent. Queues are based on the wire type, not the object type.

Yes, I tested this and see I am stuck with the current implementation.

Link to comment

As daklu will attest, I rarely get involved in these discussions. Yes, dak, this is almost a monthly thing now! Anyway, my two cents...

Is there a better solution to eliminate the need to modify the architecture to extend it?

Have you checked out AQ's Actor framework? It does not perform auto-routing based on message type (I suppose there is some way it could be done) and it does not have the single hierarchy you might desire. But, each message has a Do (Execute) method. One of the terminals is the Actor (equivalent to your Channel class). Actor properties can be made public, so I can implement the all code in Message.Do.

This is easily remedied. All I need to do is pass the channel object thru the execute and store it in a shift register. Here is an updated version of the project that does this.

So now your message when passed around carries a potential boat load of uninitialized data that is got from deriving from the parent class. OK, fine, you can make it a DVR but now you have added a complexity to the problem and put yourself further from the dataflow paradigm.

Why is the single hierarchy a requirement? There are really three distinct entities - messages, queues, and (for lack of a better word) actors. You can add a fourth, if you wish, as a message controller which your MessageQ class really seems to be. I am uncomfortable with making a a message a subclass of an actor which is a subclass of a message controller which is how I see your hierarchy.

-kugr

Link to comment

So now your message when passed around carries a potential boat load of uninitialized data that is got from deriving from the parent class. OK, fine, you can make it a DVR but now you have added a complexity to the problem and put yourself further from the dataflow paradigm.

Good point. I will need to find an alternate solution for that. This is all good feedback. In the end, I might abandon this architecture but I have definitely learned some things along the way.

Another problem I discovered is the need to pass the channel class object through all the methods on its parent's wire type. Not sure why but it would not let me do it any other way. And as a result, I cannot use the accessor methods on the channel data without casting it to the channel class type. So, this looks like a dead end.

Edited by John Lokanis
Link to comment

Good point. I will need to find an alternate solution for that.

On second thought, is this really all that bad? Since they will not contain any data, how much performance penalty will there really be?

I took a look at AQ's project you mentioned. While I am not sure I totally understand it, it does seem to have one thing in common with mine: every message is a class. Is this a bad idea? Is having a large class hierarchy a bad thing if the hierarchy is what controls the execution of your application?

Link to comment

On second thought, is this really all that bad? Since they will not contain any data, how much performance penalty will there really be?

Assuming you mean the message carries around uninitialized data, it probably is not that bad from a performance perspective. Still I have a problem with the hierarchy but I am no expert.

I took a look at AQ's project you mentioned. While I am not sure I totally understand it

Feel free to ask questions. I have pm'd AQ on the NI site and he has been very helpful. You can ask here too. I am using a derivation of this framework, but it is virtually unchanged from a fundamental aspect. Most of my changes were from deriving off of the classes. The biggest confusion is the creation of Actors. They are launched as opposed to having VIs with loops on the top level VI. And they have to exchange queue references - it is very clever, but takes a while to understand fully. Daklu's has a framework that looks great (there was an earlier thread about this) and actually can evolve into this if he ever desired to do that. His is simpler to understand from the contruction of 'actors' perspective. It uses strings, I think, to differentiate messages. The other 'challenge' with launching Actors is debugging. Good golly it can get confusing. I have started naming my queues solely to see who sent the message to who not to use in searching for a queue by name. I do need to keep track of queues, but I do that on my own.

it does seem to have one thing in common with mine: every message is a class. Is this a bad idea? Is having a large class hierarchy a bad thing if the hierarchy is what controls the execution of your application?

I hope not. It does make for a huge project and some maintenance issues when I find out I need to change something fundamental. For instance, I decided to wrap the LV queue object in a class - much like Daklu's message class. Ouch - every message had to be changed along with a number of other items including AQ's original framework. My biggest issue is the dependency between messages and actors. I have not been as careful as I should have in making sure about this. The dependencies make it hard to separate actors into independent projects - one actor sends a message and the message operates on another actor. So now sending actor's project will require the receiving actor's project. It is a hard thing to split.

Overall, it has worked well for me. My Actors are set up to be observed so they keep track of who is 'watching'. They don't care who the observers are and will send an Update message to all of its observers. The observer does have to 'register' with the observed and this is done via a message. Actors that need to command other actors do so through a Proxy (a wrapper that handles sending the message for a specific command). This is not part of the AQ's original framework. The proxy adds a bit of complexity to the developer of an actor, but makes it easier for a user of an actor. Sine the actual message is hidden inside the proxy, a message really becomes calling a method. To set up a proxy, you do need to get the queue for a specific Actor so you've got some DB type stuff to handle there (some 'global' object needs to be able to resolve this request). I am not happy with my implementation of that, but it works.

-kugr

Link to comment

Why would I want to bring the messages from one channel over to another?

Could be lots of reasons... maybe during dev you want to sandbox a variation without messing up your original code. Maybe you discover you need another channel that is almost exactly identical to an existing channel, like a connection to a second database. Whenever I assume I won't want to do something in the foreseeable future, I almost always discover the 'foreseeable future' is much shorter than I expected.

Is there a better solution to eliminate the need to modify the architecture to extend it?

Well... "better" is a subjective term... and I'm not exactly clear about which parts you are considering architectual and which parts are modifiable. But I think there are simpler solutions.

(Break out the syrup grandma, I'm cooking up waffles!)

...

...

**ack** kugr... overload... <faint>

I took a look at AQ's project you mentioned. While I am not sure I totally understand it, it does seem to have one thing in common with mine: every message is a class.

Yep, that's the command pattern.

Is this a bad idea? Is having a large class hierarchy a bad thing if the hierarchy is what controls the execution of your application?

I'll second what kugr said. It's not a *bad* thing, but it does come at a cost. In addition to what he said, I'll add:

Time - Creating new classes is still relatively time consuming in Labview. Typically I'll spend 2-5 minutes on a new class with accessors and icons. No big deal for a few, much more of a drag when there's 2 dozen of them. That was a dev task I started dreading.

Readability - Having the class hierarchy control execution flow hinders readability. All dynamic dispatching does that to some extent, but if you carry it too far it becomes very difficult for a new dev to build a mental picture of what is happening--especially if the dev isn't familiar with OOP.

In my opinion the command pattern doesn't make a very good messaging system, though I know there are many who disagree with me. I think it couples the sender and receiver together too much. Where it shines is when component A is responsible for defining the processes to be done on the data, component B is responsible for deciding when to call the process and for executing the process in its own thread, and you don't mind A being coupled to B. Plugins are a good example. The plugins are component A and the app is component B.

The roles are much less clear to me in your design. The messages for a given channel are component A, but the responsibilities for component B are split between Main.vi (executing the process) and all the other channels (deciding when to call the process.) That leads to circular source code dependencies between the messages of all your channels which will be a nightmare to untangle. IMO, good design is primarily about managing dependencies.

Link to comment

Made a few more improvements:

1. Eliminated the need for a stop message. I changed the channel execute method to set stop to true. Now, if you send the channel object as the message, it will stop the channel's loop. good idea or bad? seems cleaner to me.

2. Added an example of a message that accesses a channel's state data. Just implements a simple counter.

3. cleaned up the example diagram.

Also, to implement a complex set of message types on a specific channel, I am thinking of using delegation so the implementation is decoupled from the MessageQ architecture. In this case the channel would have only one message type who's data type was the parent class of the implementation. Is that a good solution? I will have to add that to the example at a later date.

MessageQ.zip

Link to comment

1. Eliminated the need for a stop message. I changed the channel execute method to set stop to true. Now, if you send the channel object as the message, it will stop the channel's loop. good idea or bad? seems cleaner to me.

I am OK with it as it seems that what your are doing is some default behavior for the execute method. Realize that 'Call Parent Method' from a child message will get you true for the Stop terminal.

I still don't see the advantage of your single hierarchy. The MessageQ class in your implementation really only needs the Read and Write property for the list of queues and the ReleaseMessageQ. The channel or message classes do not to derive from MessageQ.

The abstract Channel Class has a CreateQ, GetMessage and ReleaseChannel methods. Children of Channel would have additional property methods, etc. I would also put the ChannelProcess method as a part of the Channel class.

The abstract Message class has the Send and Execute methods. To support your message routing scheme you would have abstract Channel_A_Message and Channel_B_Message. From there you would derive additional messages for specific actions.

Clearly, as you have demonstrated, you can make a single hierarchy but a derived class should be some 'enhancement' on its parent. Your Channel class, derived from MessageQ, does not require anything MessageQ provides and does not add to anything MessageQ could do. MessageQ is really only a list keeper. It can do more, but it would not necessarily be channel or message specific. Similarly, your message classes do not use anything that its base classes provide with the exception of identifying the queue based on the parent Channel class. To me that is not sufficient (and can be done differently as stated above), and the extra baggage the channel adds to the derived message class with its member data and method vtable for no gain within the message class is, well, a red flag.

In the end, if it works for you, that is fine. But if I had to maintain the code, it would irritate me.

-kugr

Link to comment

I'm not sure I understand how I can change this and maintain the functionality. By having channel inherit from messageQ and message inherit from channel, I can drop the 'send message' method from messageQ on the diagram, wire any message object into it, and the 'send message' will automatically change to the proper channel 'send message' method based on the hierarchy. This seems to make it easier for the dev since they don.t need to know what channel to choose. Also, the generic channel code only uses methods from messageQ that will be overriden by channel methods based on what type of channel is wired into the subvi. That makes the code to support a channel loop reusable. I can make as many channels as I want by simply copying this sub-vi and wiring in different channel objects.

Also, channel needs access to messageQ data to find the proper queue. By having this data common to all channels, any channel can put an object in the queue of any other channel.

I would like to simplify this but being new to LVOOP, I am not sure I see how to. Can you make a simple example of what you think can be done?

Link to comment

I'm not sure I understand how I can change this and maintain the functionality. By having channel inherit from messageQ and message inherit from channel, I can drop the 'send message' method from messageQ on the diagram, wire any message object into it, and the 'send message' will automatically change to the proper channel 'send message' method based on the hierarchy.

Taking that to the extreme in a large system, you will have every possible method needed in every possible class with a Dynamic Dispatch vi originating from the base object. And all objects inheriting the memory footprint of the data (not the actual data of any instance) from all of its parent. So, what would I get if Channel_A_Count.ExecuteMethod 'called' its 'Read Channels' method. But Channel_A_Count does not have that property you say. It does from inheritance. So what stops the developer from selecting potentially wrong methods that might cause runtime errors? Nothing in this scheme. What is easier to fix - compile time or runtime errors - I would vote compile time. So a properly constructed hierarchy reduces these potential runtime errors.

This seems to make it easier for the dev since they don.t need to know what channel to choose.

You got me there, but perhaps they should not be programming :yes: The actually do not need to know what channel to select, only that they need to select from the base channel class as it has the abstract methods that would have been in your MessageQ. There was a thread in this forum sometime ago about right clicking on a terminal or wire and selecting from a valid list of methods for that terminal/wire type. That would help a developer. I think somebody implemented some add-in - sciware or black pearl perhaps, maybe a jki person.

Also, the generic channel code only uses methods from messageQ that will be overriden by channel methods based on what type of channel is wired into the subvi. That makes the code to support a channel loop reusable. I can make as many channels as I want by simply copying this sub-vi and wiring in different channel objects.

True, but my point is that those methods it uses do not belong in MessageQ since it has no use for them. They belong in the abstract Channel class including the process loop.

Also, channel needs access to messageQ data to find the proper queue. By having this data common to all channels, any channel can put an object in the queue of any other channel.

Yes, but it access the data via the MessageQ object passed into it, not from any internal representation of the MessageQ. In your implementation, the Channel does have the memory footprint (yes, a small DVR), but it is uninitialized. You are retrieving the data via a property call which has nothing to do with the base object of the channel.

I would like to simplify this but being new to LVOOP, I am not sure I see how to. Can you make a simple example of what you think can be done?

Funny you should ask. I did break up your example to see if what I was thinking would work. I am not sure you would call it simplified, but it encapsulates behavior in appropriate ways and perhaps it is better said as more understandable.

For the most part it does work though I have some issues with the Stop not being a derived message. Not quite sure of that yet but I will, as they say, leave it to the reader. I did not clean up the folders and there is an abstract class called SuperClass that does nothing but it helped me dissect your initial hierarchy.

Being new to LVOOP and asking questions on a forum such as this is a good thing. I am still learning and LVOOP is still forces me to think differently than traditional OOP.

Have fun with it.

-kugr

p.s. Daklu, too much?:P

MessageQ_krg.zip

Edited by kugr
Link to comment

Ok, I have spent some time reviewing your code. From what I can tell, you have taken the functionality of the channel class and moved some of it into the message parent class or modifed it to be specific to a particular message class. The channel class now has nothing to do. We could simply eliminate it at this point. The only thing it does do in your version is carry the state data for the process. This could easily be replaced with a SR carrying a variant.

I see how splitting the messageQ class off on it's own simplifies the class hierarchy a bit, but as you acknowledged, it eliminates the automatic channel selection of the original architecture. But as you point out, the dev should know what channel they want to place a message one.

With that change, why should the MessageQ be a class at all? Why not just have it be a DVR. That is all it is now. Having data accessors is not reason enough to use OOP in my opinion.

One other problem I see is your design allows the dev to put a message on a channel that is not designed to accept that message. So, if you are worried about runtime errors, that is a big one. The original architecture would not allow this. In fact, as pointed out, it automatically chose the proper channel for you.

If you were to eliminated the channel class and simply have a custom message class for each parallel process, you could enforce the rule of sending a message only to a receiver that can execute it.

Also noticed that the release channel will not work because you based the queue type on the message class, not the channel class. Why not move the Create and Release into the message class since that is where you get the type to set the queue from? Seems like if you are going to move the Send there, you should move all of it. Wyt have them in the channel class at all if you just need to override them or rewrite them for each channel you create. That was one of the benefits of the original design: you could simply copy and rename the channel class and you were done. No need to touch any the the VIs.

Overall, I understand you want to disconnect the classes from each other for 'good OOP design' reasons, but doing so in this case eliminates the functionality of the original design. I just don't see how it is better this way.

My original intention was to encapsulate a parallel process and all it functionality into a single entity and then allow other similar processes to communicate with it without the need to modify the architecture when extending it. That is why in my view a channel and its messages are already linked together and there is no need to separate them.

Perhaps it would be better to create explicit processes, like 'Database' and 'Display Driver' then attach child functions/messages to them, then have each create a queue and place it in a DVR that is passed around. That way, there is no master parent class and each process is not tied to the others, except when they want to pass a message in one of their functions using the queues in the DVR.

I guess is all comes down to what should dynamic dispatch be used for? Should it be a way of enforcing a message passing system or is it only ok to use it for customizing functionality of a less specific class? I guess since I am new to this, I see this new tool and want to try using it for some purposes it might not have been intended for.

Oh, one more thing, with the changes you made, the Tube no longer 'knows'. Perhaps we should change the thread's subject? Does anyone get my reference in the first place?

Simpsons, Episode 407 at ~10:50.

http://www.watchcartoononline.com/the-simpsons-episode-407-marge-gets-a-job

tongue.gif

Link to comment

Ok, I have spent some time reviewing your code. From what I can tell, you have taken the functionality of the channel class and moved some of it into the message parent class or modifed it to be specific to a particular message class. The channel class now has nothing to do. We could simply eliminate it at this point. The only thing it does do in your version is carry the state data for the process. This could easily be replaced with a SR carrying a variant.

Actually it carries nothing. At moment state data is in the ChannelProcess shift registers or derived classes. There may be reasons to keep it for the future. Suppose you would like every channel to have a name or a keep track of how many messages it correctly handled. I would add those as private data to the Channel class. Remember Channel_A and Channel_B both derive from Channel class. These children will have access to that data. In my opinion, it should keep track of its own queue, but that is debatable. Currently it is held by MessageQ and I can get it by creating a Channel_A_Message queue and I did not want to change your system. ALSO, and mos importantly, it is the common Channel class that is giving you the DynamicDispatch - what you refer to as the automatic channel selection.

I see how splitting the messageQ class off on it's own simplifies the class hierarchy a bit, but as you acknowledged, it eliminates the automatic channel selection of the original architecture. But as you point out, the dev should know what channel they want to place a message one.

It does not eliminate the 'automatic' channel selection. The channel selection you see is the design time resolution of a DynamicDispatch. Solely for the convenience of some lame programmers did you put these methods where they did not really belong. Think about the intent of the class and the methods it should publish. What is the intent of the MessageQ class? Despite its name, it really only keeps track of a list messages. What is a Channel class? It operates on a queue, but it does not hold the entire list of queues. What is a Message class? It holds data and actions that manipulate channels. They are distinct and do not have any hierarchical relationship to each other.

With that change, why should the MessageQ be a class at all? Why not just have it be a DVR. That is all it is now. Having data accessors is not reason enough to use OOP in my opinion.

You could do that. Actually, I can see MessageQ class being enhanced. I could send it a Channel_A_Message and it could return the queue for all Channel_A_Message derivations. This would isolate that loop that determines this and is implemented in multiple places.

One other problem I see is your design allows the dev to put a message on a channel that is not designed to accept that message. So, if you are worried about runtime errors, that is a big one. The original architecture would not allow this. In fact, as pointed out, it automatically chose the proper channel for you. If you were to eliminated the channel class and simply have a custom message class for each parallel process, you could enforce the rule of sending a message only to a receiver that can execute it.

I do not see what you say. Drag a B derived message down and attach it the Channel_A.SendMessage. It seems to change to Channel_B.SendMessage for me. Am I missing something? Again you are not seeing anything but the compiler resolving the call, not selecting what channel. You may think it is really the same thing, but it is the SendMessage implementation that actually selects the channel at runtime. I can change Channel_A.SendMessage implementation. I do think I lost any functionality, I simply moved it to a new base class called Channel. All I did was move the commands that did nothing in MessageQ class to the Channel class.

Also noticed that the release channel will not work because you based the queue type on the message class, not the channel class. Why not move the Create and Release into the message class since that is where you get the type to set the queue from? Seems like if you are going to move the Send there, you should move all of it. Wyt have them in the channel class at all if you just need to override them or rewrite them for each channel you create. That was one of the benefits of the original design: you could simply copy and rename the channel class and you were done. No need to touch any the the VIs.

I created the queues using the Channel_X_Message classes not the Channel_X classes. This seemed more appropriate to me. I missed the ReleaseQ method. The queue used to test against the list should be created using the Message_A class. Yes, you could move these things around. My goal was not to make so many changes that it would be confusing. Frankly, I would not search for a queue by trying to cast all of them into the one I desire, but I did not want to go down that path. Personally I would rather use some sort of look up table. Since each Channel_X class will have a queue, you could use the class name. The Create and Release methods do not belong in the message class. I would not find it natural to as a message for a queue. I would consider the Create and Release to be in the MessageQ class since it is the one keeping track of those anyway, but you would have to use some other scheme to identify the queue.

Yes, I see by creating the queue from the Channel_X class you do not have to make any changes. I don't have an alternative for that but I am not a fan of your message type specific queues anyway, but that is just me.

Overall, I understand you want to disconnect the classes from each other for 'good OOP design' reasons, but doing so in this case eliminates the functionality of the original design. I just don't see how it is better this way.

I am still not sure you lost much that can't possibly be resolved in other ways. For the most part I moved methods to other base classes. What would be needed is an alternate approach to the identification of message queues based on message or class type.

My original intention was to encapsulate a parallel process and all it functionality into a single entity and then allow other similar processes to communicate with it without the need to modify the architecture when extending it. That is why in my view a channel and its messages are already linked together and there is no need to separate them.

Realize that you do have more than one entitiy, right? And the instantiation of a derived class as a new entity brings along with it all of its parents footprint. I would find it confusing as a developer to see methods available to me in the message class that really do nothing. So when I implement the Channel_A_Count.ExecuteMessage method and I connect the Write Count to the message wire the Channel_A count did not change. There is nothing stopping the developer from doing that.

Perhaps it would be better to create explicit processes, like 'Database' and 'Display Driver' then attach child functions/messages to them, then have each create a queue and place it in a DVR that is passed around. That way, there is no master parent class and each process is not tied to the others, except when they want to pass a message in one of their functions using the queues in the DVR.

I guess is all comes down to what should dynamic dispatch be used for? Should it be a way of enforcing a message passing system or is it only ok to use it for customizing functionality of a less specific class? I guess since I am new to this, I see this new tool and want to try using it for some purposes it might not have been intended for.

I am not a fan of passing around a DVR. Actually you do not need to pass around the DVR but once. Once I have the DVR (as a true DVR not dereferenced) I have access to that memory and all of its updates that anyone does. That is the cool thing about DVRs. Publishing the list of queues does get to be a problem and I do not have a great solution yet.

More experienced folks than I should answer the best ways to use DynamicDispatch. Your approach has its merits for your requirements. Not all systems have 7 unique channels. Some systems have hundreds of channels but not all of a unique type. Look at texting and cell phones. Cell phones are pretty much the same and they can send and receive a string. I would hate to create a unique Channel_X class for every phone - that's a lot of classes that are identical. I'd rather instantiate the same class for every phone.

Oh, one more thing, with the changes you made, the Tube no longer 'knows'. Perhaps we should change the thread's subject?

You are right. The message in my case determines where to be sent. But that seems normal to me. I like modeling behavior around the physical.

Does anyone get my reference in the first place?

Simpsons, Episode 407 at ~10:50.

http://www.watchcart...arge-gets-a-job

tongue.gif

Sorry, I did not remember that episode.

-kugr

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.