Jump to content

Command design pattern and composition of functions


Recommended Posts

Hi,

I would like to run a vi and check in it if I want to continue executing it or to pass it down the flow to another vi that will run it with the same inputs that he had before.

This will allow for a basic function of function implementation or function composition.

Never mind the general concept, here is a study case that I want to solve:

I have a command design pattern (classes) that contains 3 vis: init, set specific param and execute.

The init and the execute is the same override vi for all the commands, however, the member access vi "set specific param" is different for each command.

I could pass the params to the init or to the execute through a generic input but for this example I don't want to.

The result will be a common init and execute that can iterate through the array of commands but the "set specific param" can't be iterated since it is different and regards a specific command from the array.

The problem is that we need to use "set specific param" only after the init and before the execute, thus, breaking the OO design.

My solution was to add a Boolean "is initialized" to the commands class cluster and set it to true in the init vi.

Inside the "set specific param" I check the status of "is initialized" and if it is false (init wasn't called yet) I will send the vi and the connector pane inputs to the init vi queue.

The init vi will open the queue of vis to run before closing.

This will allow me to "set specific param" on an uninitialized instance of the command instance before I go and iterate on the array of the commands.

Obviously this is not perfect in the case of a calculation being written and read but only for param setting (the complete calculation could also be generalized into this concept by creating a tree of functions of functions instead of a vi queue).

What do you think about this concept? Is there a more trivial way to do it? Since we can't run the vis reference again from the vi server I had to recall the vi. I might also pause it via a notifier (while the class input is turned into a DVR) and have the init release it and wait for it to finish before going to the next vi in the loop.

Did anyone try this concept before?

Thanks in advance.

Link to comment

Is there any way you could illustrate this or share some code? After reading it 4 times I still cannot understand what you are doing. You mention an array of commands, a commands class cluster, a queue, and something about VI server. I cannot picture how it all fits together. Are "init," "execute," and "set specific param" the possible commands, or are those actions on commands? What's the OO hierarchy?

Link to comment

ned, I tend to talk too much. Hopefully the code example will explain itself.

ShaunR, this is exactly how I felt during this OO design :)

I attached a code that demonstrates the problem and a solution that looks a bit like the picture you posted.

It contains a command class and 3 main vis: "main - old style" shows a particular problem. "main - concept" shows a solution. "main - new style" implements the solution.

However, this solution is a bit complex and it spends cpu time.

Is there a more elegant way to solve this and get the same effect but with no cpu time and with less code?

I thought of some other solutions but I'm not happy with any of them beside a generic param input which I try to avoid.

The project is saved in LV 2011. Tell me if you want it in another version.

test command.zip

Link to comment

I disagree that indexing out an individual command "breaks" OO. You have an array of objects and you want to modify one of them, so you pull that particular item out of the array, make a change to it, and put it back in the array. Seems clean and simple to me, much more so than your proposed "solution." Let's say you were going to set the parameter before initializing: then you wouldn't even bother putting it in the array until after you had set the parameter, right? But you'd still be modifying an individual element of an array, you'd just be doing it before it was inserted into the array. I don't see indexing out after building the array as any different.

You could, of course, assign unique identifiers to each instance, then set the parameter on every element in the array with an additional identifier input, and only change the elements that have a matching identifier, but that seems excessively complicated for no gain.

Link to comment

Why are you using a dynamically-dispatched “Init” method at all? Why not just have a “Create <commandname>” specific method in each command class that initializes it (with specific parameter inputs) and then send it off to be executed?

drjdpowell, this is just a basic example and not the actual feature I'm trying to implement.

True, it is possible to remove the init in my example and leave only the member access vi or join them two together.

Yet, even in this example there are reasons to have a separate init which is dynamically dispatched:

1. The init might establish communication and load configuration files while the command has other parameters that the user has to set. You don’t want to have a big init vi that does a hundred things at once. You might not have even enough connectors to do that.

2. You might want to get an instance of the command, run it with one set of parameters and run it again without initializing but with a different set of parameters.

3. Moreover, you might want to override this command to behave a bit differently which is why you want it to be dynamic. You might also want to iterate over some commands and add a common vi just to this group. If the init is different for each command you might not be able to do that.

4. As for having one big vi that both initializes and gets all the parameters at once and maybe parse some input strings, I don't like this style since it leaves a lot of room for manual mistakes.

