Output levels

A place to discuss everything about the Orxonox framework.

Moderator: PPS-Leaders

User avatar
x3n
Baron Vladimir Harkonnen
Posts: 810
Joined: Mon Oct 30, 2006 5:40 pm
Contact:

Re: Output levels

Post by x3n » Mon Jul 11, 2011 10:50 am

As you may have noticed, I created an "output" branch this weekend and will start working on this. I won't spend too much time on this, because everyone will be asked to polish their output themselves in future. I just try to get more or less useful output in console and logfile.

Additionally I came to a conclusion about different questions that were raised in this thread:
  • The output levels will be defined as in the second post of this thread. Their corresponding numbers will probably start at 1, while 0 is (forced) debug output (instead of -1)
  • Contexts will be defined as bitmasks (that's also why it's not so good to use -1 as debug output level)
  • The idea to use different macros for different output levels (e.g. COUT() and LOG()) is dropped because the output levels define only the importance and meaning of the message, but whether it appears in the console, the logfile, or somewhere else depends on the user's configuration. Therefore all output should use the same function/macro
  • Using different macros in the form of COUT_USER() and COUT_INTERNAL() is also not a good idea because there's no difference in typing between COUT(USER_ERROR) and COUT_USER(ERROR), but the latter requires the definition of ERROR which is dangerous.
  • No threadsafety for the moment
There is something else: I'll try to define COUT() as a function instead of as a macro. If this works, capital letters are not appropriate anymore. However cout() looks like a bad idea, so I suggest orxout(). As a consequence, output levels should also be defined lowercase, e.g. orxout(user_error) << "Some text" << std::endl; This looks more homogeneous and is easier to type than capital letters.

Any objections against this?

outlook:
In future I can imagine a more fundamental change of the output system (but then no changes to the output itself ;)), including thread safety. For example we could have a more STL-compliant system which uses manipulators. this could look like this:

Code: Select all

orxout << user_error << "Some text" << std::endl;
orxout << threaded << verbose << context(network) << "asdfasdf" << std::endl;
However I'm not sure if everyone would like this notation...

Everyone please share your opinion, both about the current decisions and the future suggestions.
Fabian 'x3n' Landau, Orxonox developer

User avatar
1337
Baron Vladimir Harkonnen
Posts: 521
Joined: Wed Oct 10, 2007 7:59 am

Re: Output levels

Post by 1337 » Mon Jul 11, 2011 1:46 pm

Hmm, I would still like macros with different names ;)
I'm just a bit afraid that people may drop certain bits just because of laziness. The macro name could also denote the importance. But I'm running out of linguistic ideas here...
But can you at least keep the dbgout function for forced output? I would like something that can very easily and reliably searched for before merging a branch.

@Function instead of macro: I guess you don't have to ask about my opinion ;)

@Manipulators: I like the unified notation, but it might again be a little longer in terms of characters.
However if the idea is generally accepted, I suggest implementing it right now because the extra time is probably around 10 minutes. And all the COUTs have to be rewritten anyway.

One last point about performance: so far we've always been a little concerned about that point, e.g. by introducing a hard debug level. I disagree that we should sacrifice performance for usability and instead just watch out for output that fires more than 10 times a second (in the game loop, not recommended anyway) or massive outputs while loading (I'm talking about a lot more than the current loading output). This concurs with your design, but I would really like to encourage using new ideas that improve usability or readability even if it is quite a bit slower. The reason is simple: it doesn't matter. We're doing so much that output can almost completely be neglected (unless overused of course). And secondly, output is very, very important for us developers.
http://www.xkcd.com/
A webcomic of romance, sarcasm, math, and language.

User avatar
1337
Baron Vladimir Harkonnen
Posts: 521
Joined: Wed Oct 10, 2007 7:59 am

Re: Output levels

Post by 1337 » Mon Jul 11, 2011 2:13 pm

Some statistics: We have 897 COUT occurrences in 206 files for the MSVC source code. That comprises:
  • COUT(0): 116
  • COUT(1): 244
  • COUT(2): 201
  • COUT(3): 73
  • COUT(4): 208
  • COUT(5): 52
  • COUT(6): 3
A question: std::endl or just endl? We could unify that too (should be fairly simple) so that new people would do it the preferred way right away.

A question: Do we keep CCOUT in some form or not? So far it just prefixed the error message with the class name.

A comparison:

Code: Select all

