Building states

First of all, everything static cultural object you can see in BE qualifies internally as “a building”. Radio on a table? Building. The table itself is a building. We’ve had a problem for a while now where people would see the wrong state. Over the years there have been a number of causes for various instances of the problem but the last year there have been some pretty consistent ones.

This causes a host of things from apparent clipping, firebases that don’t seem to want to blow, people seeing bridges in different states, to people thinking a town is bugged because they can see a radio table but can’t capture it.

It only took a year, two open betas, lots and lots of reports, 6 coders, a change of compilers and a countless unit tests. Finally, in the last open beta I got a consistent replication – flying Mendig to Koblenz. I finally isolated the zone of functionality with Rickb’s help and – with the help of VS 2008’s code analysis…

Propogation of building states is not trivial. There are several layers of strat data on the client, and the zone of authority for each is kind of poorly defined. Add in that there are several layers of queueing – data can load in an indeterminate pattern: you might get the strat info from the host before the client has loaded the baseline strat data for the supercell or the octet or the facility or the building or the building model. Different queues apply depending on the condition.

And there was the problem. In one particular sequence, the code assumed a certain value was being setup, but elsewhere in the code the reverse assumption was made – that the data would be queued and loaded when the receptacle was finalized.

It comes down to a one line change (if building is loaded then apply the data now otherwise update the loading stub).

With that added, I think we will finally have nixed it, just in time for Rickb’s new engine which reduces the number of layers and strongly defines authority, as well as using inheritance so that the data doesn’t need to be replicated and thus cross-maintained.

Hopefully that will mean a quick and simple client 1.28.3 patch with the fix sometime this week. It’s wonderful to get that ticket closed. If we can nail the firebug as easily, those will be gloriously tedious tail-dragging bugs off the slate and a chunk of dev team freed up for each dev cycle.

It seems like something that ought to be so much simpler to track down but some of the old design and philosophies make things like it so indescribably difficult to work through this kind of issue – its just not possible to write meaningful, closed unit tests.

The flip side of the coin is the argument for writing the code the old way – efficiency. A fallacy. If you were to liken it to painting – yes, a simple, effortless stroke of the brush produces rich, deep colors, but the effort required to provide a precise, specific shape or line of a particular hue, texture and definition is increased manyfold by the interaction with other strokes.

In a smaller, less complex system, the old method might have made sense. But as you accumulate external interactors, you accrue overheads. a=b+c is nice and simple and efficient, but when it starts to expand out to a=(b or if b is null then find the price of coal and multiply by the length of a piece of string)+(c unless c is 3, in which case add d+g together and divide by n) it’s become less efficient.

It’s also mean’t seeing some of the client’s hideous underbelly. I thought the host was bad, but even we never had anything like

somefunction(char *longString)
{
    if (strlen(longString) == 0 || longString == NULL)
       ...
}

32 Comments

This is good news, hopefully this will be the last we see of this problem.

Now the client guys just need to find the cornflakes bug and we’ll be all set. ;)

I’ll bite, what’s wrong with the code example?

(In my defence, I’ve got about 3 days total C/C++ programming under my belt and that’s been spread over 15 years.)

I am *so* jonesing for a rickb update. Glad to hear you got the state issue discovered/repaired. I /reported an old one again last night, AA AI firing only west (Baarle-Hertog, right in front of the veh spawn). With enough time and patience, these things will expose themselves.

That will always resolve with a false. Always. Zero and null will never be equal. Null means nothing, no values whatsoever is stored. Zero means that something was stored, but it’s length is zero. So if the function always returns flase, why waste the effort to compare. Or if the intent was to return true, it will never return true.

Strlen will crash if passed a NULL. And the way to test if a string pointer has zero length is just to check if the first byte is 0. “strlen(x)” has to count the bytes in x. The code is equivalent to this:

int len = 0 ;
while ( longString[len] isn’t 0 ) ++len ;
if ( len == 0 or longString is an invalid pointer ) then return ;

when what the coder really mean’t was

if ( longString is an invalid pointer or longString[0] == 0 ) then return ;

If longString is generally going to be empty, and you need the length if it isn’t, then doing

if ( longString is in invalid pointer ) then return ;
int len = strlen(longString) ;
if ( len == 0 ) then return ;

might not be so unreasonable.

You couldn’t replicate the “buildings in different states for you and me” issue in Roosendaal? With the building immediately south of the AB destroyed and spawners at the AB seeing it intact and people spawning from the South depots seeing it destroyed?