Having a data member vi that can only get a specific input enforces style on the developer.

I disagree that indexing out an individual command "breaks" OO. You have an array of objects and you want to modify one of them, so you pull that particular item out of the array, make a change to it, and put it back in the array. Seems clean and simple to me, much more so than your proposed "solution." Let's say you were going to set the parameter before initializing: then you wouldn't even bother putting it in the array until after you had set the parameter, right? But you'd still be modifying an individual element of an array. You'd just be doing it before it was inserted into the array. I don't see indexing out after building the array as any different.

You could, of course, assign unique identifiers to each instance, then set the parameter on every element in the array with an additional identifier input, and only change the elements that have a matching identifier, but that seems excessively complicated for no gain.

ned, I'm trying to create a function composition without sub vis or synchronous calls and the first step is having parallel vis wait one to the other and give each other input/output:

Given f(x) = 2x + 3 and g(x) = –x2 + 5, find ( f o g)(x)

The command design pattern is just a test case.

As for the breaking of OO, besides the fact that you deal with a particular instance instead of the general array of objects, I really hate searching for an index in the array. What will happen if you add a command to the beginning of the array? You add here a lot of manual coupling. Any assumption I have on the array which is not part of the hierarchy such as instance index or identifier/flag for some type of objects is, from my point of view, regular code that just happens to be next to OO code.

Never mind why I want to implement it, my question is what is the best way to signal the other vi to start working with as little cpu usage and mess. Notifiers? Queues? Events?...

Link to comment

I like drjdpowell's solution, with the addition of a parameterless dynamic dispatch Reinitialize.vi if you need the "reset later" behavior. Let the class store its initial state as provided by its custom Init.vi and use that when Reinitialize is called.

Never mind why I want to implement it, my question is what is the best way to signal the other vi to start working with as little cpu usage and mess. Notifiers? Queues? Events?...

Queues are the fastest way in LV to move data from one spot to another other than a direct wire. They create no data copies for the data that they shift and can shift large data structures just by moving pointers around in memory. I *believe* events behave like queues as long as there is only one event structure registered to receive the event, but I am not absolutely sure about that.
Link to comment

As for the breaking of OO, besides the fact that you deal with a particular instance instead of the general array of objects, I really hate searching for an index in the array. What will happen if you add a command to the beginning of the array? You add here a lot of manual coupling. Any assumption I have on the array which is not part of the hierarchy such as instance index or identifier/flag for some type of objects is, from my point of view, regular code that just happens to be next to OO code.

The fact that the array contains objects does not change that it's just an array. Seems like you want the array to be something more. If that's the case, are you sure an array is the appropriate structure for collecting your commands?

Link to comment
  • 2 weeks later...
drjdpowell, this is just a basic example and not the actual feature I'm trying to implement. True, it is possible to remove the init in my example and leave only the member access vi or join them two together. Yet, even in this example there are reasons to have a separate init which is dynamically dispatched:...

OK, but why do you you call the Init.vi in a loop over an array of objects? Why not take the individual objects, call Init on them, then call the Parameter setting VI, and only then put them in an array. Like this (modifying your “old style” example):

post-18176-0-53934600-1346153892.png

Here “Init.vi” can be dynamically dispatched, while “Write String.vi” can be a unique method for each child class. You could even branch the wire and reuse the preinitialized object with different parameters.

Basically I don’t understand the reasoning behind your initial example, where you put the objects in a array to call Init in a loop, then strip them all out again to treat them individually, then put them all back in an array again. Seems pointlessly over complicated.

— James (sorry for the late reply, I’ve been on holiday without internet access)

Link to comment
  • 3 weeks later...

Thanks for all the replies. I'm so sorry for the Houdini act from my own post.

You deserve a more through reply, thus, I'll strip down a demo project of mine tonight and post it full for your inspection.

For now, the example of the init process might not be the most perfect one. My basic question was: what is the best way to bring order to parallel processes making sure that one will start only once the other finished.

I guess Actors have an answer for that question but I didn't dive into it enough yet.

In the demo I'll post tonight the parallel vis are not Actors but I could, in theory, call them asynchronously.

Please don't fixate to the init example there. I guess that if only I asked how Actors communicate and bring order between them I would have gotten my answer ages ago.

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
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
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.