COUT(2) << "Warning: Can't attach a WorldEntity to itself." << std::endl;
orxout(user | warning) << "Can't attach a WorldEntity to itself." << std::endl;
orxout << user << warning << "Can't attach a WorldEntity to itself." << std::endl;
Does that correspond to the what it's going to look like? I'm just curious as to what we'll actually see in the end.

EDIT:
A remark: Looking at macro collisions with MSVC, I don't get any problems with the following variables:
USER, NORMAL, INTERNAL, VERBOSE, STATUS, WARNING, INFO
user, normal, internal, verbose, status, warning, info, error
(Only ERROR seems problematic).
http://www.xkcd.com/
A webcomic of romance, sarcasm, math, and language.

User avatar
x3n
Baron Vladimir Harkonnen
Posts: 810
Joined: Mon Oct 30, 2006 5:40 pm
Contact:

Re: Output levels

Post by x3n » Mon Jul 11, 2011 2:39 pm

1337 wrote:Hmm, I would still like macros with different names ;)
you mean different output macros/functions/streams (depending on our final implementation) for user, internal, and verbose output?
I'm just a bit afraid that people may drop certain bits just because of laziness. The macro name could also denote the importance. But I'm running out of linguistic ideas here...
I don't understand this part: what bits may be dropped? And how is this related to the name of the output function? Do I understand this right that you want shorter names? Maybe you could provide some examples.
But can you at least keep the dbgout function for forced output? I would like something that can very easily and reliably searched for before merging a branch.
I love the idea behind the DOUT macro and I definitely want to maintain this feature.
Something like dbgout() could work, but maybe it's easier to remember if it's called the same as normal output? If people have to remember "what's the name of the debug output again" they may just use orxout(user_status) instead which is clearly not intended.
With the orxout function we could define a default value, e.g. orxout() << "debug" in contrast to orxout(level) << "message". Or just a specific level, e.g. orxout(debug), orxout(none), or orxout(0). Maybe I should emphasize that forced debug output has it's own level, different from e.g. user_status, so it should always be possible to find debug output.

@Function instead of macro: I guess you don't have to ask about my opinion ;)
I know that you're a secret macro lover :lol:
@Manipulators: I like the unified notation, but it might again be a little longer in terms of characters.
However if the idea is generally accepted, I suggest implementing it right now because the extra time is probably around 10 minutes. And all the COUTs have to be rewritten anyway.
exactly my thought, but since I announced only small changes and this is such a drastic difference, I'm a bit afraid that not everyone likes it. Also there are some potential problems, e.g. because one could forget the output level. I'd definitely like to hear more people's opinion about this.
One last point about performance: so far we've always been a little concerned about that point, e.g. by introducing a hard debug level. I disagree that we should sacrifice performance for usability and instead just watch out for output that fires more than 10 times a second (in the game loop, not recommended anyway) or massive outputs while loading (I'm talking about a lot more than the current loading output). This concurs with your design, but I would really like to encourage using new ideas that improve usability or readability even if it is quite a bit slower. The reason is simple: it doesn't matter. We're doing so much that output can almost completely be neglected (unless overused of course). And secondly, output is very, very important for us developers.
Well there is quite some overhead with output, but you're right that it's still just a small fraction and probably except for the network we don't have much repeating output. But how exactly does that concur with my design? In fact my suggestion to omit the macro drops the hard debug level and the soft debug level will be moved to the << operator. So there are barely any performance considerations in my design.
A question: std::endl or just endl? We could unify that too (should be fairly simple) so that new people would do it the preferred way right away.
I think we already allow the usage of endl without std::. Personally I don't care and I don't think it makes a big difference. Just endl is easier and everyone's welcome to use it. ;) However I prefer endl over "\n".
A question: Do we keep CCOUT in some form or not? So far it just prefixed the error message with the class name.
To be honest I'm not a big fan of CCOUT and I don't think I ever used it. In fact I got mislead by it just recently when I got an error message in the form of "ControllableEntity: something's wrong", so I wen't to ControllableEntity.cc and searched for the message, but with no luck. Then I searched the whole project and found the message in WorldEntity.cc, which is a base class of ControllableEntity.
Of course I know (or better said, now I remember) that CCOUT just prints the name of the derived class, but in that case it was more distracting than helpful (I expected it to print something like __FILE__).
Does that correspond to the what it's going to look like? I'm just curious as to what we'll actually see in the end.
Well the concatenation of "user" and "warning" is interesting, but I think it's more confusing than just user_warning as a single token. So it will probably rather look like this:
orxout << user_warning << "Can't attach a WorldEntity to itself." << endl;

