Walking
arrays backwards are useful for all-sorts of things such as removing items from
an array.
Three
main ways to do this, take your pick.
1.
for ( int n = A.length; n>0; )
A[--n] …;
2.
for ( int n = A.length-1; n>=0;
n-- )
A[n] …;
3.
for ( int n = A.length; --n>0; )
A[n] …;
Which
is preferable? Well that’s really up to your style of coding and what you are
doing.
1
has extra possibilities. If you add brackets you can write code before and
after n-1.
for ( int n = A.length; n>0; )
{
//Code before n-1
A[--n];
//Code after n-1
}
If
you’re a classic stick-to-the-format type of person then 2 is probably your
cup-of-tea. It keeps the loop in its general format and there’s no dirty
pre-logic stuff.
If
you’re a keyboard-speed-freak then 3 is probably your motor car. It has
slightly less code then the other two.
Joel
Anderson
Forget
loops, D has sorting as one of an array’s attributes.
This
will sort the array A in-place.
int[] A;
...
A.sort;
Joel
Anderson
Forget
realloc, D can resize array’s dynamically.
This
will resize the array A by one.
int[] A;
...
A.length++;
Joel
Anderson
D
allows you to quickly compare arrays with “==”.
int[] A;
int[] B;
...
if (A == B) //Then both are equal in
length and items.
But
don’t worry referential testing is still supported with “===”
if (A === B) //Then both references
are equal.
Joel
Anderson
D
can automatically extract code from html pages and compile it like normal
code. What are the advantages of this?
Apart from beginning able to keep code with documentation future D IDE’s may be
able to use this feature for automatic syntax highlighting and object link
embedding.
Joel
Anderson
If
you have any notes you would like to share, email Mathew Wilson
dmd@synesis.com.au or Joel Anderson anderson@firestar.com.au. They must be
between one-sentence => two-medium-paragraphs and/or small snippets of code.
Otherwise they’ll be considered for the hints and tips section for the Journal.
Joel
Anderson
Programs
should be lowly coupled and highly cohesive. Why? What does this mean?
Programs
are highly coupled when they are heavily reliant on one another. This is
considered NOT A GOOD THING. For example a car that only uses one type of tyre
and that tyre only being useable on that car. In this case the tyre is not
reusable. You can’t very well take the tyre and use it on another car. High
coupling make programs less reusable.
Cohesion
is the way things work together. Take the car example again. Suppose the tyre
was so generalised that it even works on your-next-door-neighbours billycart.
The car may be reduced a maximum of 10km/h. Low cohesion makes components less
flexible/efficient together.
It’s
often difficult to get the balance just right between these two concepts but
just it in the back of your mind and your programs will be all the better.
Remember, high cohesion and low coupling = good thing but low cohesion and high
coupling = bad thing.
Joel
Anderson
When
using for loops (or any loop for that matter) make sure that you’re not
reloading the same value every time around the loop.
Don’t
for
(int n=0; n < getSizeof(X); n++)
{
…
}
//Where
getSizeof returns a constant value
Instead,
int
Size = getSizeof(X);
for
(int n=0; n < Size; n++)
{
…
}
That
way your not calling the fucntion getSizeof(), getSizeof(X) times.
Joel
Anderson
The
basic search looks like.
int n=0;
while (n<A.length)
{
if
(A[n]==Search)
{
//Value
found at n
break;
}
n++;
}
//Where
A is the value we are searching for
This
can be improved to…
int n=0;
while (n<A.length && A[n++]!=Search) {};
if (n != Max) {…} //Then the value is found at n-1
A
comparison can be saved by making the last character in the array the value
being searched for.
A.length = A.length + 1;
A[A.length] = Search;
int n=0;
while (A[n++]!=Search) {};
if (n != Max) {…} //Then the value is found at n-1
A.length = A.length - 1;
Joel
Anderson
Building a Toolbox for the future
When
programming, try to program in such a way that components in the program are reusable
in other programs. Try to keep things
separate and independent of other parts of the program. These independent parts may become tools of
the future, so design them well. The advantages
for programming like this normally out weigh the extra time spent. Hands will dance; they won’t have to experience
about daysharvoo so much (reduced repetition). The complier will sing, because
these tools should have been already thoroughly debugged in the previous
programs and hence no error report. Whenever
the possibility arrises, program for the future.
Joel
Anderson
Did
you know that there is a D newsgroup on news.digitalmars.com server? Here you
can ask/suggest anything about D and even talk to the creator Walter.
Joel
Anderson
-----------Pavel’s
Stuff---------------
D Stacks
D
array can be used to easily construct a stack:
int[] stack;
...
stack ~= 666; // push a value;
...
a = stack[stack.length-1]; // get last element
...
stack.length = stack.length - 1; // pop last element
----------Walters
Stuff------------
Header Files
C
and C++ rely heavilly on textual inclusion of header files. This frequently
results in the compiler having to recompile tens of thousands of lines of code
over and over again for every source file, an obvious source of slow compile
times. What header files are normally used for is more appropriately done doing
a symbolic, rather than textual, insertion. This is done with the import
statement. Symbolic inclusion means the compiler just loads an already compiled
symbol table. The needs for macro "wrappers" to prevent multiple
#inclusion, funky #pragma once syntax, and incomprehensible fragile syntax for
precompiled headers are simply unnecessary and irrelevant to D.
The
syntax:
#include <stdio.h>
is
expressed in D as:
import stdio;
Walter
Getting the
Size of a Type
The
sizeof(int)
sizeof(char *)
sizeof(double)
sizeof(struct Foo)
The
Use
the size property:
int.size
(char *).size
double.size
Foo.size
Walter
Get the max and min values
of a type
The
#include <limits.h>
#include <math.h>
CHAR_MAX
CHAR_MIN
ULONG_MAX
DBL_MIN
The
char.max
char.min
ulong.max
double.min
Walter
Primitive Types
C to D types
bool
=> bit
char =>
char
signed char => byte
unsigned char =>
ubyte
short =>
short
unsigned short => ushort
wchar_t => wchar
int => int
unsigned => uint
long => int
unsigned long => uint
long long => long
unsigned long long => ulong
float =>
float
double =>
double
long double =>
extended
_Imaginary long double => imaginary
_Complex long double
=> complex
Although char is an unsigned
8 bit type, and wchar is an unsigned 16 bit type, they have their own separate
types in order to aid overloading and type safety.
Ints and unsigneds in C are
of varying size; not so in D.
Walter
Taking the Modulus of a floating point number
The
#include <math.h>
float f = fmodf(x,y);
double d = fmod(x,y);
long double e = fmodl(x,y);
The
D supports the modulus ('%')
operator on floating point operands:
float f = x % y;
double d = x % y;
extended e = x % y;
Walter
Dealing with
The
C doesn't define what happens
if an operand to a compare is
#include <math.h>
if (isnan(x) || isnan(y))
result = FALSE;
else
result = (x <
y);
The
D offers a full complement of
comparisons and operators that work with
result = (x < y); // false if x or y is nan
Walter
Assert's are a necessary part of any good defensive
coding strategy
The
C doesn't directly support
assert, but does support __FILE__ and __LINE__ from which an assert macro can
be built. In fact, there appears to be practically no other use for __FILE__
and __LINE__.
#include <assert.h>
assert(e == 0);
The
D simply builds assert into
the language:
assert(e == 0);
Walter
Initializing all elements of an array
The
#define ARRAY_LENGTH 17
int array[ARRAY_LENGTH];
for (i = 0; i < ARRAY_LENGTH; i++)
array[i] =
value;
The
int array[17];
array[] = value;
Walter
Looping through an array
The
The
array length is defined separately, or a clumsy sizeof() expression is used to
get the length.
#define ARRAY_LENGTH 17
int array[ARRAY_LENGTH];
for (i = 0; i < ARRAY_LENGTH; i++)
func(array[i]);
or:
int array[17];
for (i = 0; i < sizeof(array) /
sizeof(array[0]); i++)
func(array[i]);
The
The
length of an array is accessible the property "length".
int array[17];
for (i = 0; i < array.length; i++)
func(array[i]);
Walter
Creating an array of variable size
The
C cannot do this with arrays.
It is necessary to create a separate variable for the length, and then
explicitly manage the size of the array:
#include <stdlib.h>
int array_length;
int *array;
int *newarray;
newarray = (int *)
realloc(array, (array_length + 1) * sizeof(int));
if (!newarray)
error("out of
memory");
array = newarray;
array[array_length++] = x;
The
D supports dynamic arrays,
which can be easilly resized. D supports all the requisite memory management.
int array[];
array[array.length++] = x;
Walter
Formatted printing
The
printf() is the general
purpose formatted print routine:
#include <stdio.h>
printf("Calling all cars %d
times!\n", ntimes);
The
What can we say? printf()
rules:
import stdio;
printf("Calling all cars %d
times!\n", ntimes);
Walter
Functions that have no arguments
The
void function(void);
The
D is a strongly typed
language, so there is no need to explicitly say a function takes no arguments,
just don't declare it has having arguments.
void function()
{
...
}
Walter
Goto Statements
The
The much maligned goto
statement is a staple for professional C coders. It's necessary to make up for
sometimes inadequate control flow statements.
The
Many C-way goto statements
can be eliminated with the D feature of labelled break and continue statements.
But D is a practical language for practical programmers who know when the rules
need to be broken. So of course D supports the goto!
Walter
Struct tag name space
The
It's annoying to have to put
the struct keyword every time a type is specified, so a common idiom is to use:
typedef struct ABC { ... } ABC;
The
Struct tag names are not in a
separate name space, they are in the same name space as ordinary names. Hence:
struct ABC { ... };
Walter
Declaring struct types and variables.
The
Is to do it in one statement
ending with a semicolon:
struct Foo { int x; int y; } foo;
Or to separate the two:
struct Foo { int x; int y; }; // note terminating ;
struct Foo foo;
The
Struct definitions and
declarations can't be done in the same statement:
struct Foo { int x; int y; } // note there is no terminating ;
Foo foo;
which means that the
terminating ; can be dispensed with, eliminating the confusing difference
between struct {} and function & block {} in how semicolons are used.
Walter
Getting the offset of a struct member.
The
Naturally, another macro is
used:
#include <stddef>
struct Foo { int x; int y; };
off = offsetof(Foo, y);
The
An offset is just another
property:
struct Foo { int x; int y; }
off = Foo.y.offset;
Union initializations.
The
Unions are initialized using
the "first member" rule:
union U { int a; long b; };
union U x = { 5 }; // initialize member 'a' to 5
Adding union members or
rearranging them can have disastrous consequences for any initializers.
Walter
The
In D, which member is being
initialized is mentioned explicitly:
union U { int a; long b; }
U x = { a:5 }
avoiding the confusion and
maintenance problems.
Walter
Struct initializations.
The
Members are initialized by
their position within the {}'s:
struct S { int a; int b; };
struct S x = { 5, 3 };
This isn't much of a problem
with small structs, but when there are numerous members, it becomes tedious to
get the initializers carefully lined up with the field declarations. Then, if
members are added or rearranged, all the initializations have to be found and
modified appropriately. This is a minefield for bugs.
The
Member initialization is done
explicitly:
struct S { int a; int b; }
S x = { b:3, a:5 }
The meaning is clear, and
there no longer is a positional dependence.
Walter
Arrays that parallel an enum
The
Consider:
enum COLORS { red, blue, green, max };
char *cstring[max] = {"red",
"blue", "green" };
This is fairly easy to get
right because the number of entries is small. But suppose it gets to be fairly
large. Then it can get difficult to maintain correctly when new entries are
added.
The
enum COLORS { red, blue, green }
char cstring[COLORS.max + 1][] =
[
COLORS.red :
"red",
COLORS.blue :
"blue",
COLORS.green : "green",
];
Not perfect, but better.
Walter