27 Aug, 2014, Asylumius wrote in the 1st comment:
Votes: 0
A RaM question? In 2014?! Ayep.

So one of the things the original RaM people did was change

typedef void DO_FUN ( CHAR_DATA *ch, char *argument );

… to …

typedef void DO_FUN ( CHAR_DATA *ch, const char *argument );

Which resulted in a lot of really ugly code like this

void do_mset( CHAR_DATA *ch, const char *argument )
char arg1[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
char arg2[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
char arg3[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
// …
char local_argument[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
const char *lap = local_argument;

strcpy( local_argument, argument );
smash_tilde( local_argument );
lap = one_argument( lap, arg1 );
lap = one_argument( lap, arg2 );
strcpy( arg3, lap );
// …

First, why is const char pointer better than char pointer in the use case of commands?

And second, is there a better way of handling multi-argument commands in RaM than that messy chunk code above?
27 Aug, 2014, Rarva.Riendf wrote in the 2nd comment:
Votes: 0
>First, why is const char pointer better than char pointer in the use case of commands?

Adding const is for code readability. If you do not add it, you have absolutely no idea what is your pointer after the call of a method.
You have no idea if the address is still the same, no idea if the value is the same, so you cannot even free it without risking a crash.

>And second, is there a better way of handling multi-argument commands in RaM than that messy chunk code above?

It is not messy, you can easily read this code even if you dont know a thing in C.
IT is verbose though, lots of code for very simple thing, but well, that's C for you.
27 Aug, 2014, Tyche wrote in the 3rd comment:
Votes: 0
const char * won't allow you to modify the chars in argument without a warning.
But the code that follows isn't the result of that.
27 Aug, 2014, quixadhal wrote in the 4th comment:
Votes: 0
A great many functions in RaM were changed to const to silence compiler warnings, and because (in theory) the compiler can better optimize things if it knows a parameter is immutable.

However, there are also several functions in Rom that relied on being able to modify the arguments passed in. In order for the compiler to accept a const declaration, there can't be any attempts to modify it, NOR can it be passed to a non-const function.

So, the workaround in some places was to copy things (either actually copying, or tricking the compiler into thinking it was a copy) to local storage to prevent losing the const from the entire chain of function calls, because ONE place wanted things to be mutable.

Does that make any sense?
27 Aug, 2014, Asylumius wrote in the 5th comment:
Votes: 0
quixadhal said:
Does that make any sense?

Yep. I was just a little disappointed that the extra local variables and string copying was going to be necessary in what ends up being quite a few place (in the version of RaM on MB there are actually a number of commands that compile but simply do not work in-game). It sounds like I have my solution though, even if I think it's a little kludgy.
27 Aug, 2014, Scandum wrote in the 6th comment:
Votes: 0
I would say valgrind obsoleted the usefulness of const.

I'm interested to hear why const is faster, and by how much.
28 Aug, 2014, quixadhal wrote in the 7th comment:
Votes: 0
As to the why part, it's because the compiler can generate different code if it knows the variables cannot change. In particular, it could always reference those variables as stack address + offset without having to pop them off the stack, and push them back on again. If the string were volatile, modifying it could change the size, meaning it has to be reallocated. You can also imagine that a highly optimized compiler might pass very short strings directly on the stack, rather than as pointers.

foo("hello") is short enough to pass directly on a 64-bit architecture, allowing you to test the value without needing to dereference a pointer.

Not a great example, perhaps, since that's char * const, not const char *. gcc, at least at one time, made the distinction between "a constant pointer which references volatile data" vs. "a volatile pointer which references constant data". I believe you could have both as const char * const.
28 Aug, 2014, Tyche wrote in the 8th comment:
Votes: 0
Whats with the 7 NUL characters?
char                    arg1[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";

You would think smash_tilde() need be called in only one place on input and well before processing commands.
28 Aug, 2014, quixadhal wrote in the 9th comment:
Votes: 0
The 8-byte long string of NUL's was to help in debugging on a 64-bit platform, since it ensured that whatever memory arg1 ended up pointing at would return 0 when dereferenced, at least at first. :)
28 Aug, 2014, Kaz wrote in the 10th comment:
Votes: 0
The idea that const can help with performance is a little out-dated. With modern compilers (by which I mean just about anything with which you might compile a mud), any location where the placement of const might be an optimization has already been deduced and optimized by the compiler. After the front-end, const is whitespace.

So, const is simply an expression of intent to other developers: "in this function, the value passed in shall not change." Remembering Abelson's Maxim: "Programs must be written for people to read, and only incidentally for machines to execute", this is arguably the more important part of the const keyword.


char arg1[MAX_INPUT_LENGTH] = { '\0' };

initializes the entire arg1 array to 0, not just the first 8 bytes as in the quoted example (because in aggregate initializer expressions, elements that are not explicitly initialized are zero-initialized). You may find this useful.
31 Aug, 2014, Scandum wrote in the 11th comment:
Votes: 0
Looks like const has some uses.

const int max = 1000000;
int cnt;
for (cnt = 0 ; cnt < max ; ++cnt);

Using const allows the compiler to turn max into a compile time constant.

Also makes sense to declare tables as const for the same advantage which could include short strings as quix mentioned.

It still seems to me that Diku is using const incorrectly. Alternatively one could do something like:
lap = one_argument_and(lap, arg1, FLAG_SMASH_TILDA);
01 Sep, 2014, alteraeon wrote in the 12th comment:
Votes: 0
Pretty much all strings in Alter Aeon are const char pointers. It has helped the compiler catch a large number of programming mistakes which would have been allowed and simply caused bugs if they were merely char pointers. It's perhaps more important on AA than other servers because we use a de-duplicating string allocator, but as a general rule we use const wherever it's reasonably possible to do so.