This has been 100% reproducible for me. I’ve posted simple, detailed, and ridiculously detailed steps for reproducing several times, going back probably to 2003.

Lead a horse to water…can’t make ’em reproduce.

Not sure that’s the way that saying’s sposed to go…sounds kinda wierd. Oh well.

…@/

I personally liked how how the variable name ‘long string’ was being checked if it was an empty string… because its a long string but maybe not!

Bad variable names is a personal pet peeve of mine.

This has been 100% reproducible for me. I’ve posted simple, detailed, and ridiculously detailed steps for reproducing several times, going back probably to 2003.

I fixed the Willemstaad bug you described in 2004, the code that caused the version I just fixed has only been in the code base since 2007.

You left off the :p

So is zero and null the same in C++? In my database centric world,null and zero are not always the same.

Hmm. Its a little hard to explain. 0 and null are the same. The exception to this is when the number you are talking about is supposed to be a memory address of an actual value (called a pointer in C/C++) .

For instace, you might load a jpeg into memory. Lets say you load a 10,000 byte jpeg into memory starting at the 5001st byte of memory. The “address” of the jpeg is “5001” to “15,001”, so a pointer-variable which ponts to the jpeg has the value “5001”. This pointer-variable is otherwise indistinguishable from a normal variable, only telling the compiler that it is a pointer constrains how you might use it.

int i = multiply(5 ,2);
pointer p = loadJpeg();
print(i);
print(p);

would print “10” and then “5001”. P is a variable, so it contains a single value, but you’re denoting that it is a pointer so that the compiler will understand its a po-box of real data, to get the jpeg you have to say “the value(s) AT p”, which is C syntax is “*p”, e.g.

print(*p);

The caveat is that if the value of this variable “p” is 0, then it is pointing to nothing, and the computer can’t read “nothing” so if you try to use it as an address, as a pointer, it will crash the application.

So C/C++ don’t have a concept of a NULL variable beyond giving it value 0. However, when the variable is a pointer, we call it a NULL pointer if its value is 0. Zero and NULL are the same, but zero isn’t going to mean anything if you try to read that address in memory.

int i = 10;
pointer pi = addressOf(i);
print(i); // Outputs 10
print(pi); // Might output 2349348, whatever the address of ‘i’ is in memory.
print(*pi); // Outputs 10 – whats AT that address

pointer p = 0; // Quite valid, but normally written as p = NULL for clarity
print(p); // outputs: 0
print(*p); // crashes

So in C/C++ you can distinguish between a value and no value by using a pointer instead of hte value itself.

So, back to our jpeg example. The function to load a jpeg might first check to see if the file exists. If the file is not found, it might return NULL (0) as the address for the loaded image, to tell me “the image is nowhere in memory”.

pointer p = loadJpeg(“fruitloop.jpg”);
if ( p == NULL ) then give up;
else …

The difference between a pointer and a variable can be a hairy thing to describe because both of them are just numeric values, the difference is purely contrived – in the above examples the compiler will complain to you if you type “*i” because you didn’t declare “i” as a pointer.

Its really akin to postal addressing. Playnet is at 1901 Central Drive, Suite 400. There are two numbers here. 1901 is the street address and 400 is the suite number.

If you were to write on an envelope

address 1901 Central Dr

you’re declaring a pointer – meaningfully telling the postman where to drive to. That is Playnet’s location in the world. In the context of our building “suite 400” is our value. We could be anywhere in the build – akin to having any value – but we’d still be at 1901 central drive.

If you instead wrote

suite 400

the postman couldn’t find us. It only has meaning inside the address.

So – it is possible to distinguish between a value and NULL, and its possible to distinguish between a pointer to a value that contains zero (“if *p == 0”) and a pointer that does not point to a value (“if p == 0”), but only if you step back and deal with a pointer.

I completely agree with the code example and your interpretation.

There’s a simple rule to avoid that and some sideeffect matters being aligned to that case:

Do never ever use OR, when u can have two code block instead:

if (first)
if (second)

That’s even better for error propagation, as far as i am concerned. :D

But why?
However, the order of expression evaluation is/was unspecified and therefore compiler dependant (§ 5.2.2, iso c++, i’ve googled that :D), as far as i recall.