Note that this example is probably rather an internal warning than a user warning, since the problem is not caused by the user ;)
Fabian 'x3n' Landau, Orxonox developer

User avatar
1337
Baron Vladimir Harkonnen
Posts: 521
Joined: Wed Oct 10, 2007 7:59 am

Re: Output levels

Post by 1337 » Mon Jul 11, 2011 5:08 pm

x3n wrote: you mean different output macros/functions/streams (depending on our final implementation) for user, internal, and verbose output?
Yes, but only because it's shorter.
x3n wrote: I don't understand this part: what bits may be dropped? And how is this related to the name of the output function? Do I understand this right that you want shorter names? Maybe you could provide some examples.
orxout(user | warning) might be abbreviated to orxout(warning) if there is a default value for the target.
x3n wrote: I love the idea behind the DOUT macro and I definitely want to maintain this feature.
Something like dbgout() could work, but maybe it's easier to remember if it's called the same as normal output? If people have to remember "what's the name of the debug output again" they may just use orxout(user_status) instead which is clearly not intended.
With the orxout function we could define a default value, e.g. orxout() << "debug" in contrast to orxout(level) << "message". Or just a specific level, e.g. orxout(debug), orxout(none), or orxout(0). Maybe I should emphasize that forced debug output has it's own level, different from e.g. user_status, so it should always be possible to find debug output.
I like orxout(). That's easy to find.
x3n wrote:
@Manipulators: I like the unified notation, but it might again be a little longer in terms of characters.
However if the idea is generally accepted, I suggest implementing it right now because the extra time is probably around 10 minutes. And all the COUTs have to be rewritten anyway.
exactly my thought, but since I announced only small changes and this is such a drastic difference, I'm a bit afraid that not everyone likes it. Also there are some potential problems, e.g. because one could forget the output level. I'd definitely like to hear more people's opinion about this.
My concerns too. What about a mail to the orxonox dev mailing list? Everyone should get that pretty quickly.
x3n wrote: Well there is quite some overhead with output, but you're right that it's still just a small fraction and probably except for the network we don't have much repeating output. But how exactly does that concur with my design? In fact my suggestion to omit the macro drops the hard debug level and the soft debug level will be moved to the << operator. So there are barely any performance considerations in my design.
Macmillan English Dictionary for Advanced Learners:
To concur: to agree with someone or something
x3n wrote: I think we already allow the usage of endl without std::. Personally I don't care and I don't think it makes a big difference. Just endl is easier and everyone's welcome to use it. ;) However I prefer endl over "\n".
I agree.
x3n wrote: To be honest I'm not a big fan of CCOUT and I don't think I ever used it. In fact I got mislead by it just recently when I got an error message in the form of "ControllableEntity: something's wrong", so I wen't to ControllableEntity.cc and searched for the message, but with no luck. Then I searched the whole project and found the message in WorldEntity.cc, which is a base class of ControllableEntity.
Of course I know (or better said, now I remember) that CCOUT just prints the name of the derived class, but in that case it was more distracting than helpful (I expected it to print something like __FILE__).
I haven't yet thought about the search problem. And I'm a big fan of that. I also don't like auto generated log very much (apart from a number or two).
So I definitely think we should get rid of CCOUT.
x3n wrote:
Does that correspond to what it's going to look like? I'm just curious as to what we'll actually see in the end.
Well the concatenation of "user" and "warning" is interesting, but I think it's more confusing than just user_warning as a single token. So it will probably rather look like this:
orxout << user_warning << "Can't attach a WorldEntity to itself." << endl;
I would prefer that too. I thought you wanted to go for bit masks.
x3n wrote: Note that this example is probably rather an internal warning than a user warning, since the problem is not caused by the user ;)
I had a look at your first post and thought that this message should definitely be visible in the console (not for the release version though). So I went for "user" because "internal" would only be written to the log file.
http://www.xkcd.com/
A webcomic of romance, sarcasm, math, and language.

User avatar
x3n
Baron Vladimir Harkonnen
Posts: 810
Joined: Mon Oct 30, 2006 5:40 pm
Contact:

Re: Output levels

Post by x3n » Mon Jul 11, 2011 6:06 pm

