To go with Go or C/C++?

T

Tony

No, I mean using the 'class' keyword to provide many of the benefits of
objects. Data encapsulation, code organization, etc.

I knew what you meant straight away. I think that maybe Paavo was being
facetious (or propagandish).
 
T

Tony

(e-mail address removed) (Scott Lurndal) wrote in


Here I have to agree with you, .*printf interface is often much more
convenient. But I never use it directly, I have written special C++ class
wrapper to make it typesafe (everything is converted appropriately), so the
usage goes approx like this:

std::string date = Sprintf("%02d.%02d.%04d")(day)(month)(year);

This is similar to boost::format AFAIK.

I too have my own "type-safe printf-like" library (and many other such
replacements). Funny how so many people have their own elementary facilities
rather than using the ones provided by the C++ language. I still conjecture that
at some time, every C++ programmer who is a software developer will outgrow C++
and seek another language or create one (save for the ones who milk the cash cow
for all it's worth).
 
T

Tony

I agree. I do quite a lot of work in areas where there isn't any C++
run-time support (kernel land). Even without exceptions, RTTI and
chunks of the standard library, what's left of C++ is still a better C.

It's not C at all. It's a specific subset of C++. What you are describing is
"tits on a boar", but that doesn't jive.
 
S

Stuart

[snip]


Exercise left to the student. Suffice it to say that
real code does return an indication either via a return
value from a function or by setting state in the object
that can be subsequently interrogated.
Of course, not all such errors are fatal to the
application, or even of concern to the caller.

Point taken. I think that it is difficult to decide whether errors
should be propagated via return values or exceptions. Especially when
the code is put into some library, so that one doesn't know how the user
is going to use it.

Take the following example: You are writing a library that deals with
linear algebra. You'll certainly implement some matrix class which also
offers a function to compute the inverse of a matrix. How should this
function look like? There are two possible solutions:

class Matrix
{
public:
// Version that throws exceptions:
class MatrixIsSingularException;
class MatrixIsNonQuatraticException;
Matrix getInverted () throw (MatrixIsSingularException,
MatrixIsNonQuatraticException);

// or using error code
enum MatrixInversionErrorCode
{
MatrixIsSingular,
MatrixIsNonQuadratic,
InversionSucceeded
};
MatrixInversionErrorCode getInverted (Matrix& target) throw ();
Matrix getInverted (MatrixInversionErrorCode& target) throw ();
};

Now if somebody wants to use this code, he can either use the version
with exceptions or the version with error codes:

double foo (const Matrix& r, const Vector& v)
{
// r should be a rotation matrix, so there is no
// need to check for error codes (if r should
// be no rotation matrix, there is nothing sensible
// we can do here with the error code anyway).
return (r.getInverse () * v).getAngle ();
}

whereas the following code is faster with the error code version:

int main ()
{
std::cout << "Please enter a 3x3 matrix: ";
Matrix m;
std::cin >> m; // Error handling omitted.

// Now m is quite likely to be singular, so we better check for
// error codes (the version with exceptions would produce slower
// code).
MatrixInversionErrorCode e;
Matrix inverted = m.getInverted (e);
if (e == MatrixIsSingular)
{
std::cout << "Entered matrix is singular";
return 0;
}
std::cout << inverted;
}

Now everyone can decide whether to use the version with exceptions or
the version with error objects.

Of course, having to prove both versions of such functions is a PITA.
When I had to do some Microsoft COM programming, I wrote my own code
generator which provided exception aware versions for my COM objects
(automation compatible COM objects have to use error codes).

Regards,
Stuart
 
S

Stefan Ram

Stuart said:
Now if somebody wants to use this code, he can either use the version
with exceptions or the version with error codes:

And do you implement the error code version in terms of the
exception version or the other way round, or both using a
third private function?
Matrix inverted = m.getInverted (e);
if (e == MatrixIsSingular)

Let me suggest a third version, which is close to the spirit
of C's standard library! It's

Matrix getInverted()

, and its documentation says »The behavior for singular
matrices is undefined.«. It then might be used this way:

if( m.isSingular() )std::cout << "Matrix is singular.";
else { Matrix const inverted = m.getInverted( e ); ...

. Admittedly, this might be slower in this case, depending
on implementation details.
 
Ö

Öö Tiib

[snip]

Exercise left to the student. Suffice it to say that
real code does return an indication either via a return
value from a function or by setting state in the object
that can be subsequently interrogated.
Of course, not all such errors are fatal to the
application, or even of concern to the caller.

Point taken. I think that it is difficult to decide whether errors
should be propagated via return values or exceptions. Especially when
the code is put into some library, so that one doesn't know how the user
is going to use it.

I try to produce thoughts how it can be made less difficult. Common example
when exceptions seem to be thrown (for me) is impossible request of producing
something new that does not have common and valid "missing" states.

Lot of things can go exceptionally wrong with birth of new object. Resources
needed may be unavailable or inaccessible, input may be from "dirty" source
(like UI, communication channel or file) but not properly validated. On the
other hand constructors do not have return values.

If non-throwing version of constructor or factory is needed then the object
must have some valid "unavailable" or "broken" states. Novices feel being
in not smaller trouble with such possible states than with exceptions so
if one or other is "simpler" is hard to say. It sometimes is more helpful
to have static methods that check the situation for validity of construction,
return their assessment and neither throw nor construct anything +
throwing constructor instead of such broken states.

I never throw from functions for erasing or cleaning up. Such may be
used in some destructor and so can cause lot of problems.
Take the following example: You are writing a library that deals with
linear algebra. You'll certainly implement some matrix class which also
offers a function to compute the inverse of a matrix. How should this
function look like? There are two possible solutions:

class Matrix
{
public:
// Version that throws exceptions:
class MatrixIsSingularException;
class MatrixIsNonQuatraticException;
Matrix getInverted () throw (MatrixIsSingularException,
MatrixIsNonQuatraticException);

// or using error code
enum MatrixInversionErrorCode
{
MatrixIsSingular,
MatrixIsNonQuadratic,
InversionSucceeded
};

MatrixInversionErrorCode getInverted (Matrix& target) throw ();
Matrix getInverted (MatrixInversionErrorCode& target) throw ();
};

Request for inverse matrix that does not have inverse feels like request to
produce something that is impossible to construct. I would likely only
throw from here. What Matrix contains that the non-throwing version
returns? If someone ignores the error code and proceeds with returned
Matrix can he do something stupid with? Can he crash somewhat later?
I have seen several of cases when maintainer then tries to fix the situation
in point of such later crash because he can't find out why he suddenly has
such invalid "matrix" there.
Now if somebody wants to use this code, he can either use the version
with exceptions or the version with error codes:

double foo (const Matrix& r, const Vector& v)
{
// r should be a rotation matrix, so there is no
// need to check for error codes (if r should
// be no rotation matrix, there is nothing sensible
// we can do here with the error code anyway).
return (r.getInverse () * v).getAngle ();
}

whereas the following code is faster with the error code version:

int main ()
{
std::cout << "Please enter a 3x3 matrix: ";
Matrix m;

std::cin >> m; // Error handling omitted.
// Now m is quite likely to be singular, so we better check for
// error codes (the version with exceptions would produce slower
// code).

MatrixInversionErrorCode e;
Matrix inverted = m.getInverted (e);
if (e == MatrixIsSingular)
{
std::cout << "Entered matrix is singular";
return 0;
}
std::cout << inverted;
}

I have to disagree. It can not be measurably faster. On lot of platforms
you can throw and catch tens of thousands exceptions per second. To
achieve tens of thousands matrixes to be entered per second you must
somehow hook input from hundreds of thousands of simultaneous users
to std::cin of that application.

Also it would be lot more helpful if the place where "error handling
omitted" did instead help the user better to enter valid matrix for the
operation. If validity is well checked there then the throwing invert
would never throw and so would be faster.
Now everyone can decide whether to use the version with exceptions or
the version with error objects.

For me the reason why that second example is good for return values is
hard to see. I would go with exceptions. Return values likely work fine as
well in so limited case, but I don't see any benefits.
Of course, having to prove both versions of such functions is a PITA.
When I had to do some Microsoft COM programming, I wrote my own code
generator which provided exception aware versions for my COM objects
(automation compatible COM objects have to use error codes).

I did not parse. When there are both in interface then both versions have
very similar unit tests and most likely share most of the code too.
 
J

James Kanze

[...]
Since most of my programming is on linux, I use gcc's
__attribute__((printf,...)) to let the compiler ensure
type-safety,

Except that this feature doesn't work, since you almost never
have format strings that are compile time constants.
but your solution is superior to the C++ << >>
operator stuff.

Except that I've yet to see another solution which works.
Everyone complains about << and >>, but what else works? (By
works, I mean allows logical markup, where the format
specifications are *not* part of the immediate string, which
makes maintenance a real nightmare, and where you can define
input from and output to almost anything, including filters.)
 
I

Ian Collins

James said:
[...]
Since most of my programming is on linux, I use gcc's
__attribute__((printf,...)) to let the compiler ensure
type-safety,

Except that this feature doesn't work, since you almost never
have format strings that are compile time constants.

It also appears unnecessary due to gcc doing the type checking by
default. I don't buy the "never have format strings that are compile
time constants" part however. Just about everywhere I've seen (s)printf
used has been with a fixed format string.
Except that I've yet to see another solution which works.
Everyone complains about << and >>, but what else works? (By
works, I mean allows logical markup, where the format
specifications are *not* part of the immediate string, which
makes maintenance a real nightmare, and where you can define
input from and output to almost anything, including filters.)

I do agree with this part having recently been part of a lengthy debate
about portable printing of (u)int64_t types on an OS developer list...
This really boiled down to C introducing new types and adding clunky
macros rather than new format specifiers to print them.
 
Ö

Öö Tiib

It also appears unnecessary due to gcc doing the type checking by
default. I don't buy the "never have format strings that are compile
time constants" part however. Just about everywhere I've seen (s)printf
used has been with a fixed format string.

Lot of applications have some I18N (internationalist software). There
strings are produced by functions like '_("Untranslated text")' (GNU gettext) or
'tr("Untranslated text")' (Qt translation). Lot of applications do not have any
I18N (nationalist software). People *almost* *never* work both with
nationalist and internationalist software. Internationalist software can use
RTTI to report errors runtime also some sort of static analysis can be made
but the checks of gcc do not help with it.
 
R

Rosario1903

That's for sure. But to really understand C (or motivation behind it),
one has to know at least one assembler.

easy words written in a page as assembly
can be better of all the c++

the power is in the words dispose in the page.
the power is in the words world
not the concept they would represent, not in the program that run
 
J

James Kanze

(e-mail address removed):
Paavo Helde <[email protected]> writes:
[...]
Since most of my programming is on linux, I use gcc's
__attribute__((printf,...)) to let the compiler ensure
type-safety,
Except that this feature doesn't work, since you almost never
have format strings that are compile time constants.
If the format string is not a compile time constant then it is indeed
hard to use the printf-style formatting because it would become
cumbersome to ensure that even the number and order of the arguments
match (all possible variants of) format strings, not to speak about the
type safety.

About the only time I've had to output compile time constants
was when doing programs for some government authority. If
you're code implements French tax laws, then you probably don't
have to worry about outputting in German. For almost everything
else, output strings have come from external, language dependent
files. (Of course, if you really have to support natural
languages in all of there detail, rather than just translating a
few simple messages, you'll need a separate DLL for each
language, so you could end up with compile time constants there
as well.)
This does not mean that I would advocate using gcc-s __attribute__. First
it is non-portable, second it requires special attention from the
programmer, and third, the programmer is still not relieved from the duty
of taking care of the low-level type correctness and needs to type in
explicit casts and conversions when needed. A C++ typesafe solution can
do all this work for the programmer and convert everything automatically.
Admitted, the printf-style formatting is a limited tool, but in its
limited area it does its job well. We are using it mostly for composing
error and log messages, so there is no fancy object serialization or
stream filtering involved.

Logging is one case where you often can use a single language.
It's also a case, however, where using printf would be a
maintenance nightmare, since you're outputting internal types,
which could easily change.

Even at the time and place where it was invented, printf was a
step backwards, compared to other languages. The "motivation"
behind it is, I suspect, the desire to not make IO part of the
language, but strictly a library component. Realistically, I
think we can call it an experiment which failed. C++ manages to
make IO purely library, but only because it has overloading and
polymorphism.
 
B

Balog Pal

[...]
Since most of my programming is on linux, I use gcc's
__attribute__((printf,...)) to let the compiler ensure
type-safety,

Except that this feature doesn't work, since you almost never
have format strings that are compile time constants.

Does not match my experience -- indeed there are cases with localized
strings but those are not majority. Not completely sure for the reasons,
that might be the maintenance overhead, so those are avoided as much as
possible.

And if they were in majority I can think of automated solutions that
locate the spots and replace the actual string from the resource file
for checking.
 
W

woodbrian77

Logging is one case where you often can use a single language.

It's also a case, however, where using printf would be a

maintenance nightmare, since you're outputting internal types,

which could easily change.

In the past I worked on a "logging service" that like
the C++ Middleware Writer helped with the maintenance
problems. G-d willing that project will come back to
life in the future.

Even at the time and place where it was invented, printf was a

step backwards, compared to other languages. The "motivation"

behind it is, I suspect, the desire to not make IO part of the

language, but strictly a library component. Realistically, I

think we can call it an experiment which failed. C++ manages to

make IO purely library, but only because it has overloading and

polymorphism.

In my view the << >> stuff was a step forward and a
step backward. The step back involved the loss of
the concept of a unit that printf has -- these n
items go together to form one thing.


Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net
 
I

Ian Collins

David said:
James said:
On Friday, May 10, 2013 6:09:27 PM UTC+1, Scott Lurndal wrote:

[...]
Since most of my programming is on linux, I use gcc's
__attribute__((printf,...)) to let the compiler ensure
type-safety,

Except that this feature doesn't work, since you almost never
have format strings that are compile time constants.

It also appears unnecessary due to gcc doing the type checking by
default.

That's because the libraries for gcc already have the "printf" attribute
in their declarations for things like printf, snprintf, etc. So you
only need the attribute if you are making your own printf-like functions.
I don't buy the "never have format strings that are compile
time constants" part however. Just about everywhere I've seen (s)printf
used has been with a fixed format string.

I agree with that in most cases. And the C++ standard alternative -
using << and >> - fixes the formatting in compile-time code.

One common situation where the format strings are non-constant is with
internationalised code, such as using gettext. Then you have things like:

printf(_("The date is %02d/%0d\n"), day, month);

I agree, my objection was to the "almost never". An awful lot of code
gets written without internationalisation.
 
J

James Kanze

(e-mail address removed):
]
Since most of my programming is on linux, I use gcc's
__attribute__((printf,...)) to let the compiler ensure
type-safety,
Except that this feature doesn't work, since you almost never
have format strings that are compile time constants.
If the format string is not a compile time constant then it is indeed
hard to use the printf-style formatting because it would become
cumbersome to ensure that even the number and order of the arguments
match (all possible variants of) format strings, not to speak about
the type safety.
About the only time I've had to output compile time constants
was when doing programs for some government authority. If
you're code implements French tax laws, then you probably don't
have to worry about outputting in German. For almost everything
else, output strings have come from external, language dependent
files. (Of course, if you really have to support natural
languages in all of there detail, rather than just translating a
few simple messages, you'll need a separate DLL for each
language, so you could end up with compile time constants there
as well.)
My feelings about i18n are mixed. On one hand it would be nice to
communicate with the software in my own language. On the other hand the
general state of the art seems to be so bad (e.g. half of menu items in
broken native language, and half in English) that I almost always switch
the interface to English.

That's generally a problem in technical software. Each
translator invents his own translation for newer technologies,
or each company develops its own standards. (I know that when
I worked at Siemens, we often spoke of Siemens-Deutsch: a set of
translations for things like cursor which were only really known
within Siemens, and not even always then.)
In my mind, converting some software to a native language should be done
well or not done at all. With the kind of software we are making, I
cannot see the former happen in the next 30 years, for various reasons.
And by then the Google Glasses should be advanced to the Babel Fish level
already so there should be nothing to worry about.
I guess this all depends on the scope of the application. And yes, our
software is used in France and China. We are taking care that if someone
wants to write filenames or dataset annotations in hieroglyphs he can do
so. However, the error messages will still be in English.

This is probably acceptable for some types of technical software
(e.g. a C++ compiler). For most things, however, you'll want
a local language interface, and most of the companies I've
worked for have insisted on it (including when I was working on
compilers for Siemens).
That's why one needs to use C++ typesafe equivalents of printf.

Or simply `std::eek:stream`. It's much better adopted to the
different sinks you're likely to encounter. Logging almost
always means custom streambuf's.
I think you are mixing up formatting and IO, these are quite orthogonal
topics.

Not for the printf family.
IO is done by OS and is mostly binary, it sees only bytes and
does not care about types.

Perhaps I should have said sinking and sourcing rather than IO;
I thought the implication was obvious. With the printf family,
you have to use different functions for different sinks and
sources; with iostream, it's all handled in the concrete
strategy of the streambuf.
Nevertheless, many newer languages have borrowed the printf concept,
primarily because of its concise syntax. As soon as the language is
introspective enough to know the types of its variables, one can make a
typesafe printf, removing its largest drawback in C.

Typesafety is only one of the problems of printf. The lack of
extensibility is an issue anytime you can define your own
types. Or you need to define your own sinks and sources.

Which means pretty much always.
 
J

James Kanze

On Friday, May 10, 2013 6:09:27 PM UTC+1, Scott Lurndal wrote:

[...]
Since most of my programming is on linux, I use gcc's
__attribute__((printf,...)) to let the compiler ensure
type-safety,
Except that this feature doesn't work, since you almost never
have format strings that are compile time constants.
It also appears unnecessary due to gcc doing the type checking by
default.
[/QUOTE]
That's because the libraries for gcc already have the "printf" attribute
in their declarations for things like printf, snprintf, etc. So you
only need the attribute if you are making your own printf-like functions.
I agree with that in most cases. And the C++ standard alternative -
using << and >> - fixes the formatting in compile-time code.

Not any more than standard printf.

Unix extends it to allow changes in order. Back when I started
C++, I implemented something similar in a type safe manner, with
full support of _all_ of the printf formatting options. It
turned out to be useless. By the time you have to start
worrying about word order, you're also having to deal with
things like agreement (where adjectives have to agree in number,
gender, and possibly case with the noun they modify) and other
more complicated issues. If you need variations in word order,
you probably need a separate DLL for each language, to handle
the grammatical issues.
One common situation where the format strings are non-constant is with
internationalised code, such as using gettext. Then you have things like:
printf(_("The date is %02d/%0d\n"), day, month);
gcc can't do static checking on this as it stands - but it's easy enough
to add some pre-processor magic so that you can do a "check" compile
with _() defined to nothing.
And you can do things like add an American translation of the string as
"The American-style date is %2$02d/%1$02d\n" - something that cannot be
achieved with << and >>.

Not with standard printf. That's a Unix (not even Posix)
extension. And from experience: it doesn't work. (The case of
dates is particularly special: there are a number of
conventions, which don't respect the usual locales---US military
uses a different format than civilian use, etc. The best
solution here is to correctly overload
operator<<( std::eek:stream&, Date const& ) to do the right thing,
picking up the format from a user defined manipulator, and
things like the names of months from an external file. Or just
to use ISO format everywhere, but the world isn't ready for that
yet.)
There are times that << and >> are useful too - but printf and friends
are still often the best choice.