Example: some compilers support quick evaluation (breaking an AND (&&) at the first FALSE, don’t evaluate the 2nd expression eg.) , some (older) compilers don’t. If the compiler in use starts with the rightmost expression and evaluates a true for IsNull and breaks (one TRUE is enough for an OR-expr) the first code example above *will* work without causing a crash. Keep that in mind, folks, if you tend to write reusable code parts to be still in use in let’s say 20 years.

To be clear, i don’t like that, i completely share your point of view, kfs1. And if i am wrong, don’t beat me. That’s what i remember…
And “writing solid code” says:

somefunction:
if (NULL != longString)
{
if (0 != strLen(longString)
{
..do smth. valid..
return ok;
}
return empty;
}
return invalid;

best regards

That’s unfortunately not that uncommon. Just the other day I was reviewing some people’s code for a consultant job and I found a similar, even though in Java, “gem”:
———-
String whatever = …. some method that returns a String
if(whatever.length()==0 || whatever.equals(null))
{

}
———-
For those not versed, calling length() on a null String will throw an exception, calling equals() on a null String will throw an exception, and even if you could call it, equals() when applied to a null value always returns false (unless you change the implementation and you are nuts ; ) ).

I have to say the coder was fired that same day, even though not just for that and not due to my review. I would have not felt guilty though, that was the “best” I could find from him.

Oh well, good for me :).

Kudos on the fix!

If you’re worried about compilers that don’t use short-circuiting on logical conditions, you’re going back to the 1970s. CF: The MMDF mail system’s source code relies on short-circuiting.

IMHO, it makes sense to group certain logical ands/ors together, particularly when they are related.

if ( string == NULL || *string == 0 )

are both looking for an empty or non-existent string.

Incidentally, it’s a stylistic thing, but I’ve never understood

if ( NULL ==
or
if ( NULL !=

NULL doesn’t change. Why are you testing it against something?

Is this an homage to Yoda speak? “If $5000 in your pocket have, not break legs will I” :)

Did your school teacher ask you trick questions like “are 6 the number of apples you have left after I give you three apples plus three apples?” :)

Yes, Mr Space-Semicolon is questioning someone else’s coding style – its one of those things that is purely stylistic. Maybe its easier for people who’s first language isn’t English to read, but as an English speaking coder I find “NULL != stringPtr” a very strange way to the question “is this variable empty?” :)

Er…I’m a C# guy so I’m not sure on this, but isn’t that code example also testing the length of a pointer instead of the value of the pointer??

null != val is also a pet-peave of mine. Who thinks this way?

I know some people (not myself) like to do:

if( rvalue == lvalue )

so if they typo a single equals (assign to) the compiler will pick it up rather than silently test the truthfullness of the rvalue.

Ok, that explanation makes sense, xiper. I’ve only ever had it explained stylisticly so I’d never even thought of that.

<- converted.

cowboy, strlen takes a pointer argument. C/C++ generally pass a pointer unless the function proto expects an array.

:D
Of course it is not ~style~. Discussions about style are a waste of time, only important to people who don’t have anything else to talk about. Sorry.

I care for good reasons.

Avoiding an error by using a CONST as LVALUE (u see) is definitely a good reason. I don’t want to test, whether or not i can assign 5 to i, when i want to know, if i actually *is* 5.

This trick is very common. I know companies, where comparisions have to be DONE that way (if possible). It’s is not a matter of like or dislike. It’s a matter of rules to keep the amound of potetial errors as small as possible and make testing easier.

I simply ignore your stupid sentencenses about Master Yoda :) and your laughters. The force of course no longer will be with u, young pavian! :D

The short circuit or fast evaluation depends on one simple thing you forgot to mention. Question is:
Which expression inside the expression evaluates first? Leftmost or rightmost?

And that is, what i tried to say: AFAIK this is not specified. It is clear for your compiler or family of compilers, it might be documented, if you are lucky. But it is *not* global. And the comparision OR-line of your very first code-post *WILL* work with compilers which start with the rightmost expression. And it won’t today with your modern set.

Left most evaluates first, and has done since the 80s, that’s part of the ANSI standard. If there is a compiler which doesn’t, please name it. Microsoft (VC5 and above), Intel (all versions), GCC (all versions), Sun’s CC (all versions), Borland, TCC, mkcc, Lattice C, SAS C… All implement left-to-right with shortcircuiting.

And if you’re talking about C++, it’s specified in the standards. If I were writing pure C, then I might avoid short-circuiting if I wasn’t 100% sure what compilers were going to be used. If its a “.cpp” or “.cc” file, even if I’m writing C, then I wouldn’t be afraid to use short-circuit. Guaranteed left-to-right.

