#"Good" Code
31 messages in this thread
I'd put it this way – an ideal compiler CAN produce it, but may not if the
user wants things like 32 bit stack parameters, stack checking, and so on.
Issues that seem like coding issues manifest themselves in the object quite
often – in incompatabilities with other objects to be linked and so on. It
is a fact that different preferences in the object which have some form of
goodness you can measure or at least sense will affect the code size and
speed. Object that cannot be linked with standard amiga object files may be
small, but is less useful. Object that can't handle data larger than 32k or
64k again may be small, but may not be able to handle the task at issue.
The Lattice compiler was set up to default to handling big tasks, with a
lot of safety built in for the user. The Manx compiler was set up to make
lean mean code, w/o a lot of error checking the Lattice compiler had, and
without things like callable assembly proceedures – the ILAC specifically
encourages the ignorant and lazy programmer to place code inline, which
reduces object size since the call to the software isn't there, but also
reduces the quality of the code as opposed to the object. The issues aren't
seperable across the board.
Manx is obviously a functional compiler. I love to pull Mikes leg, maybe
because it's always dangling within reach; but I am serious about the
issues involved. ILAC is bad, period. Use of it is wrong, period. I support
the Lattice compiler over Manx largely on that issue, since I feel that
Manx is harming the quality of our code by the very inclusion of the
feature.
Don't try and get me to pick on YOU… I know better. :^)
Ben
Amateur Radio Callsign is A A 7 A S
Ben –
I am reminded about a software "truism" I heard several years ago. I
believe it was called Morrison's Law.
GOOD
/ \
/ \
/ \
FAST—–CHEAP
The corner's of the triangle describe the code in two words. Code can be
GOOD and FAST, but it won't be cheap. Or it might be CHEAP and GOOD but
not FAST. Etc…
In actuality it is a simple restatement of a general truth of
neo-capitalism. That being, "You get what you pay for."
– Nelson …
(Good code never breaks… it developes unintentional funtionality.)
Interesting. :^)
Ben
Amateur Radio Callsign is A A 7 A S
_LOVE_ the tag line.
Victor A. Wagner, Jr.
There is a strategic (or "philosophical?") issue here of "what should a
compiler do." I know what an _assembler_ should do. An assembler should
translate mnemonics into machine code. I think what a _compiler_ should do
is to translate an algorithm expressed in some language into machine code.
In the fourth generation language world, there are those who hold that the
"compiler" – the database server – should be smart enough to add and remove
indexes, change the way data is being stored on the disk, modify the amount
of cache, etc., based upon changing conditions, where the user is giving no
guidance other than the user's actual commands. As a concrete example, do
I want 32-bit parameters, or do I want the virtues that 32-bit parameters
bring? Wouldn't "God's Compiler" (or maybe God's Linker) be smart enough
to go searching through the make file and determine what int length is
best, perhaps recompiling other code if necessary? Does this start to
sound too much like Wheeler's interpretation of quantum mechanics?
God's compiler, like God, is a myth. But might be as much fun to discuss.
:^)
A c compiler has a number of goals. Obviously, it wants to create an
executable program. We'd like that code to be fast, we'd like it to be
small, although that is becoming a non-issue anymore.. it's not like we're
writing for 32k machines. We'd like the source that is fed to a particular
compiler to be palatable to _other_ compilers, such that if one had an
application on the Mac, for instance, then one could bring it to the Amiga
compilers and get 100% compiles the first time.
A programmer has a number of goals as well. We want the code to be written
in such a way that we can read it now, and read it later. We want OTHER
programmers to be able to read it as well, now and later. Many of us want
the elusive quality of "elegance" also, though I'd hate to be pinned down
on THAT one! We want the code to not only port across compilers, but if it
would go across machines and still function, this is highly desirable, as
it buys more market share. Some programmers, like me, won't do that at the
expense of compromising what they consider an ideal market (The Amiga) but
some, like Borland, would consider that _the_ important issue.
Some of these goals can intersect. For instance, if a programmer codes well
(even elegantly) then the code tends to trend towards the more readable and
maintainable ends of the spectrums. It may make the compilers job easier as
well, by dint of a concise, elegant structure in C may well represent the
same in object.
I'm taking the term compiler here to be limited to exactly what an
assembler does – generate object code, in modular form. I think the term is
becoming somewhat confused with the advent of your 4th gen database users,
and I'm reasonably sure they should be shopping for a new term, so as to
not get entymologically (sp?) all tangled up.
Ben
Amateur Radio Callsign is A A 7 A S
Boy, Oh, Boy!
You do like to start "discussions". 🙂
Marcus
moi? <grin> n
Ben, you seem to have forgotten some important people – users of your
products. Your users don't give a flying ***** whether you used C, ADA,
forth, Modular-programming techniques, or a hammer and chisel to write your
application. All they care about is what it does, and how well it runs.
If tweaking an application w/ five or six lines of ILAC in the right place
will make it perform better, why is that so evil? You've said that only
amateurs use ILAC, and that professionals only use modular techniques. I
say you're dead wrong. Professions write programs (er, make that
'professionals') which does what the user wants done, and does it well. A
professional does what he has to do to make his code run as quickly and
correctly as possible. I would say that a programmer who avoids 'evils'
such as ILAC at all costs, despite the fact that they may improve program
performance, is the true amateur, because he values his code's asthetics
over his users.
Some of the best selling software ever was written in the most heathen,
unstructured, and ugly language of all – assembly langauge. Lotus 1-2-3 is
a prime example. So is a huge number of game/simulation software packages.
The code was ugly, but the users loved the products becasue they were fast
and worked well. Now Lotus has re-written 1-2-3 in mostly C, and all their
users are whining that its significantly slower than previous versions
(even w/ smart recalc). Lotus gained code portability and modularity, but
upset lots of its users. Which do you think matters more?
-Mike
Mike,
I don't share Ben's knee jerk response to ILAC.
If a program was written with portability in mind, and certain sections
need to be coded in asm, that's what I'd do — code in asm, assemble, and
link with the .o file. If a program is never expected to be ported, who
cares if you use ILAC? The inclusion of a tool like ILAC has nothing to do
with the overall package. No one is forced to use it. So much hot air
over nothing.
If there are indeed major differences in code generation and speed
between Lattice and Manx, _that's_ an issue, not the inclusion of tool that
is left up to the programmer to use or not.
Just in case anyone's interested, on the Amiga, I started with Lattice
3.01, then 3.03, found them unreliable, switched to Manx, versions 3.2,
3.4, and 3.6, got tired of waiting for a significant update, and switched
to Lattice 5.05.
-sja
"If a program is never expected to be ported"
Let's see… according to your message, you switched c compilers twice, for
a total of three re-coding jobs if you used ILAC or decided to begin using
ILAC. How the heck do you KNOW if you're going to port or not? A simple
utility can turn into the wrlds best money maker if it's the right kind of
thing.
As for reasons outside of inter-compiler portability, there is
inter-machine portability, maintainability, modularity, and of course that
elusive concept, "elegance".
Clearly written code makes a better example/source for modifications of the
module, as well. Examples that get posted on systems like CIS cut out a
significant part of the audience when they use ILAC or Lettuces stupid
binary generator. If the reader of such a file is an expert C programmer,
they may still be completely unable to recode the module, as they don't
neccesarily know what register assummptions that other compiler uses in the
middle of a module… and this stuff is often done at 3am, when there is no
one to ask.
If you need speed, use asm. A _module_ of asm. If not, use nice, common C.
People use the c compiler often for a "loop control generator" which is
simply lazy – the 68xxx series has all you need to do virtually any kind of
loop with no problem. Putting that ILAC inside some loop just renders the
module crummy, w/o buying you anything worth diddly.
If I knee jerk, it's because I have a raft of reasons.
The reason YOU gave "if you wanna and no ones gonna see it" can even be
countered with: It builds bad habits which hurt you later.
Ben
Amateur Radio Callsign is A A 7 A S
Ben,
I am rife with bad habits.
You may have read my message but you didn't read my message.
I said that if portability was an issue you should create an asm module,
assemble it, and link with the .o file. If portability was not an issue it
makes no difference. I've switched C compilers twice. The code I had
written did not need to be ported, the code worked as I'd wanted it to,
therefore, I had no need to recompile.
I personally don't use ILAC as I feel there are much better ways to
achieve the same goal. However, unlike temperance workers of the past or
anti-nuke radicals of the present, I feel no need to impose my bias upon
others. While your reasons may be valid for you they are not necessarily
valid for others.
I read it… I just disagree with the statement you made that if
portability was not an issue, it made no difference. I say, and said, that
you don't KNOW whether it's an issue until the code is obsolete.
To be specific, you may not do it, but your reasons for saying it's ok are
specious.
Ben
Amateur Radio Callsign is A A 7 A S
So you're saying that 75 lines of asm code in a module is going to be more
readable than 20 lines of C code and 2 or 3 lines of ILAC? Get real, Ben.
Most ILAC that I've seen comprised of 2 or 3 lines of assembler, which was
all the assembler that really had to be done. If the modules had been done
completely in assembler, future maintenance programmers would have had an
_awful_ time of figuring out what was going on.
-Mike
Maybe it's just me, but I've always found that it took a fair knowledge
of how a particular compiler generated code in order to figure out what
ILAC was doing. Without that knowledge, ILAC is not so much confusing as
misleading. A separate assembly module, on the other hand, is either easy
to understand or completely opaque, depending, of course, on the
programmer.
No – I'm not saying that at all. I'm saying it's BETTER than 20 lines of c
and a few lines of assembler. I'm saying it's more portable. I'm saying
it's more maintainable. Readable? That's a code style issue – and it
depends almost entirely on things like comments, indentation, and variable
naming, issues we haven't even touched on.
Ben
Amateur Radio Callsign is A A 7 A S
I think Lattice did the right thing… slow, eh? Maybe they're a Manx user?
<grin> …just poking you there, don't have a fit.
As for forgetting my users… no, that's who I'm always thinking about, and
they are one of the best reasons to NOT use ILAC.
My users want me to be able to find, and to fix, bugs as soon as possible.
They'd prefer I didn't make any of course, but I'm not perfect, and will no
matter what. They also would like Black Belt to become a "big" company,
successful, so that we can provide them with high performance applications
both in function and speed. As this happens, though, I have to pass off
code that I have written to new programmers – and they MUST be able to
understand it. If they need to port it for any reason, say to support the
Amiga 4500 which uses RISC to use a fictional example, then they must NOT
encounter C modules that are useless because of the mixed use of language.
They will find, in any module coded here, only ONE language. If it's a c
module, it'll be in C. If it's an asm module (we use a LOT of asm) it'll be
in asm. The C modules can be moved directly (mainly because we stay away
from ALL "high performance hacks" like ILAC, the binary inline that Lettuce
offers, the various #pragmas, and as many library routines as we can.
Performance… it might interest you to know that Board Master, which is
written in Lattice C, is the fastest object oriented CAD system I've ever
seen on any platform; is the fastest CAD system on the Amiga, period; and
would port VERY fast to something like the Mac. Electron, which is a
schematic program, is the fastest line-based CAD system on the Amiga, by
quite a margin, only part of the credit going to Lattice, some of course
goes to El Blittero. Board Master uses 32 bit protocols thruout. Electron
uses 16 bits in most places, and guess what? The workspace is too small…
darn dynamic range bit us – that's my fault, of course, since I should have
been able to intuit that problem coming down the pike, but it SHOULD have
been 32 bit, speedy or not.
Isn't it sort of contradictory to use ignorant/lazy with assembler? I would
think an "ignorant" or "lazy" programmer would ignore assembler because it
was too difficult or intimidating. Not that good programmers have to use
assembly language, just that assembly language programmers don't tend to be
ignorant or lazy. 😉
Marcus
No, I don't think so. If there is a need for speed, in a C program, then
you have a (weak) option of carefully optomizing your C code and possibly
checking the code generation of your particular compiler…. which will
probably change the next time they upgrade it (the compiler). The ONLY
choice you have is to change to assembler, where you have 100% control and
can ensure that operations the compiler would have done to save
variables/states that are no longer neccesary are avoided. So, assuming
that performance IS an issue, we come to assembler one way or another.
In-line assembler can be "whacked" into code. Very quickly – in fact, about
as fast as you can think. As opposed to opening another file, assempling it
separately, and linking it later. In adddition, an external assembly module
is more difficult to interface, as one has to carefully build a stack or
register oriented interface for it.
The quick solution, however, has all these maintainence problems,
portability problems, and etc. The external module solution requires extra
file/assembly work, and may require (for speed) that the control structures
be built in, too, depending on the objective of the code.
It is clear that the long term advantages come from external modules, and
the short term advantages come from ILAC. The converse is also true – no
short term advantages from modules, no long term advantages from ILAC.
I'm in it for the long term. How about you?
Ben
Amateur Radio Callsign is A A 7 A S
Ben,
I guess it really depends on what you're developing. If I'm writing an
application program, at work I rarely ever use assembler, and never use
ILAC. I don't need to. But if I'm writing a real time program (such as a
packet switching system) that requires sub-second response, or perhaps a
game program, that's a different story. I've found that for portability
reasons (between platforms), I try to stay away from ANY assembler because
it isn't portable between different processors (6809, 680xx, 80xxx, etc.)
But, for a game, I have a real problem with people who write games that
don't really on the particular hardware of the machine to enchance
performance/appearance/playability, just to make it easier to port the game
to another machine. I believe the primary motivator there is $$$, not
readability, etc. So in one sense, I agree with you: high level
applications should be kept portable and maintainable by avoiding assembler
when possible. On the other hand, there are times when squeezing a few
extra micro-seconds out of a program can make a difference, but would not
necessarily warrant the time and effort needed to write a separate
assembler module (as in a real-time, 3-D game), since a lot of that part of
the code would probably have to be re-written to port the game to another
machine anyway. By the way, how does having the ability to do ILAC affect
the quality of a compiler anyway? Isn't the programmer supposed to decide
what will be used/not used concerning style/"good programming"? I really
would rather the compilers DIDN'T decide for me 😉
Marcus :^{
Marcus, I have _no_ objection to the mixing of asm and C. I do feel that
the mixing should only be done at module boundries, however. I've written a
great deal of mixed code myself – probably more than the majority of Amiga
developers, although I am of course guessing. I'm perfectly comfortable in
asm, and in fact it was all I worked in up until about 7 years ago, having
tossed the early "high level" languages out as unusable for performance
applications.
As for the user deciding rather than the compiler… sure. Sounds great to
say that. Do you want your compiler to include apl parsing, with the
decision left up to the programmer as to whether to include APL in the
current module?
#apl
$#(*%($@*%&$#(&% #endapl
how about…
#basic
40 GOSUB 1100: GOSUB 2300: IF A>B GOTO 50
45 PRINT "HI MOM"
50 PRINT "HI DAD" #endbasic
I mean, is it appropriate? These "features" would bring extra functionality
– and confusion – and portability problems.
One problem with any implementation of such a thing is that not all
compilers have it – even on the same machine – and if they DO have it, then
the underlying assumptions (registers, asm language, etc) may not be the
same. K&R simply say that "some version "may" reserve the keyword asm" in
the 1st book, and in the second book, the same line, unchanged appears in
the reference. The 2nd book covers the ANSI version, in case you don't know
that. Do you want to use a "feature" that is so nebulously defined? I don't
– and I don't want to have to decipher it, either. If you need performance,
write an asm module. Then you'll have it. If yo u need elegance, write a c
module. I believe that mixing languages is best done at the link level.
Then, in the form of the function calls, you at least have the definition
of what the module is supposed to do. Inside a module, asm is a black
mystery.
You seem to have rather strong feelings about this. <grin>
moi? I guess I have strong feelings about most things. I'm a b&w kind of
guy.
Wow! that was a quick reply. And I though *I* was on here a lot. Marcus
:^) BTW-I was at the HamVention. Were you there? Someone told me there was
an Amiga-3000 there, but I couldn't find it. *Sigh*.
Yes, I was there, in the AEA booth. We were showing the AVT system and the
HAM-E.
What does AEA stand for?
Advanced Electronics Applications, Incorporated.
A feature that is not used destroys no portability. A feature that is used,
knowingly, will destroy portability at the discretion of the programmer.
Nebulously defined language definitions are not rare in 'standard' C.
Yes, yes, and, unfortunately, yes.
Ben
Amateur Radio Callsign is A A 7 A S
Marcus,
Naw, I don't agree. I learned in machine code (hex code, not asm)
switched to asm and am now using C. If I'm feeling lazy, I'll generally
code things in asm, since I KNOW what is going to be generated. This is
certainly the case when I need to bang bits, it codes faster and runs
faster.
I agree with Ben, if you are going to use asm in a C program, break it
out into a seperate module and make a function call to it. It's simple
enough to do, and keeps me, at least, from having to switch mental gears in
mid stream. I'm also leary of what happens to inline asm when compiler
revisions change. Assumptions can kill ya.
Dean
DKB Software
Dean,
I understand your point, but you have come from a STRONG assembler
background. I started with ASM, but that was 10 years ago. The processors I
wrote entire assembler programs for were 8080's, Z80's, etc. I switch to C
about 8 years ago, and have only touched assembler on a few occations on
68000's, 80286's, etc. What may be easy or second nature to you, may not be
so easy to a large number of C programmers. I still find it a bear to set
up a separate assembler module on a PeeCee, especially if I haven't done so
recently. I really have a great deal of respect for programmers who speak
assembler as well as english <grin>, but I'm no longer one of them. Just a
different perspective I guess.
Marcus