1337 wrote:Yes, but only because it's shorter.
[...]
orxout(user | warning) might be abbreviated to orxout(warning) if there is a default value for the target.
[...]
I would prefer that too. I thought you wanted to go for bit masks.
Nope, bitmasks only for contexts (unless you disagree, but I think combining bitmasks is nothing our devs should be forced to do by default).
x3n wrote: I love the idea behind the DOUT macro and I definitely want to maintain this feature.
I like orxout(). That's easy to find.
but if we use the stream syntax, we need a different solution. maybe again dbgout, or a dedicated constant for the debug output level.
Macmillan English Dictionary for Advanced Learners:
To concur: to agree with someone or something
oh crap, I thought that means "konkurrieren" :D
I had a look at your first post and thought that this message should definitely be visible in the console (not for the release version though). So I went for "user" because "internal" would only be written to the log file.
Yep, should be visible, but only if developers configure orxonox to show also internal errors and warnings in the console (which will be the default for debug builds). In my opinion it's not a user warning, because there's no real "danger" for the user and because the same warning could happen multiple times (or every tick) during a match. But it depends on the judgment of each developer how he classifies an output message... in the end, the output has to be good, that's the only requirement. And now define "good" ;)
Fabian 'x3n' Landau, Orxonox developer

User avatar
x3n
Baron Vladimir Harkonnen
Posts: 810
Joined: Mon Oct 30, 2006 5:40 pm
Contact:

Re: Output levels

Post by x3n » Tue Jul 12, 2011 8:03 am

After thinking about the stream notation (orxout << user_warning << "Some text." << endl;) I came to the conclusion that there is a fundamental problem: the syntax allows orxout << "Some text." << endl; without specifying an output level.

So what's the behavior in this case? There are two possible solutions: A) It uses the output level which was defined last, B) It uses by default the (forced) debug output level

The problem with A) is that, for example if the last defined level was "verbose", the output may not be visible in the console nor the logfile, which would be very confusing.
The problem with B) is that it creates forced debug output which can not be found easily if you search the source code.

So the behavior is undefined, or - if we define it - not intuitive. Therefore we have to assure there's always an output level defined. This could be achieved for example if "orxout" returns a temporary object which accepts only output levels. "orxout << level" then returns the real output stream object. However this breaks the unified stream syntax.

For this reason, the stream syntax is not appropriate in my opinion. Hence we will probably remain with orxout(level) << "Some text." << endl; This syntax ensures there's always an output level defined.
Fabian 'x3n' Landau, Orxonox developer

User avatar
1337
Baron Vladimir Harkonnen
Posts: 521
Joined: Wed Oct 10, 2007 7:59 am

Re: Output levels

Post by 1337 » Tue Jul 12, 2011 12:33 pm

Yeah, it also separates message attributes from the actual message.

The only possible application for manipulators I see would be context. But again, it just doesn't look right. And it's more to type anyway.

Something else I just noticed: we could go for unit64_t for the bit mask. Then we'd have about 60 different contexts instead of about 28.
http://www.xkcd.com/
A webcomic of romance, sarcasm, math, and language.

User avatar
x3n
Baron Vladimir Harkonnen
Posts: 810
Joined: Mon Oct 30, 2006 5:40 pm
Contact:

Re: Output levels

Post by x3n » Tue Jul 12, 2011 1:02 pm

Yeah and there's actually no real reason to put level and contexts into the same value... orxout(level, context) should work as well. orxout(level) means no specific context (0) (or maybe all contexts (111111...)? but 0 is probably better). Then we have 64 contexts - or 65 if we use very small bits. :coding:
Fabian 'x3n' Landau, Orxonox developer

User avatar
1337
Baron Vladimir Harkonnen
Posts: 521
Joined: Wed Oct 10, 2007 7:59 am

Re: Output levels

Post by 1337 » Tue Jul 12, 2011 1:11 pm

I feel kind of stupid, but orxout(level, context) seems way better.
I'm not even sure whether we should allow a default context. On the other hand, it's sometimes really difficult to actually identify the right context.
http://www.xkcd.com/
A webcomic of romance, sarcasm, math, and language.

User avatar
x3n
Baron Vladimir Harkonnen
Posts: 810
Joined: Mon Oct 30, 2006 5:40 pm
Contact:

Re: Output levels

Post by x3n » Tue Jul 12, 2011 1:36 pm

I see contexts more as a tool to get only the desired output of some level than as a requirement. So I wouldn't enforce it, but you can use contexts on every level if you want.