Did i say something wrong? I am sorry – no offense meant. English is not my language.

In Borland C++ it is an option (default: off). U can decide whether or not u want a complete evaluation. It is rather important to know about this because there might be sideeffects which won’t be kicked otw. It is called “Complete boolean expression” i believe.
Let me have a look on the others and the right to left expression (which is in fact exactly what happens if u use a = b= c = 3;).but i am not quite sure.

There’s an entry at Bjarne Stroustrups FAQ
http://www.research.att.com/~bs/bs_faq2.html.
Scan for “order of” and read the 2nd example.

May be the order is guaranteed for logical operators? I don’t know, i don’t have access to the ANSI standard, unfortunately. But it seems to be true for || and &&, as far as Google is concerned. :D

What i’ve actually found is a (trustable?) copy of the standard, here.
http://www.kuzbass.ru:8086/docs/isocpp/expr.html
I am referring to 5.2.2 with my remarks about the order of expression evaluation. But it is still possible this is “guaranteed” for || and &&, and i am too paranoid. :D

Nevertheless there are much traps, and i agree with your point of view for the first code example, as i mentioned before. I always try to break code with logical operators into different code blocks, if it can be done without “harm”. In most cases it can be done easily by creating the… what’s the word? Invers?

Last example, why it is an option, and i believe, this is still the case for more modern compilers than my Borland.
If u code something like

if (IncreaseASomewhere() && IncreaseBSomewhere())
the problem would be: What if A returns false? May be u still want B to be increased? It is not an acceptable path of doing that, but old code is full of stuff like that, as you’ve stated before. And may be it just doesn’t run anymore because the employee “forgot” to document the switch and left the company years ago. It is very hard to track.

So far.

http://www.research.att.com/~bs/bs_faq2.html

:D
Sorry. It is the point at the end, which ruins the first link. I am a bloody noob.

Forget about the option “Complete boolean expression” . I am sorry. It is an option for the borland family; but it is nested on the “pascal” page. Therefore it seems to work only there. You are right about the short circuit i believe now.
<– converted.
My example just collapsed.

No, Los, you didn’t say anything wrong, I’m enjoying our discussion. I’ve had people tell me that “some” compiler doesn’t do short-circuiting since 1988, but was never able to pin them down on which compiler this was – hence my challenge, nothing personal.

The first C compiler I used, Lattice C on the Atari ST, was at its first short-circuit version when I picked it up. Since then I’ve done a lot of cross-platform work but never run into a compiler that didn’t properly isolate each fragment of logic and execute them in steps.

I’m also a believer in “-Wall -Werror” and taking the strength of a compilers warning/error system into account when choosing one. All 3 compilers I currently work with will complain if you try to do

if ( x = y )

which leaves me only with a stylistic concern as to whether it is “NULL == p” or “p == NULL”, and I prefer to put the variable being inspected on the left hand side.

But then I have an odd style anyway – copious white space down to putting spaces before semicolons (;).

Left to right: logical and/or
ISO 5.14 and 5.15 state clearly: you are right. Left to right is in fact guaranteed for “&&” and “||” since 1998 at least. Before that? Don’t know. But it should not be possible for any compiler to evaluate the second expression first on “||” or “&&”, due to optimizations, architecture of destination or whatever since 98 at least.

Complete boolean expression vs short circuit
is quite a pita for me now. BCB shares the same backend with Delphi. So the C++-ide i use 99% of time supports the feature (checkbox) “Complete boolean expression.” I never realised until today, that this in fact is true ONLY for the pascal side i see in the components, not in my c++ parts (would never use a construction like my example myself anyway). Okay, the tab is labeled pascal… it’s time to blush.

Unfortunately that *was* my example. I am not familar enough with other compilers, only took a glance at some (Watcom, BC and M$VS, all windows sited; did not do real work with them, except for BC, which we r.i.p.’ed three years ago – finally).

CONST as LVALUE on comparision
Yes. That’s strange. I needed three months to get used to it, i remember that. Nevertheless, the only argument *against* that “swapped” condition is ~style~ as well. At least afaik. But it has (techn.) advantage: it generates a compilererror on typos, regardless of which level of warning you use. The warning still comes in play (and is valuable), if both sides are variables. But in my case the majority is comparision against constants.
Okay.. no harm using it, but advantage: i didn’t hesitate and converted :)

