Sign in to follow this  
3dmodelerguy

need a solution to decides logic at runtime

Recommended Posts

Ok, hear is the story. I am going to be building a game console/chat system for a game engine and will be using C# as the language for this game console/chat system. The person using this game console/chat system will be able to type in commands by starting them with a forward slash (/) so "/playtime" would execute code that will display the playtime in the game console window. The person can also just type in normal text without the forward slash which would just internally call the say command and message out what the person typed to the console window. The way I thought I was going to do this is have a class for each command and have each class inherit from iconsole_command interface and then just create the instance of the object during runtime and call the execute method. I was then directed to try to find a different way to do this as it can be quite slow, which I agree. The one thing I want to be able to do it keep the code the manages the execution of the commands as independent form the actual command code, so that when I want to add a command to the system, I will not need to change the code the manages the execution of the commands. Someone suggested I try the strategy pattern and while that solves the issue, it seems if I used that pattern, the code executing the commands would need to know what commands are available which create more coupling than I want. Is there a better design pattern/way of doing this?

Share this post


Link to post
Share on other sites
Actually, the game engine I will be building the game console for is using Mono for its scripting engine, so technically, C# is the scripting language for the game engine (even tho I would not call C# a scripting language).

I will take a look at using a dictionary as it seems like a clean and easy possible solution.

Share this post


Link to post
Share on other sites
Quote:
Original post by 3dmodelerguy
Actually, the game engine I will be building the game console for is using Mono for its scripting engine, so technically, C# is the scripting language for the game engine
If you already have a scripting language, that is even better - I had assumed you were starting from scratch [smile]