I just had the idea that you could have an output listener for user level with level loading context, to get all loading related messages - then you display them on the loading screen. So in this case it makes sense to use a context, but it's no harm if you don't.
Fabian 'x3n' Landau, Orxonox developer

User avatar
x3n
Baron Vladimir Harkonnen
Posts: 810
Joined: Mon Oct 30, 2006 5:40 pm
Contact:

Re: Output levels

Post by x3n » Tue Jul 26, 2011 8:49 am

The output system is more or less re-implemented with what I believe to be the same amount of features, but with a different architecture. For example, LogWriter (a class inheriting from OutputListener which writes output to a log file) is now implemented as a singleton, instead of accessing it indirectly through OutputHandler.

OutputManager, OutputStream, and orxout()
OutputHandler is removed and its functionality split into OutputManager, which distributes output to the registered OutputListeners, and OutputStream, which is a derivative of std::ostream and is used similar to std::cout.

In particular, you can write this code: OutputStream() << "Some text" << endl; This will send "Some text" to the OutputManager. Since creating an instance of OutputStream for every line of output is slow, orxout() returns a static instance of this class. Note that it may return a different static instance in every library of orxonox, but that doesn't matter. This design allows us to use different instances of OutputStream in each thread, even though thread safety is not yet achieved (OutputManager is not thread safe). But future changes are possible.

It's important to know that OutputStream sends a "message" to OutputManager whenever you use "endl". An example:

Code: Select all

OutputStream() << "Some text"; // does NOT send anything to OutputManager
OutputStream() << "Some text" << endl; // sends "Some text" to OutputManager
OutputStream() << "Some text" << '\n'; // does NOT send anything to OutputManager
OutputStream() << "Some text" << '\n' << "More text" << endl; // sends "Some text\nMore text" to OutputManager
Note that this example constructs a temporary instance of OutputStream for every line, hence output which is not sent to OutputManager is lost after the ";". Using orxout() this behaves differently:

Code: Select all