I can definitely think of cases where there could be better
solutions than << and >>. But none where printf would be that
solution.
 
J

Jorgen Grahn

I agree. I do quite a lot of work in areas where there isn't any C++
run-time support (kernel land). Even without exceptions, RTTI and
chunks of the standard library, what's left of C++ is still a better C.

And I agree too, but it didn't seem to me that is what SL wrote about;
he seemed to talk about replacing 'struct' with 'class'. Of course,
now that I think of it it doesn't make sense to do so unless you also
add member functions, so he was really talking about something less
trivial than that.

However, I still see no reason to avoid major C++ features in the
normal case, i.e. where a full C++ implementation is available.

/Jorgen
 
J

James Kanze

Actually, it is POSIX.

Yes. It looks like it got added in one of the recent updates.
And the positional parameters have been around since
Unix V7.

System V, actually. Or rather, the X/Open standardization of
System V. Sometime in the mid or late 1980's. It definitely
wasn't in V7 or the Berkley kernel.

It sounded like a good idea back then. As I said, in practice,
it really didn't buy much, which may account for the fact that
there's been no interest in bringing it into ISO C.
For dates, on POSIX systems, use strftime(3)/strptime(3).

strftime is standard C (and thus C++). But generally, you'll
want a Date class, with overloads for << and >>. (The overload
for << would probably use strftime. Parsing is more difficult,
and strptime helps less than one would expect, since you've
still got to get the data out of the stream, and recognize when
it ends.)
 
