Do's and Dont's of Symbian programming
Tutorial posted March 26th, 2008 by raghav_an
in
Here below are given a few example of good practices to follow and practices to avoid while programming in Symbian.
- Always use the correct data type which suites the requirement. This is not specific to programming in Symbian OS. It is always a good parctice to use correct data types.
Using incorrect data type can sometimes lead to bugs which are very hard to bust.
eg:
void SomeFuntion()
{
TUint theValue(0);
TInt error = GetValueOfSomething(theValue); //Some method that assigns the value to "theValue" (GetValueOfSomething(TUint& aValue))
if(error != KErrNone)
return;
for(TInt i=0; i<theValue;i++) // !!Beware!! This can turn into an infinite loop
{
//Do some operation
}
}
The same thing can happen if the data being compared are of different types.It is always a good practice to use correct data type or typecast them. - Use "Mem::Copy()" instead of "memcpy()" while copying data in memory.
The method "Mem::Copy()" is heavily optimized. It is about three times faster than memcpy() for unaligned memory copies.
It is, most of the time, better to use the Symbian OS library provided string and memory API's than using own implementation. Since most of the API provided by Symbian are optimized, the own implementation may not be as fast as Symbian provided implementation.
- Always push the heap allocated data onto CleanUpStack before doing any operation that can leave.
This avoids memory leaks, incase the operation leaves.
- Avoid cyclic dependencies between two server modules.
Eg:Two servers S and S'. S is client of S' and S' is client of S.
S sends a synchronous message M to S' and S' sends synchrounous message M' to S and completes M only after completion of M'.
This kind of scenario can lead to a deadlock.
- TRequestStatus instance passed to service provider must have greater lifetime than asynchronous operation. A very common bug is TRequestStatus allocated on stack.
Eg:
void CMyRequest::DoSomeThingAsync()
{
//Some pre-amble operations...
//
//
TRequestStatus status = SendRequest();
//Some code...
User::WaitForRequest(status); //This will cause problem
//some more code...
}
TRequestStatus CMyRequest::SendRequest()
{
switch(iMyState)
{
case 1:
{
TRequestStatus status1;
iServiceProvider->Service1(status1); // This will cause problem
return status1;
break;
}
case 2:
{
TRequestStatus status2;
iServiceProvider->Service2(status2); // This will cause problem
return status2;
break;
}
case 3:
{
TRequestStatus status3;
iServiceProvider->Service3(status3); // This will cause problem
return status3;
break;
}
}
TRequestStatus dummy; // To remove compiler warning
return dummy;
} - In order to have a robust program, it is always a good practice to check the return values of all called function. All the pointers being used should be checked against NULL before dereferencing.
- When using interfaces (pointer to some class-object) created by other object always make sure who owns the interface, and whose responsibility to destroy it.
eg:
CMdaAudioOutputStream::CustomInterface(TUid aInterfaceId); //returns TAny*
In this case it is the responsibility of the caller to destroy the interface after using it.