// this sends "SomeText" to OutputManager:
orxout() << "Some";
orxout() << "Text";
orxout() << endl;
Summarized, you should always use "endl" at the end of a message. Use \n only to split a single message into multiple lines. (Note that using endl is superior to \n anyway, since endl flushes the output buffer, but \n doesn't. Hence one should always use endl, also with std::cout)

Output levels
Concerning the output levels, there is also a point worth mentioning: They are not defined as numbers from 0 to x anymore, instead they are defined as binary masks from 0x0001 to 0x8000. It doesn't make sense to combine these masks for one line of output (e.g. the level of some output should always have only one bit set to 1), but it makes sense for OutputListeners to define the output they want as a mask (e.g. user_error | user_warning defines a mask that accepts only errors and warnings at the user level). However this is usually hidden from the developers, so the only common way to use output levels is in orxout(level).

Output contexts
With output masks we have the same, they are also defined as binary masks but this time with 64 bits, allowing a maximum of 64 different contexts. Note that "no specific context" is also a context, hence we remain with 63 effectively usable bits. As with output levels, an OutputListener can also define a mask of allowed contexts. The default listeners (LogWriter, ConsoleWriter) accept output of all contexts (their mask equals 0xFFFFFFFFFFFFFFFF).

However defining a context is a bit more difficult, because I want to assign a string to each context, e.g. "Network" to the network context. This allows us to print the output of a message to the log, and it also allows us to define the desired output contexts in the config file as strings instead of very complicated integer numbers.

To do so, one could use a pattern like this:

Code: Select all

OutputContext network = registerContext(0x0000000000000001, "Network");
But since we have to call registerContext() anyway, this function can generate the context itself, which leaves us with this code:

Code: Select all

OutputContext network = registerContext("Network");
In particular, OutputManager maintains a map with all contexts and their strings. If a string doesn't exist in the map, a new context is generated, otherwise the existing context is returned.

Unfortunately there is a problem because the contexts are defined in a common header file, these statements are included in virtually every source file. This means that registerContext() is called once for every context TIMES the number of source files. If in future we have 50 contexts and 2000 source files (we already have more than 350), we end up with 100'000 calls to registerContext(), which means 100'000 lookups in a map for a string. I have no clue how long this takes, but let's say 1 second. This is not much, but 1 second more between you start orxonox and before it actually starts loading might just be 1 second too much for the user.

So I decided to use functions instead of global variables, which allows a lazy initialization (and registration) of the contexts:

Code: Select all

OutputContext network() { return registerContext("Network"); }
Now this calls registerContext() every time you use the context, which can be improved by calling it only once and storing the result:

Code: Select all

OutputContext network() { static OutputContext context = registerContext("Network"); return context; }
Now this would mean that you have to use contexts this way (Note that all contexts are defined in the "context" namespace):

Code: Select all

orxout(level, context::network()) << "Some text" << endl;
But I'm a friendly person and allow you to pass contexts also directly as a function:

Code: Select all

orxout(level, context::network) << "Some text" << endl;
orxout then calls the context-function internally.


So far that's it, lots of internal details, but I thought some of you (reto) might be interested. Now I'm about to replace calls to the old implementation with their new counterparts. This may take some time because, for example, I also have to adapt the bindings of lua and tcl to orxout (formerly COUT) in a way which allows using the new levels and possibly also contexts.
Fabian 'x3n' Landau, Orxonox developer

User avatar
1337
Baron Vladimir Harkonnen
Posts: 521
Joined: Wed Oct 10, 2007 7:59 am

Re: Output levels

Post by 1337 » Tue Jul 26, 2011 1:33 pm

Lua's going to be fun. Somehow you can just do almost anything you want in that language ;)

Thanks a lot for sharing the details, I've read it with great interest.

If I look at the implementation of output contexts, shouldn't it be possible to define them in another file that OutputDefinitions.h?

So, technically, I see it possible to even define a function netout() in NetworkPrereqs.h that automatically adds the network context (and that could then be refined by one or two extra contexts).
Where's the catch?
http://www.xkcd.com/
A webcomic of romance, sarcasm, math, and language.

User avatar
x3n
Baron Vladimir Harkonnen
Posts: 810
Joined: Mon Oct 30, 2006 5:40 pm
Contact:

Re: Output levels

Post by x3n » Tue Jul 26, 2011 1:55 pm

Yes you can define netout() and yes you can define output contexts wherever and however you want. The most generic form is probably OutputStream(level, registerContext("name")). Everything else, like orxout() or the context functions, are just for convenience (or speed).

Originally I put the contexts into OutputDefinitions.h because they were defined as contextname = 0x001, etc, so it was important to gather all contexts at the same place to avoid using the same number for two different contexts. Later i kept the contexts in OutputDefinitions.h because I feel they should be included together with orxout() because it is tedious if you have to include two separate files for the same thing. Of course you can achieve the same by defining them in a Prereqs.h file or another common header file (except for UtilPrereqs.h which is not a good choice because of possible circular includes, hence all util-related contexts fit well into OutputDefinitions.h anyway).

Personally I have no preference, but it's obvious that commonly used contexts like "undefined" or contexts which are used in multiple unrelated files need to be defined in a common place, while for example the "network" context could be defined in NetworkPrereqs.h and the "gametype" context in Gametype.h


Edit: One should also consider that we have a limit of 63 contexts, so refining the network context with a multitude of sub-contexts might not be a good idea. If this limitation turns out to be a problem, we need another concept - for example by defining contexts by real numbers instead of a mask, or by using two context variables (major/minor). Or we might just use plain strings. But I guess in the short term we're fine with about 20 contexts, this should already cover most of the framework - and game logic is not supposed to print output anyway.
Fabian 'x3n' Landau, Orxonox developer

User avatar
1337
Baron Vladimir Harkonnen
Posts: 521
Joined: Wed Oct 10, 2007 7:59 am

Re: Output levels

Post by 1337 » Tue Jul 26, 2011 2:28 pm

x3n wrote: Personally I have no preference, but it's obvious that commonly used contexts like "undefined" or contexts which are used in multiple unrelated files need to be defined in a common place, while for example the "network" context could be defined in NetworkPrereqs.h and the "gametype" context in Gametype.h
That's exactly how I see it.
x3n wrote: Edit: One should also consider that we have a limit of 63 contexts, so refining the network context with a multitude of sub-contexts might not be a good idea.
That's why I said one or two sub contexts and not two or three ^^
For the moment, I don't think we'll run into problems with too few contexts because I suggest to minimize them anyway to prevent unnecessary confusion.
http://www.xkcd.com/
A webcomic of romance, sarcasm, math, and language.

Post Reply

Who is online

Users browsing this forum: No registered users and 8 guests