I recently took a job in which the primary language of the development group is C++. This has not been a terribly happy thing for me because while I can code and read C++ decently enough, I do not like the language very much. C++ has a lot of good ideas underlying it, but it's just terribly implemented. The syntax is god-awful, the rules for inheritance of code and data members are convoluted as hell, and the compiler does things behind your back that can easily cause fits for even an experienced programmer.
I much prefer C. As someone said in a discussion post on Kuro5hin said, "If you must use the wrong language for the job, I'd rather see you use C than C++. It's true that C gives you enough rope to hang yourself. But so does C++, and it also comes with a premade gallows and a book on knot tying." That said, though, C ain't perfect either...
Another thing that catalyzed my thinking about the faults of various programming languages is that I've been reading Writing Compilers and Interpreters (second ed): An Applied Approach using C++. I've been trying to come up with a simplified C-esque language I could write a compiler and/or interpreter for that would attempt to eliminate some of the more glaring flaws of C.
What are some of those flaws? Well, just off the top of my head:
- Assignment vs. comparison. Hasn't this
tripped up many
a novice and even occsionally an experienced programmer? We
need to
differentiate between assignment and equality. Using the
same or similiar
symbols for both operations is a just asking for headaches.
- Pointers. Pointers get programmers in a lot
of trouble.
And not just in obvious ways, either. Ever assigned one
struct to another
that had a string pointer inside? How long did it take you
to realize what
was really going on? (C++ has this problem even worse,
thanks to its
amazingly over-wrought object architecture.)
- Memory managementMalloc() and free() cause a
lot of
trouble, even for experienced programmers. C has the honor
of having its
memory allocation scheme so badly designed that a whole
company (Pure Software)
makes a very comfortable living selling a third-party
library (Purify)
to help us track down our memory leaks. This is ridiculous.
- Keystroke Efficiency On a more general note, I find that many programming language these days require the use of the shift key and special symbols more often that I'd like. My idea of a good identifier is one that you don't have to hit the shift key for. Parenthesis, curly brackets, asterisks and ampersands should be infrequently used characters, not the mainstays of the language syntax.
How do we address these weaknesses? Well, to quote the Perl programmer's motto, "There's more than one way to do it." However, here are some of my proposed solutions to the items mentioned above: (Please, pick on these and tear 'em up! I'm submitting this precisely so people will tell me what's wrong with my ideas...)
- Assignment vs. Comparison. Assignment gets a
new
symbol: "<-", as in "A <- B + C". Read as: "A gets B plus
C." Comparison
continues to use "=". In pratice, "<-" is a real pain in the
ass to type.
So either a macro will need to be made or another symbol
will need to
be substituted. Perhaps ":", in the tradition of Pascal.
- Pointers. Most of the problem with pointers
comes from a
pointer not pointing at what it should, either because it
was never pointed
there in the first place, or because it got re-pointed
(perhaps set
to NULL). So I propose that a pointer can only be set once,
and is
immutable once set. This will get rid of a lot of ugly crap,
not the
least of which is the horrible practice of casting between
different
pointer types. Also, before a pointer is set, it is in a
"non-initialized"
state, and dereferencing a non-initialized pointer will be
prohibited.
I believe both these conditions can be enforced at compile
time. Those
conditions said, however, altering the thing pointed to by a
pointer is
still allowed. Without this functionality, there'd be no
point! (If
you'll pardon the pun. ;])
- Memory mamagement This is the 21st century,
folks. We have
gigahertz CPUs and hundreds or thousands of megabytes of
memory. Almost
no task that a modern PC's main CPU undertakes is hard
realtime critical.
(If someone has such a task, I recommend they not use my
little theoretical
language here.) Garbage collection algorithms have come a
long way and
no longer require unbounded time to operate. We've already
tossed the
bad features of pointers out the door, let's continue in the
spirit of
keeping what we like and having the machine deal with the
ugly stuff and
specify that a well-optimized, bounded-run-time garbage
collector be part
of the language.
- Keystroke Efficiency The first obvious one to me is to substitute "[" and "]" for "{" and "}". Assuming an otherwise C-like syntax, this change should take all of 30 seconds for C programmers to get used to. (What we do about arrays, I don't know - maybe my little toy lanague here won't have them.) Function calls can have a new syntax, funcName:arg1,arg2, etc... This eliminates having to type parenthesis every time you want to call a function, a wrist killer if there ever was one. Strings will get Pascal-style '' delimiters, 'like so', though the backslash notation for escaping characters can stay. We'll keep ; for the end of a statement too, that's actually one I like.
Now, a quickie example of the last point...
Original C:
int main(void) { printf("Hello, world!"); exit(0); }
New style whatever it is:
int main.void [ printf.'Hello, world!'; exit.0; ]
Try typing these two and see which one feels quicker. I think the new function syntax is a real win, anyway.
That's all I have at the moment. So... Questions? Comments? Additions? Flaming rants about my shoe-size IQ? ;]