J

Jorgen Grahn

So what would you say to people who want to use C++ in small embedded
systems, especially when safety or reliability is vital?

That you have to make exceptions for exceptional cases. I never
intended to claim there are no reasons at all not to use all of C++.

[snip]
....
I agree that to use the advantages C++ gives you, you need to design
your program in a different way from plain C. But that certainly does
not mean you have to use all the "major features" of C++ in order to
write better programs.

True -- there's a lot I never or rarely use myself. My point was that
there's some loosely-defined core which it's almost never (not "never")
wise to avoid.

/Jorgen
 
S

Stefan Ram

Jorgen Grahn said:
That you have to make exceptions for exceptional cases.

C++ makes so much effort for the sake of efficiency
that it might be against the spirit of C++ to use
or not to use exceptions solely for stylistic reasons,
when the use or non-use would clearly be more efficient
in a certain case.

For example, one can write

result = f()? g() : h(); return result;

or

if( f() )return g(); else return h();

. I prefer single returns (first case) for reasons
of structured programming, but I had to learn that
immediate returns (second case) where faster under
some implementations (I don't remember whether this
was C or C++). Therefore, I might prefer the second
solution.

The question is whether you can really subset C++.
You might decide not to use templates or exceptions.
But when you use ::std::vector you are using a
template, and when you call a function from a third-
party library, you better be prepared for the
possibility that it might throw an exception.

There is done more maintenence programming in the
world than programming of new projects.
The C++ maintenance programmer cannot choose the
subset that is used in the code he has to maintain.
So he has to be prepared for everything.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,102
Messages
2,570,646
Members
47,247
Latest member
GabrieleL2

Latest Threads

Top