I used to have a few tutorials on integrating in-game consoles with scripting languages, in my file of links, but I seem to have misplaced them. At any rate, since you already have the scripting language integrated with the engine, it would make very little sense not to wire it up to the console.
Quote:
(even tho I would not call C# a scripting language).
C# makes a very good scripting language - unity3d use it to great effect.

Share this post


Link to post
Share on other sites
Quote:
Original post by 3dmodelerguy
Actually, the game engine I will be building the game console for is using Mono for its scripting engine, so technically, C# is the scripting language for the game engine (even tho I would not call C# a scripting language).

I will take a look at using a dictionary as it seems like a clean and easy possible solution.


In .Net 4.0, all .Net languages can become scripting languages natively. You can already do so some .Net with certain framework implementations. Embedding IronPython in a c# app took a matter of hours to get down.

Share this post


Link to post
Share on other sites
Good mercy. Look at the number of people suggesting you use bulldozers to move a teaspoon of sugar into a demitasse cup. This is the sort of thinking that made Vista the model of performance that it is.

If you have a small handful of commands and they mostly result in having some function called, let me suggest you do the equivalent of

if (cmd == "playtime")
do_Playtime();
else if (cmd == "quit")
do_Quit();
...
else
CmdWindowingSystem << "Excuse me?";

Granted, if you have need of deferred command processing, or your commands are all variations on a complex theme, then getting into classes and dictionaries and full blown scripting langauges may have some appeal. But if it's simple verb recognition, save yourself the elaboration of languages, containers and classes, and just write some if-then-else. It's not as cool but it is vastly simpler, and easier to read.


Share this post


Link to post
Share on other sites
Quote:
Original post by ScottMayo
If you have a small handful of commands and they mostly result in having some function called, let me suggest you do the equivalent of

if (cmd == "playtime")
do_Playtime();
else if (cmd == "quit")
do_Quit();
...
else
CmdWindowingSystem << "Excuse me?";
That is a very verbose, painful and inflexible version of the dictionary suggestion. What exactly do you think your if/else approach offer over a map of strings to functions?
Quote:
But if it's simple verb recognition, save yourself the elaboration of languages, containers and classes, and just write some if-then-else. It's not as cool but it is vastly simpler, and easier to read.
Sure, a scripting language may be overkill at this stage in the game (though a dictionary certainly isn't), but what happens 6 months down the line when the engine has been expanded many times, and you need to add another 20-odd functions to your console on a weekly basis?

Share this post


Link to post
Share on other sites
Quote:
Original post by swiftcoder
Sure, a scripting language may be overkill at this stage in the game (though a dictionary certainly isn't), but what happens 6 months down the line when the engine has been expanded many times, and you need to add another 20-odd functions to your console on a weekly basis?


... you get the code to a major title I worked on a few years ago, where a single if-else chain had grown so large that it exceeded the limits of the compiler. (GCC for PSP, IIRC). =)

Share this post


Link to post
Share on other sites
What I meant by saying I would not call C# a scripting language is that I would put it at the same level of C++ and not something like PHP which I consider to be more of a scripting language than a full programming language (but lets not get into that here).

Funny someone mentioned Unity as that is the engine I am designing this game console for as they have no in game console solution available.

The if/else if (or switch) solution is not something I would consider using because it is quite limiting. I plan this game console to be able to run any type of command simple or complex and want it to support unlimited number of commands. Also with that solution, adding custom commands (and since the main reason for starting this project is to allow easier testing so I would except people to want to added custom commands) is next to impossible to maintain if I want to be able to continually release updates as they would need to modify the core code.

Share this post


Link to post
Share on other sites
Mostly related, but if you have a lot of if / else string comparisons it can get pretty slow if you have a lot of strings (as probably has been pointed out).

A quick and easy solution to speed things back up is to do a switch on the first letter first ie:


//assuming Command has been converted to lowercase
switch(Command[0])
{
case 'a':
{
if(!strcmp(Command,"authenticate"))
Authenticate(Params);
else if(!strcmp(Command,"authorize"))
Authorize(Params);
break;
}
.....
case 'q':
{
if(!strcmp(Command,"query"))
Query(Params);
else if(!strcmp(Command,"quit"))
Quit(Params);
break;
}
}



Share this post


Link to post
Share on other sites
Ugh - this is C#. Don't reinvent the wheel or use hacks. Dictionary is probably just as fast as any if/else or switch statement, and scales without effort to tens of thousands of entries with no maintainability penalty.

Delegates solve the problem of binding, and it's trivial to add multiple handlers should it prove convenient.

And the string routines handle the parsing of input. And if anyone is concerned about speed of parsing or lookup: How many commands can a human enter per second?

Command parsing needs to be trivially maintainable - it will never become a performance bottleneck, even if a person types hundreds of commands per second, or they happen to be loaded from a file or something - the overhead of processing will never be an issue.

Even if used for run-time dispatch, doing tens of thousands of lookups is very unlikely to be a problem - the cost of execution would sooner limit the performance.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Threading;



namespace ConsoleApplication1
{


class Program
{
public static void run(string[] args)
{
Console.Out.WriteLine("Running");
}

public static void print(string[] args)
{
foreach (string s in args) Console.Write(s + " ");
Console.WriteLine();
}


static bool done;
public static void quit(string[] args)
{
done = true;
}


public delegate void CommandDelegate(string[] args);
class Commands
{
private Dictionary<string, CommandDelegate> commands = new Dictionary<string, CommandDelegate>();

public void installCommand(string cmd, CommandDelegate d)
{
commands.Add(cmd.ToUpper(), d);
}

public bool execute(String line)
{
string[] parts = line.Split(' ');
if (parts.Length > 0 && parts[0].Length > 0)
{

string cmd = parts[0].Substring(1).ToUpper();
CommandDelegate d;
if (commands.TryGetValue(cmd, out d))
{
d(parts.Skip(1).ToArray());
return true;
}
}
return false;
}

public void printHelp(String[] args)
{
Console.WriteLine("Commands:");
foreach (var p in commands) Console.WriteLine(p.Key);
}

}

static void Main(string[] args)
{
Commands cmds = new Commands();
cmds.installCommand("run", new CommandDelegate(run));
cmds.installCommand("print", new CommandDelegate(print));
cmds.installCommand("help", new CommandDelegate(cmds.printHelp));
cmds.installCommand("quit", new CommandDelegate(quit));

Console.WriteLine("Type /help to list commands");
while (!done)
{
string line = Console.ReadLine().Trim();
if (line.StartsWith("/"))
{
if (!cmds.execute(line)) Console.WriteLine("Invalid command: " + line);
}
else
{
Console.WriteLine(">" + line);
}
}
}
}
}







And, to make it extensible, instead of registering everything up-front, simply pass the Commands object to each subsystem:
class SomeSubSystem {
public SomeSubSystem(Commands c) {
c.installCommand("foo", new CommandDelegate(this.foo));
c.installCommand("bar", new CommandDelegate(this.bar));
}
};
Just add an extra check for duplicate commands.

Share this post


Link to post
Share on other sites
Yea, I am not too worried about the code execute speed of the command process because like you said, no human will be able to type commands fast enough to make it a bottle neck.

I should also mention that I am limited to functionality provided in Mono 1.2.5 so not sure if that means some suggestions here are not possible due to the version of Mono Unity uses.

Share this post


Link to post
Share on other sites
Quote:
Original post by 3dmodelerguy

I should also mention that I am limited to functionality provided in Mono 1.2.5 so not sure if that means some suggestions here are not possible due to the version of Mono Unity uses.


Dictionary and delegates should be available, and that is about all there is to it.

Share this post


Link to post
Share on other sites
Quote:
That is a very verbose, painful and inflexible version of the dictionary suggestion. What exactly do you think your if/else approach offer over a map of strings to functions?


Simplicity. Comparison and dispatch are in a single place, completely exposed to the human eye. It's KISS in purest form. There's no chasing around to find where the dictionary is instantiated and what's in it (probably off with the rest of the process initialization in some other file, great, another window to manage in the editor, like I don't already have 30 of those). I know the current fad is terse code with as much abstraction as possible, but sometimes code is just simpler when it's exposed, stupidly simple and trivially obvious.

I'm a big fan of Big Abstraction for Big tasks. But if it's 5 string commands that simply dispatch to 5 unrelated functions... screw it. It's if/then/else every time. Refactoring for concise coolness can be done if the simple approach ever breaks down - though I'd argue that if there are so many cases that if/then/else doesn't fit in a function anymore, as one fellow mentioned here, then you have too many commands for a human to remember anyway, and your problem is human factors, not code design.

It's worth noting that I currently work for a company where not everyone knows C++, and indeed not everyone is interested in being cool, OO and modern. There can be a lot of advantages to writing the simple code in a simple fashion that *anyone*, from the guys who grew up in Fortran 4 and don't know why we bothered with anything else, to wildest fad follower using the latest language with the niftiest non-procedural construct, can look at and *instantly* understand. It's not worth a day of my time to explain templates, maps, and function pointers to people who will point out, with complete accuracy, that I just buried 10 lines of extremely simple code under a huge, reeking pile of totally unnecessary language coolness.

Share this post


Link to post
Share on other sites
Quote:
Original post by ScottMayo
It's worth noting that I currently work for a company where not everyone knows C++, and indeed not everyone is interested in being cool, OO and modern. There can be a lot of advantages to writing the simple code in a simple fashion that *anyone*, from the guys who grew up in Fortran 4 and don't know why we bothered with anything else, to wildest fad follower using the latest language with the niftiest non-procedural construct, can look at and *instantly* understand. It's not worth a day of my time to explain templates, maps, and function pointers to people who will point out, with complete accuracy, that I just buried 10 lines of extremely simple code under a huge, reeking pile of totally unnecessary language coolness.
That comes across more as a condemnation of the strange creature that is normal C++ code, more than anything else. Don't forget that the OP is working C# - a high level language with a mature container library, and simple delegates, as opposed to the small nightmare that is C++ templates and function pointers.

I would also argue that both the guy stuck in the Fortran era, and the guy who programs in buzzwords, should find stl containers and algorithms to be much easier to comprehend than the basic loops and hand-rolled constructs. If you aren't familiar with the language, a random_shuffle() or partition() is much clearer than the hand-rolled implementation thereof. And even your functional guy should have some LISP/related background in functional programming...

But quite apart from that, it doesn't require 'cool, OO and modern' to recognise where an approach is and isn't efficient, both in terms of performance and man-hours. An in-engine graphical console isn't something you implement on a whim to display the time of day - it requires considerable effort, and you aren't going to throw it away at the end of the week. Thus the if/else chain fails both criteria miserably - maintenance is horrific, and performance is only equivalent to the dictionary approach for a very small number of items. And when the list grows, and either the maintenance cost or the performance becomes unacceptable, you have to rip it out and use a dictionary *anyway*.

Chances are, by the time you are done with all that, you might as well have gone ahead and implemented the scripting language [smile]

Share this post


Link to post
Share on other sites
Quote:
Original post by ScottMayo
from the guys who grew up in Fortran 4 and don't know why we bothered with anything else


These people are not developing in Unity engine, using C# running on Mono. So whatever their opinion might be, it's not relevant in this thread.

Share this post


Link to post
Share on other sites
ScottMayo does imo make an interesting point though - maybe not applicable
in every situation but at the very least something to think about.

As an example,
I've got a little debugging webserver where you can register webpages (derived from abstract webpage class), register them at a server-class (derived from a connection/socket-class) which manages connections
and returns the requested pages (stored in a map of webpage*'s) - OO C++ like
anyone would use it.

Needed the same thing in a limited platform (had to go back to C), and honestly,
I went for the KISS approach, killed around 50-60% of the C++ code while rewriting
it to C, using a simple functionpointer-callback at one point, and it still
works.

Admitted, I now have a hardcoded limit for #pages instead of a dynamic container - and that's not because it wouldn't be possible, but rather because I wanted to get something up and running quickly to spend time on other things; it's easy to increase the hardcoded value - and if I really wanted, I could change the structure to be dynamic without changing the interface - *if the need arises*.

The excercise did make me think about the entire "lets abstract it away",
generating huge piles of wrapping/abstraction code, however ^^

ps: I do have to admit that not having constructors is annoying though...

Share this post


Link to post
Share on other sites
Quote:
Original post by Kitt3n
OO C++ like anyone would use it.
Except, apparently, me [smile]

Just because C++ is so often referred to as an OO language, doesn't mean that you can only write OO code. If you write idiomatic C++ using the standard library and boost, it ends up looking a whole lot more like functional programming.
Quote:
The excercise did make me think about the entire "lets abstract it away", generating huge piles of wrapping/abstraction code, however ^^
I hate to come out and say it like this, but if abstraction is requiring 'huge piles of code', then you are most likely doing it wrong.

And back to the strange discussion of if/else chains vs a dictionary, can someone please enlighten me as to why they feel that this:
if str == 'option1':
option1();
elif str == 'option2':
option2();
elif str == 'option3':
option3()
else:
raise Exception('unknown option: ' + str);



is preferable to this?
options = {'option1': option1, 'option2': option2, 'option3':option3}

options[str]()




[Edited by - swiftcoder on July 21, 2009 5:29:06 PM]

Share this post


Link to post
Share on other sites
[quote]Original post by swiftcoder

And back to the strange discussion of if/else chains vs a dictionary, can someone please enlighten me as to why they feel that this:
if str == 'option1':
option1();
elif str == 'option2':
option2();
elif str == 'option3':
option3()
else:
raise Exception('unknown option: ' + str);




is preferable to this?
options = {'option1': option1, 'option2': option2, 'option3':option3}

options[str]()



[/quote]

Easy one. The if-then-else option is blinding clear to anyone that knows any language - and I'd guess that people who have no exposure to languages at all might make a decent guess at what's going on. And it's very clear what happens if you don't match anything. It hits that exception-thing.

But that associative array code? I've seen a few languages over the years, so I have no trouble grokking what's going on there. But look at it with eyes that don't have your background. It's not even obvious that option1 is a function pointer, so even if you work out that the array "index" is an associative lookup and it returns what's on the right hand side of the colon, it might not be so clear that this is all about dispatching. But the real flaw to clarity is you completely hid the error path. What if str doesn't match anything? Well, you know that this associative array construct throws some sort of exception, presumably, and you know which one. But there's not *one clue* in this syntax about that. You just "have to know". And if you are writing for others, it's very much a problem how much they "have to know", just to understand what's fundamentally a trivial test-and-dispatch operation.

Now, of course, it depends on your audience. In a game devel environment where everyone knows a common language, there's not much wrong with being concise and leveraging the conveniences of a language. And if you're coding for yourself, hey, we've all chosen to save on keystrokes and let the code be a little mysterious now and then.

But I work on defense systems these days, and some of my coworkers have years of experience in languages so old you have not heard of them. Defense contracts give you an appreciation for code that ANYONE can read and get right. Because at the end of the day, only two things matter in my line of work: clarity and speed. And clarity is frequently the more important of the two.

Share this post


Link to post
Share on other sites
Quote:
Original post by ScottMayo
Now, of course, it depends on your audience. In a game devel environment where everyone knows a common language, there's not much wrong with being concise and leveraging the conveniences of a language. And if you're coding for yourself, hey, we've all chosen to save on keystrokes and let the code be a little mysterious now and then.

But I work on defense systems these days, and some of my coworkers have years of experience in languages so old you have not heard of them. Defense contracts give you an appreciation for code that ANYONE can read and get right. Because at the end of the day, only two things matter in my line of work: clarity and speed. And clarity is frequently the more important of the two.
As you say, audience is everything - in the context you describe, I have no real disagreement with your method. I would assume it is also unlikely that this audience would be writing significant software in a dynamically-typed scripting language, a la my python example [smile]

However, I do wonder how strongly 'clarity' relates to 'safety'. If clarity requires 5x more code, clarity is going to cause 5x more typos and copy/paste errors. I find that ensuring the correctness of tight, idiomatic code using standardised algorithms and containers is orders of magnitude easier than ensuring the correctness of spaghetti for loops and if/else chains.

Share this post


Link to post
Share on other sites
Quote:
Original post by ScottMayo

But I work on defense systems these days, and some of my coworkers have years of experience in languages so old you have not heard of them. Defense contracts give you an appreciation for code that ANYONE can read and get right. Because at the end of the day, only two things matter in my line of work: clarity and speed. And clarity is frequently the more important of the two.


This is all fine and dandy. But here is my assignment:
- Write a chatbox command parser (see any MMO or IRC)
- You will be provided with user's input string
- If line does not begin with / it is treated as chat
- A command takes the form of: "/command param1 param2 ... param n", params are separated by spaces and contain no spaces
- When a command is executed, a handler method is invoked
- Actual commands are currently not specified and will be defined and implemented by subsystem developers

Bonus (based on WoW's chatbox)
- commands may be added by user-provided plug-ins.
- commands may be redefined and re-routed

The language is C#, developers working on it will be CS graduates, full-time employed, with MS certification in C# and .Net 3.0.

My solution is above. Feel free to propose a simpler, cleaner, more readable one, that meets all the requirements above. Gotcha: real project (for better or worse) would require full unit test coverage of said functionality, which means that you need to take into consideration that if you hard-code anything, unit tests for console will need to test the invoked functionality as well. Like it or not, this is basically the norm today.

This is probably just as typical assignment as one can get, with as plain requirements as it gets, based completely and entirely off requirements of every such chatbox.

Share this post


Link to post
Share on other sites
I have decided to go with Antheus's solution with the dictionary of string to delegates as it provided the most flexibility without being too complicated. I am not worried about someone looking at the code that processes all the commands as they should never be touching that code (if they do, then they are trying to do someone that this system is not designed to do but again, the code it not really complicated).

The if/else if solution would be fine if i did not care about how easily I could add functions and did not care about be able to upgrade the system without break other poeple custom functions but I do care about that so that is just not a good solution for this project. With the dictionary solution, some can create a class with a bunch of static methods like:


class custom_commands
{
public static void setup_commands()
{
console_command_manager.add('command1', command1);
console_command_manager.add('command2', command2);
console_command_manager.add('command3', command3);
console_command_manager.add('command4', command4);
console_command_manager.add('command5', command5);
}

public static void command1(List<string> parameters)
{
//code for commands1
}

public static void command2(List<string> parameters)
{
//code for commands2
}

public static void command3(List<string> parameters)
{
//code for commands3
}

public static void command4(List<string> parameters)
{
//code for commands4
}

public static void command5(List<string> parameters)
{
//code for commands5
}
}


So know if I want to update the processing code, I can safetly do it without worrying about break other peoples code since there custom command will be in completely separate classes.

Thanks for all the input as the dictionary solution is so much simpler than the solution I was first think of.

Share this post


Link to post
Share on other sites
Quote:
Original post by ScottMayo
But look at it with eyes that don't have your background. It's not even obvious that option1 is a function pointer, so even if you work out that the array "index" is an associative lookup and it returns what's on the right hand side of the colon, it might not be so clear that this is all about dispatching.


I'd say if you were looking at it with eyes that didn't understand, you were in the enviable situation of learning something new, something that is very useful.

Despite your objections, the dictionary method is easier to maintain, easier to test and easier to extend. It is less error prone and has scalable performance. In terms of ease of implementation, I'd say they are pretty much on a par. Of the two solutions the dictionary method beats the hard-coded method hands down, why wouldn't you want people to learn if they didn't already know about it?

I get your point about the hidden error path, but if you're that worried about making that explicit then you could just handle the error condition there, just like in the hard coded version.

If someone is put off by things they don't understand, then computer science is not the place for them.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this