Re: Do's and Dont's of Symbian programming
Good effort here, I have a two notes though:
This is should not be a problem:
void CMyRequest::DoSomeThingAsync() { //Some pre-amble operations... // // TRequestStatus status = SendRequest(); //Some code... User::WaitForRequest(status); //This will cause problem //some more code... }Because since you do "WaitForRequest", your thread will block at this point until this request has completed, so the TRequestStatus will be valid on stack for as long as its needed.
This pattern is not recommended anyhow though, since it makes for an unefficient system if you are a client of more then one asynchronous service (and you always are if you are a UI app)
*
Also, when it comes to memcpy vs Mem::Copy, I'm pretty sure one of them simply calls the other one internally, so there should be close to 0 difference.
Re: Do's and Dont's of Symbian programming
It is good of you to attempt to help others, however there are a few things that require clarifying.
1) The TRequestStatus example is so contrived only a lunatic would write code like that.
"A very common bug is TRequestStatus allocated on stack." No its not, there are many many instances where they are allocated on the stack. As mentioned above it
will halt your current thread but there are instances when it is acceptable to do so, you can't simply say doing that is a bug - its not.
2)
{
for(TInt i=0; i
//Do some operation
}
Are you going to explain why it can turn into an infinate loop so the dear readers will know what the problem is?
3)
"Two servers S and S'. S is client of S' and S' is client of S.
S sends a synchronous message M to S' and S' sends synchrounous message M' to S and completes M only after completion of M'."
I can't think of a circumstance when two servers are each clients of each other? What's a real world example?
And whats the point of saying don't do something if you don't give the solution?
Re: Do's and Dont's of Symbian programming
Here is my take on it. It's related mostly to game and image processing programming.
1. Don't do Symbian programming if you can help it. Practically any other platform (alive I mean) is more easy, more open, better documented and have better market for third party application. (or will have in case of iPhone or Android)
2. If you absolutely must use Symbian writing functional prototype on PC/workstaion would help a lot. I don't mean Nokia/UIQ SDK emulator, I mean normal native PC application which have a block with the same functionality. Debugging will be a lot more easy and faster.
3. Don't use Mem::Copy and Mem::Fill, use memcpy and memset instead. But define them as
#define memcpy(...) Mem::Copy(...)
Use int instead of TInt.
That way porting to and fro other platform would be a lot more easier.
But don't forget - TReal is not float.
Don't use Symbian naming condition for the same reason.
4. Don't use massive floating points calculation if target device don't have FPU. Use fixed point math instead. While using fixed point math always keep in mind overflow and precision loss. However use common sense - several floating point operations wouldn't kill you. Also TReal32(float) is a lot faster than TReal (on the devices without FPU).
There is a lot of fixed point math code on the net. Including FFT. It would be easy to incorporate it into your code if you stick with advice 3.
Re: Do's and Dont's of Symbian programming
>> 1) The TRequestStatus example is so contrived only a lunatic would write code like that.
Numpty, You're a star. I'm very much liking your new "zero tolerance" attitude!
>> I can't think of a circumstance when two servers are each clients of each other?
I've seen this happen, although it's not really something you'd encounter on a day to day basis. Certainly you'd have to be doing something fairly advanced or at the OS level to have this happen. The point is that a server is fundamentally just an active object so it can only process one message at a time.
>> Also, when it comes to memcpy vs Mem::Copy, I'm pretty sure one of them simply calls the other one internally, so there should be close to 0 difference.
It really depends on the size of the copy. The overhead of the additional function call could be significant for small copies. I think Raghav has the right idea though: avoid using "libc" on Symbian if possible!
>> 1. Don't do Symbian programming if you can help it. Practically any other platform (alive I mean) is more easy, more open, better documented and have better market for third party application.
I don't agree with this statement at all. For sure there are things that could be so much better (I've ranted on various forums about these from time to time) but fundamentally Symbian programming is not any different than any other platform. If anything it's better on Symbian (which probably explains why I'm still doing it).
>> Don't use Mem::Copy and Mem::Fill, use memcpy and memset instead. But define them as
#define memcpy(...) Mem::Copy(...)
Use int instead of TInt.
That way porting to and fro other platform would be a lot more easier.
But don't forget - TReal is not float.
Don't use Symbian naming condition for the same reason.
This is NOT good advice. The way you make porting easier is that you seperate the engine parts of the application from the UI / OS layers. C/C++ code mostly runs just fine on Symbian, so engine code shouldn't need changing. The UI / OS layers should use the proper coding conventions and OS functions.
Re: Do's and Dont's of Symbian programming
>> All the pointers being used should be checked against NULL before dereferencing.
This is mostly good advice but it's not always necessary. For example, I hate seeing code that checks pointers that have been allocated by the NewL(). There's no way those can be NULL, so you are just writing inefficient and harder to follow code. And there is no point in checking a pointer if it has been set by a leaving function, e.g.
somepointer = CreateObjectL();
if (somepointer)
{
// Always true, so the test is pointless.
}
Whether pointers can be NULL should be specified in the design (for example as part of the pre and post conditions for each function). In addition if pointers passed to functions can't be NULL you should be using references instead (although of course that isn't always practical).
Re: Do's and Dont's of Symbian programming
A sort of similar thing that just about everybody does is set a pointer to NULL after its been deleted in a destructor.
Folks if you're in a destructor the object is just about to vanish so setting a member variable pointer to NULL is a complete waste of time in that situation.
Re: Do's and Dont's of Symbian programming
"Two servers S and S'. S is client of S' and S' is client of S.
S sends a synchronous message M to S' and S' sends synchrounous message M' to S and completes M only after completion of M'."
Its a weird case, but it can happen, we have had this exact problem in our project, but then again, our project is pretty much "over the top" when it comes to complexity and OS integration...
This is the "simple" case though, much more "fun" is the 3 party deadlock, A calls B, B calls C and C calls A, and with perfect timeing to have all 3 just hang there waiting for reply...
-
Also, 100% agree with fig7, DON'T write null checks everywhere where they are not needed!
Follow symbian conventions and mostly you don't need them.
Also, don't try to write your symbian code with some other coding standard, use the symbian coding standard for any and all symbian specific code, and then keep your platform independent engine part in whatever coding standard you like for it.
Actually just makes it easier to keep engine and platform integration apart properly that way.
There is no way you can find any one coding standard that works perfectly on all platforms anyway...
Re: Do's and Dont's of Symbian programming
First example: I've spotted the problem as a signed/unsigned comparison. Infinite loop-ness would depend on the compiler and how it handles signed/unsigned comparisons though (I think).
TRequestStatus examples: I'm surprised no-one else has noticed this yet. There is a problem with all examples given, namely that the examples are passing the TRequestStatus by value rather than reference. This would completely avoid memory leaks, but at the expense of them no longer being the same TRequestStatus objects that the asynchronous objects are using for their status (assuming, of course, that the copy-constructor isn't made private in TRequestStatus, at which point it just wouldn't compile anymore. I can't quite remember if it is or not
)
Re: Do's and Dont's of Symbian programming
[qoute]
TRequestStatus examples: I'm surprised no-one else has noticed this yet.
[/qoute]
I think we all saw it..
But... it was supposed to be an example of how to not do it, so there was nothing to comment on that....
Re: Do's and Dont's of Symbian programming
Heh
maybe
I raised it due it the example giving a completely different reason why the code was incorrect that said the problem was somewhere else. Especially as it is meant for beginners to Symbian who may take into account the requirement to check RequestStatus scopes but still miss the problem of requiring references to avoid bugs.
Re: Do's and Dont's of Symbian programming
I don't see how in example 1 it can turn into an infinite loop... I would appreciate some explanation. Merci.
Re: Do's and Dont's of Symbian programming
"I don't see how in example 1 it can turn into an infinite loop... I would appreciate some explanation. Merci."
TUint is unsigned while TInt is signed, this means a TUint can hold a larger positive value then a TInt, thus in the example if 'theValue' is greater than 2147483647 then i can never reach that high because its max value is 2147483647 so when its incremented it'll wrap round to a negative number and thus still be less than theValue.
The poster is correct about it being a good principle to always choose the correct data type, however the example is a little obscure, especially when no explanation was given as to why it could cause an infiniate loop.
Re: Do's and Dont's of Symbian programming
Indeed it's definitely a little obscure. The more likely scenario is that you've mistakenly written something like:
for (TUint i = someValue ; i>=0 ; i--)
{
}
There was a time when I cared a great deal about whether variables were signed or unsigned. For example I'd always make array indexes unsigned, because of course negative values are not valid in that case. These days I really don't bother using unsigned variables at all, it's just more complexity and in my old age I'd like to avoid any of that if at all possible! I think there are really very few situations when you have got to have an unsigned value, so it makes much more sense just to stick with TInts and thereby avoid situations where you get mismatches (and lots of compiler warnings!)
Re: Do's and Dont's of Symbian programming
Only time it I've found it really matters is when bit shifting.
shifting a signed negative value right will shift in 1:s, and shifting an unsigned value will always shift in 0:s.
(asm programmers usually know the difference as arithmetic vs logic shift.)
Re: Do's and Dont's of Symbian programming
4. Don't use massive floating points calculation if target device don't have FPU. ->>
I would say even if it has. Avoiding floating points calculations on a phone save time, power and keeps it easy to port to other terminals.