May be i took a comment in one piece of code i’ve to care about too serious: “Be paranoid”.

Left to right: You linked to Bjourne Stroustroups FAQ, he makes some other very pertinent comments about ordering (v[i] = i++).

At the end of the day, there isn’t anything wrong about writing your code more explicitly. I know some coders disagree and love to pile things onto single lines, but surely that means more reading. Well written code is more scannable than readable (one of the reasons I eschewed the “rvalue == lvalue” syntax, as a native English speaker “lvalue == rvalue” is more intuitive). If you go piling expressions into single lines you have to spend more time reading across than down.

I agree. It is not intuitive.
It actually is quite the same here. And, as i believe, everybody has it the classic way (“I == 5”). But it is only a matter of trained behaviour(?) and it did save my a.. from time to time.

My first years i’ve always tried to pile conditions as “elegant” as possible – always tried to get rid of lines of sourcecode.
I stopped that after getting employeed (rules) and support that after some private debugging-sessions where i ended in a combination of conditions which i did not cover or which ended (correctly) in a part of code i didn’t want it to.

So now i do believe breaking conditions has advantages for me – and people reading my code. Especially since i started to comment a little T/F table over the local “if”s and “else”s for the higher conditions which might not be “in sight” anymore. If i end up with 6 parts doing the same and only two which behave different my complete condition is not minimal and i change it. The code is still not large.

And even better i’ll get a clear error propagation for each case, if needed.

It is slightly more to write, but for me it guarantees less headaches than identifiying which cases are all grouped indirect while implementing an “else” for
“if (A && (B || !C || (5==i)))” which in fact tends to break into more “ifs” anyway. Not to mention the “(…)”-Problem inside the condition itself, which is eliminated. And you will find the correct case in source code much easier after some years.

Sorry for long text, my daughter sleeps now, i’ve the time.

Not sure if C/C++ has it as I have not used them in a long time but Java has &&/|| and &/| as logical operations where “double symbol” implies short-circuiting and “single symbol” means “both sides evaluated”. It is also specified that the order is left-to-right so…

In any case, using expressions that evaluate in conditions to perform some tasks, the only reason I can think why someone would want to avoid short-circuit, is something I avoid like the plague. Hidden side effect always come to bite you, or the person to maintain the code after you, in the rear and with force.
Fortunately for me, I don’t work in an industry where I have to squeeze every ms., so I can write clearer code as “maintenibility” is more important than a 2-3 ms extra.

S!

Short circuiting could lead to bad style.

Because, afaik, evaluation order in function calls is not clearly defined. There was a website about it I don’t recall atm.

You’ll have to read the discussion with Los, barkas. Short circuiting is part of the ISO and ANSI standards and well defined. If you are working on a legacy, *nix, DOS or older-OS based system, then you should take it into account. If you’re working on a modern project, then you can work with it.

Incidentally, Visual Studio 2008 Team System has a “Code Analysis” tool, which I’ve found to be very helpful – I’m a big fan on Visual Studio. One of Microsoft’s best products, IMHO.

It found a number of logical errors that I thought VC and GCC detected. For instance:

if ( ! x & 7 == 0 )

Hint: “!” has higher precedence than “&” :)

This is still alive? :)

The codeline above is actually mixing with . Two possibilities for intention:
a) (~x & 7 == 0)
b) ! (x&7 ==0) (x & 7 != 0)
I did not swap the condition for your convenience. Please imagine a if ( ) .

What really happens (not intentional, i guess) is:

case x != 0:
==> !(x) ==> [4.12] !(true) = false ==> [4.5.4] 0 && 7 == 0
==> (0 == 0) is always true, regardless, which value x != 0 actually has. Since this looks like a mask test it is probably not working as intended.

case x ==0:
[4.12] !(0) = !(false) = true := 1.
1 & 7 = 1 != 0
1==0 is always false. Can’t tell, if this would case any problems.

So it is just testing for (x != 0)… could be written more simple as
if (x) // using [4.12] again.

Arg… it deleted my tags i sat with “smaller than” and “greater than” :D

Corrections:
The codeline above is actually mixing *bitwise and* with *logical not*.

b) ! (x&7 == 0) eqv. (x&7!=0)

case x!=0:
… ==> [4.5.4] 0 & 7 == 0

Leave a Reply

Name and email address are required. Your email address will not be published.

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

You may use these HTML tags and attributes:

<a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <pre> <q cite=""> <s> <strike> <strong> 

%d bloggers like this: