* mike3:
I use the Borland C++ Builder 5.5 Command line tools.
Gratis, really?
Yep.
Is there a "stripped" version that has only the
C++ compilers, like with the Borland thing?
Not as far as I know, but unless it's very different from 7.1 you can
use the command line tools separately from the IDE.
[snip]
Then I'd be curious to know. Does this require a cast,
to get the value of the pointer for our error information?:
FG3DError SomeRoutine(BigFloat *a)
{
FG3DError err;
<blah blah blah>
if(<some operation on "a" failed>)
return(FG3DError(<Error code>, a)); <--- here
else
return(FG3DError(FG3D_SUCCESS));
}
Do something like
void someRoutine( BigFloat const& a )
{
// some operation on "a"
}
If "some operation" fails it will throw an exception.
What if the operation though is something that returns
an error value instead?
The you convert to exception.
Fair warning: code below is my preferred way but many programmers find
it unnatural. If you find it unnatural, just replace "||" with "if".
bool throwX( char const s[] ) { throw std::runtime_error( s ); }
void someRoutine( BigFloat const& a )
{
someOp( a ) == NO_ERROR || throwX( "someRoutine: someOp failed" );
}
Oh and when I throw the exception
I also need to convert a pointer to give additional
information to whatever handler catches the exception,
(there's handlers in any area where exceptions may
get thrown out of) for example to show that an
operation on "a" failed.
That seems to a requirement that stems from a particular current
solution. When replacing the current solution the requirement then
disappears.
Should there be _no_ functions that return error
values, and instead _always_ throw exceptions when
they fail (as that way you don't have to worry about
neglecting an error check around one, you can just
keep a few exception handlers at various levels,
etc.?)?
Personal preference. There is a run-time cost associated with throwing
exceptions, and that needs to be weighted against clarity and ease of
programming: running time versus programmer's time and correctness. But
in general, as long as the program is fast enough, exceptions are in my
experience preferable even when the situation is not "exceptional".
However, it's /very important/ to think about simplicity of /usage/.
For if using the function will then require a try/catch in the immediate
caller for the most common usage, then exceptions are strongly
contra-indicated -- most try/catch-es indicate a possible improvement.
[snip]
No, in the code you showed the arguments would be promoted to int, the
computation done as int, and only then the result converted to long.
So then you have to typecast, right?
Nope.
[snip]
So then would a typecast be a good idea?
Or is does this do it, and is it "proper"?:
---
double DivideInts(int a, int b)
{
double adbl = a;
double bdbl = b;
return(adbl/bdbl);
}
This is good, but perhaps even better:
double doubleDiv( int a, int b ) { return 1.0*a/b; }
For some reason I like one-liners...
Any half-decent compiler should optimize away the "1.0*". What it does
is to force a promotion to double of a and b. Before anything else.
[snip]
It works now! The bug has been fixed!
Good.
The Init functions are *pnly* and I say again, *ONLY*
called in CONSTRUCTORS, period. And *always* called from
them. They're just there to save a bit of cutting-and-
pasting. At no point are they called anywhere else.
By expressing them as constructors (of e.g. a private base class) you
express that in code, /ensuring/ that they're not called from anywhere
else, and so making it completely safe to remove initialization checks.
[snip]
Could you tell me where my design is wanting, by the way?
I'd like to know so I can improve it.
Please note first that /every/ design is wanting.
There is no such thing as a prefetc design.
So the question is where to draw the line of possible improvement versus
work.
Since the present design is causing trouble, that line is not yet reached.
I'd start by a physical repackaging, not design. Currently, 'main.h'
(or something) is included everywhere, and a module's implementation
does not include the module's own header file. That should be exactly
opposite, for a great number of reasons, one of which is that currently
any change of 'main.h' forces a recompilation of (nearly) everything.
The main design problem I saw, with just a cursory look at the code, was
a mix of very high level (abstract operations) and low level (pointers,
casting), an abstraction gap, indicating one or more missing
intermediate levels.
Try to encapsulate low-level operations in some not-very-high-level
classes. For example, such encapsulation classes, or functions, do all
pointer stuff, translate from error codes to exceptions, etc. Just
getting that bug-inducing low level stuff /out of the way/, packaged.
Else-thread I have already mentioned another aspect of that high level
low level clash, that it would be a good idea to use std::vector instead
of raw arrays and pointers.
I think the above is the most important. But since no design is
prefetc, having done this other possibilities (including replacing
Init-functions with constructors, if not yet done) will suggest
themselves. The important thing then is to be very aware of whether the
improvements fix current bugs, prevent future ones, help future
maintainance, help reuse, or what. If the gain is not clear, but is
just "feels more elegant", then possibly the line has been reached.
[snip]
Ah, thanks.
Cheers, & hth.,
- Alf