Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > which of these 3 casts would you prefer?

Reply
Thread Tools

which of these 3 casts would you prefer?

 
 
Duga Chernobyl
Guest
Posts: n/a
 
      08-27-2011
Dnia 26-08-2011 o 23:27:03 Jorgen Grahn <(E-Mail Removed)>
napisał(a):

> On Fri, 2011-08-26, Duga Chernobyl wrote:
>> Dnia 26-08-2011 o 14:40:27 A <(E-Mail Removed)> napisa??(a):
>>
>>> I do not understand though reluctance to use C style casts.
>>>
>>> They can cast to reinterpret_cast but they also try out the weaker cast
>>> before. It is just automatic way to do what you would do manually -
>>> first
>>> try const_cast, then static_cast and finally reinterpret_cast... yes,
>>> it
>>> can
>>> use reinterpret_cast but you would have to use it anyway in a
>>> particular
>>> case where you really need it.
>>>
>>> So what's wrong with little automation, providing that you know what
>>> you
>>> are
>>> doing with casts?

>
>> Sometimes you are tired and you don't want to check, if something is
>> good
>> or bad. For me compiler is the best friend (in programming )

>
> Yes, in C++ programming anyway.
>
>> and always
>> set this settings:
>>
>> Try search all convertions with c++ style and all with c style. What,do
>> you think, is easier to find all of them?
>>
>> -Wall -Wextra -pedantic -g -pg

>
> I'm surprised you're listing g++ warning options, but omit the topical
> one: "-Wold-style-cast". I use it for all my code.
>
> /Jorgen
>


Thanks
 
Reply With Quote
 
 
 
 
Jorgen Grahn
Guest
Posts: n/a
 
      08-27-2011
On Sat, 2011-08-27, Duga Chernobyl wrote:
> Dnia 26-08-2011 o 23:27:03 Jorgen Grahn <(E-Mail Removed)>
> napisa??(a):


>> I'm surprised you're listing g++ warning options, but omit the topical
>> one: "-Wold-style-cast". I use it for all my code.


> Thanks


You're welcome It took me a few years to discover that flag --
I think programmers in general read their manuals to rarely.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
 
Reply With Quote
 
 
 
 
BGB
Guest
Posts: n/a
 
      08-27-2011
On 8/26/2011 5:40 AM, A wrote:
> I do not understand though reluctance to use C style casts.
>
> They can cast to reinterpret_cast but they also try out the weaker cast
> before. It is just automatic way to do what you would do manually - first
> try const_cast, then static_cast and finally reinterpret_cast... yes, it can
> use reinterpret_cast but you would have to use it anyway in a particular
> case where you really need it.
>
> So what's wrong with little automation, providing that you know what you are
> doing with casts?
>


unlike the others here, I don't take much issue with C style casts.


then again, I am also primarily a C programmer (for various reasons),
and most of the C++ code I have written has been in a C-like style
(usually either because for some reason I needed C++, such as
interfacing with a C++ only library, or because there is C++/CLI but not
a C/CLI, ...).


one can also argue that function overloading and operator overloading
are nifty, but rarely have I found this to be a big issue (one can
typically sort-of make due with using short macro names to redirect to
longer operator function names or similar, and with the convention of
using short suffixes to function names to indicate the argument types or
similar...).


it is not that I don't know about OOP or whatever, just that:
what I usually want done can be done "well enough" in C explicitly using
structs and vtables (so C can still do OOP, sort of);
in other cases, I am using a language like C# or Java, or my own
scripting language (vaguely ActionScript-like);
it often just so happens to be a bit easier to do multi-direction
cross-language interfacing in C than in C++.


not that my case likely represents a normal development process though,
and if one is doing pure C++ (or pure C++ for application code with C
mostly in back-end libraries), then the comments made by others here
make more sense.

also, FWIW, my own scripting language doesn't have C-like casts (mostly
for syntactic reasons though, namely syntactic ambiguity), but instead
splits them into multiple casts indicated by a keyword ("x as type", "x
as! type", ...).


or such...
 
Reply With Quote
 
Juha Nieminen
Guest
Posts: n/a
 
      08-27-2011
BGB <(E-Mail Removed)> wrote:
> one can also argue that function overloading and operator overloading
> are nifty, but rarely have I found this to be a big issue (one can
> typically sort-of make due with using short macro names to redirect to
> longer operator function names or similar, and with the convention of
> using short suffixes to function names to indicate the argument types or
> similar...).


The reason why function and operator overloading is important is not
because it's "handy" or "convenient" or anything like that. It's because
it's *necessary* for generic programming. It's what allows you to do
things like this:

template<typename T>
T foo(T value)
{
std::cout << "The input value was " << value << std::endl;
return std::cos(value);
}

The above code would be impossible without function and operator
overloading. For example in C you have cos(), cosf() and cosl(), and
you just can't write a macro that would call the proper function based
on the type of the parameter. In C++ you have just different versions
of std::cos(), and the proper version will be automatically called
depending on the type of parameter.

(You could write *three* macros with different names, but now you have
not only triplicated your code, you have made it impossible to call
the macro from other macros without triplicating those too, so the
triplication becomes contagious. Also, it doesn't allow the user to use
a custom user-defined type.)

Likewise it's what allows the std::cout above to work properly.

This is something the most C programmers don't understand. They are
not to blame, though, because many C++ programmers don't know this either
(or have never thought about it).

> it is not that I don't know about OOP or whatever, just that:
> what I usually want done can be done "well enough" in C explicitly using
> structs and vtables (so C can still do OOP, sort of);


The major problem in C is not the lack of dynamic binding. It's the
lack of RAII and templates. (And, to some extent, exceptions.)
 
Reply With Quote
 
Noah Roberts
Guest
Posts: n/a
 
      08-27-2011
On Aug 26, 5:40*am, "A" <(E-Mail Removed)> wrote:
> I do not understand though reluctance to use C style casts.
>
> They can cast to reinterpret_cast but they also try out the weaker cast
> before. It is just automatic way to do what you would do manually - first
> try const_cast, then static_cast and finally reinterpret_cast... yes, it can
> use reinterpret_cast but you would have to use it anyway in a particular
> case where you really need it.
>
> So what's wrong with little automation, providing that you know what you are
> doing with casts?


Perhaps a story would help you understand.

A while back I worked under a guy who used C++ but basically feared
everything about it. Boy did he love inheritance though. He used
inheritance as his only method of code reuse. He created these
gigantic higherarchies that spanned multiple concepts attempting to
tie them together. Trying to add a new object to this system was a
nightmare because a lot of the time he put in "assert(false); // this
function shouldn't be called" as the base object definition instead of
using pure virtuals. He did this because his higherarchy was a total
pain in the ass and required you to implement more functions than you
needed. This of course left one not knowing what functions they
needed to override until running the program and getting an assert.

Eventually this guy quit and moved on to other things and places.
Hopefully he learned something about code design but he was pretty
stubborn. Once he did, I set about trying to fix the project and put
it into a state that allowed for more code reuse and in which it was
easier to add new behavior.

Did I mention this guy hated everything C++? This included new-style
casts. He used C casts everywhere. He even used them where they were
not necessary. For example:

class Object
{
public:
Object* readObjectA(char* c) { return (Object*)ObjectA(c); }
... lots more of these ...
};

class ObjectA : public Object { ... };

Now, I did not realize this was going on at the time. I split all the
various responsibilities that Object had in its interface into
multiple base objects and used multiple inheritance to apply those
interfaces only where they were being used. Sent the code off to
testing and it starts acting really stupid. What happened?

Well, the original developer had seen something in the compiler output
like, "cannot convert ObjectA* to Object*, use a reinterpret or c-
style cast," and so he did that instead of realizing he needed to put
these functions in a place that could see the full definition of
ObjectA so that it COULD do that conversion the way it's supposed to.
Believing only in all things C this kind of thing comes completely
natural to him. Of course, a reinterpret cast to one base among many
is a very bad thing to do.

This problem was trivial to fix but later I ran into further issues.
Because there were C style casts all through the code, we had
opportunity for more issues to come up. This used the Win32 API and
had a lot of callback functions. These functions would take a type
number ID (guy hated RTTI and dynamic casting) and then cast to the
appropriate type, having already casted the long or void* to the base
type. Often this code would assume it's only going to get a certain
subset of objects passed to it because they're the only ones that have
some somewhat related functionality. If the type wasn't of one it
would assume the other. It would use c-style casts to do so. So the
code would promptly cast to the wrong derived class object and start
calling functions on it. This issue did not turn up until I started
messing with things; it was of course illiciting undefined behavior
all over the place but nobody was the wiser about it because it just
worked, and had worked for 15 years.

Because this guy used c-style casts instead of the appropriate new-
style (or even the inappropriate one), it was quite impractical to
hunt down casts like these and fix them. They had to turn up as
errors, which occasionally they did when we started adding new objects
to the tree that performed roles that were previously assumed to only
be performed by a group of classes. We knew that we needed to start
doing dynamic casts for these and shooting out error or exceptions
(which the guy also hated of course) instead of allowing undefined
behavior, but we were stuck because there is no such thing as a
regular expression that will match c-style casts.

This product tree had to be scrapped and redone. We were stuck with
old interfaces, lacked any amount of I18N and were trying to get into
foreign markets, etc...things that nobody really thought of when the
project started and because of poor design choices and especially
because of an abundant use of C-style casts...the amount of work
necessary to fix the code was astronomical compared to simply redoing
the whole thing. Cost the company many thousands of dollars to do so
and they're still at it 3 years later.

C-style casts are horrible because they can do anything at any time
without any warning. One minor code change can turn a static cast
into a reinterpret cast. You can't hunt these things down because
regular expressions are useless. The undefined behavior they cause
may or may not turn up at some time in the near future....it may be 2
decades before your code starts crashing in some place utterly
unrelated to the cast in an object that has nothing to do with what is
actually in the memory its using. NOBODY can keep track of every
place that needs to cast, especially within complex desktop
applications that use casting quite regularly. Stuff gets lost and
bad things happen. The new style casts provide a much better method
because they turn up more errors, you'll get a compiler error instead
of successful compile when your static_cast is no longer appropriate,
and can be searched for quite easily. They should be used for all
cases in which they can be, which is all cases in most projects.
 
Reply With Quote
 
Noah Roberts
Guest
Posts: n/a
 
      08-27-2011
On Aug 27, 11:38*am, Juha Nieminen <(E-Mail Removed)> wrote:
> BGB <(E-Mail Removed)> wrote:
> > one can also argue that function overloading and operator overloading
> > are nifty, but rarely have I found this to be a big issue (one can
> > typically sort-of make due with using short macro names to redirect to
> > longer operator function names or similar, and with the convention of
> > using short suffixes to function names to indicate the argument types or
> > similar...).

>
> * The reason why function and operator overloading is important is not
> because it's "handy" or "convenient" or anything like that. It's because
> it's *necessary* for generic programming. It's what allows you to do
> things like this:
>
> * * template<typename T>
> * * T foo(T value)
> * * {
> * * * * std::cout << "The input value was " << value << std::endl;
> * * * * return std::cos(value);
> * * }


You don't even need to be doing this to run into the lack of function
overloading as a great annoyance. I recently started working in a
project where the lead architect insists it's in C (there are a bunch
of other things that are more frustrating to me about it than that,
but whatever). I've found the necessity to think of obscure names to
make sure to avoid any naming conflicts is a serious quandry. For
example, in writing a generic stack, vector, or managed string class
(I have no problem with C OOP, it can be elegant in its own way) you
have many functions that have a related concept but of course are very
different in implementation. You could use polymorphism to get by,
but what if you don't want to use polymorphism? You're quite stuck
having to name functions like isEmpty to things like
isNamespaceStackEmpty and isNamespaceStringEmpty, and you're always
going to be worried that somewhere someone else is naming their stack
or vector functions the same thing.

Luckily the project code is quite small and this isn't anything but a
minor annoyance, but I can't imagine having to deal with it on a
larger scale. In C++ these things just work themselves out and they
work themselves out quite well in a very direct manner that is easy to
detect errors. There are rules like ADL and more complex rules when
possible overloads are templates, but they're actually not that hard
to remember especially for the gain you get from them. Honestly this
issue has bugged me more than any lack of operator overloads, etc...
 
Reply With Quote
 
RaZiel
Guest
Posts: n/a
 
      08-27-2011
On 26.08.2011 23:27, Jorgen Grahn wrote:
> On Fri, 2011-08-26, Duga Chernobyl wrote:
>> Dnia 26-08-2011 o 14:40:27 A<(E-Mail Removed)> napisa??(a):
>>
>>> I do not understand though reluctance to use C style casts.
>>>
>>> They can cast to reinterpret_cast but they also try out the weaker cast
>>> before. It is just automatic way to do what you would do manually - first
>>> try const_cast, then static_cast and finally reinterpret_cast... yes, it
>>> can
>>> use reinterpret_cast but you would have to use it anyway in a particular
>>> case where you really need it.
>>>
>>> So what's wrong with little automation, providing that you know what you
>>> are
>>> doing with casts?

>
>> Sometimes you are tired and you don't want to check, if something is good
>> or bad. For me compiler is the best friend (in programming )

>
> Yes, in C++ programming anyway.
>
>> and always
>> set this settings:
>>
>> Try search all convertions with c++ style and all with c style. What, do
>> you think, is easier to find all of them?
>>
>> -Wall -Wextra -pedantic -g -pg

>
> I'm surprised you're listing g++ warning options, but omit the topical
> one: "-Wold-style-cast". I use it for all my code.



For those who aren't using GCC, here is an alternative (Perl script):
http://www.abisource.com/mailinglist.../May/0198.html

>
> /Jorgen
>


- RaZ
 
Reply With Quote
 
BGB
Guest
Posts: n/a
 
      08-27-2011
On 8/27/2011 11:38 AM, Juha Nieminen wrote:
> BGB<(E-Mail Removed)> wrote:
>> one can also argue that function overloading and operator overloading
>> are nifty, but rarely have I found this to be a big issue (one can
>> typically sort-of make due with using short macro names to redirect to
>> longer operator function names or similar, and with the convention of
>> using short suffixes to function names to indicate the argument types or
>> similar...).

>
> The reason why function and operator overloading is important is not
> because it's "handy" or "convenient" or anything like that. It's because
> it's *necessary* for generic programming. It's what allows you to do
> things like this:
>
> template<typename T>
> T foo(T value)
> {
> std::cout<< "The input value was "<< value<< std::endl;
> return std::cos(value);
> }
>
> The above code would be impossible without function and operator
> overloading. For example in C you have cos(), cosf() and cosl(), and
> you just can't write a macro that would call the proper function based
> on the type of the parameter. In C++ you have just different versions
> of std::cos(), and the proper version will be automatically called
> depending on the type of parameter.
>
> (You could write *three* macros with different names, but now you have
> not only triplicated your code, you have made it impossible to call
> the macro from other macros without triplicating those too, so the
> triplication becomes contagious. Also, it doesn't allow the user to use
> a custom user-defined type.)
>
> Likewise it's what allows the std::cout above to work properly.
>
> This is something the most C programmers don't understand. They are
> not to blame, though, because many C++ programmers don't know this either
> (or have never thought about it).
>


yes, fair enough. C does not do this...

however, it could be argued that *not* having to write duplicated code
in this case is what is nifty/convinient/...


as well, there is another partial way around this problem:
one can implement a dynamic type-system, and then use wrapping and
run-time type-checking for a lot of this. it is a tradeoff (performance
is worse, ...), but it works.

another variant is to use JVM-like "signature strings" which are used
alongside any data, with a lot of the type-specific behavior being
handled by character-driven logic.

both are fairly useful in implementing VMs, and have different merits
and drawbacks. in my case I end up using both strategies in different
situations (well, along with having parts of the typesystem being
essentially driven by queries to a hierarchical database system...).


otherwise, I had developed a much fancier macro preprocessor that can be
used with C (using it to implement such combinatorial/"generic" code was
one thing I had used it for), but I didn't really use it much for a few
reasons:
cases where it was needed were fairly rare;
it is likely that in cases where one feels the need for such a
mechanism, they are likely "doing it wrong" anyways;
it is kind of a build hassle to run code though an additional
preprocessor prior to running it through the main compiler.

worst case, one will copy/paste the logic a few times and specialize it
for each type or situation involved (or keep it in memory, and write out
a specialized version if/when a need for it pops up, so for example
people have the logic for linked-lists/hashes/quicksort/... generally
memorized).


>> it is not that I don't know about OOP or whatever, just that:
>> what I usually want done can be done "well enough" in C explicitly using
>> structs and vtables (so C can still do OOP, sort of);

>
> The major problem in C is not the lack of dynamic binding. It's the
> lack of RAII and templates. (And, to some extent, exceptions.)


RAII normally only really deals with cases which can be dealt with
manually though (apart from exceptions, which also don't exist in C, and
things like longjmp are rarely used).

also, several other major languages, such as Java and C#, also lack RAII
(with exceptions, this behavior is handled by the use of a "finally"
clause).

 
Reply With Quote
 
BGB
Guest
Posts: n/a
 
      08-27-2011
On 8/27/2011 12:32 PM, Noah Roberts wrote:
> On Aug 27, 11:38 am, Juha Nieminen<(E-Mail Removed)> wrote:
>> BGB<(E-Mail Removed)> wrote:
>>> one can also argue that function overloading and operator overloading
>>> are nifty, but rarely have I found this to be a big issue (one can
>>> typically sort-of make due with using short macro names to redirect to
>>> longer operator function names or similar, and with the convention of
>>> using short suffixes to function names to indicate the argument types or
>>> similar...).

>>
>> The reason why function and operator overloading is important is not
>> because it's "handy" or "convenient" or anything like that. It's because
>> it's *necessary* for generic programming. It's what allows you to do
>> things like this:
>>
>> template<typename T>
>> T foo(T value)
>> {
>> std::cout<< "The input value was "<< value<< std::endl;
>> return std::cos(value);
>> }

>
> You don't even need to be doing this to run into the lack of function
> overloading as a great annoyance. I recently started working in a
> project where the lead architect insists it's in C (there are a bunch
> of other things that are more frustrating to me about it than that,
> but whatever). I've found the necessity to think of obscure names to
> make sure to avoid any naming conflicts is a serious quandry. For
> example, in writing a generic stack, vector, or managed string class
> (I have no problem with C OOP, it can be elegant in its own way) you
> have many functions that have a related concept but of course are very
> different in implementation. You could use polymorphism to get by,
> but what if you don't want to use polymorphism? You're quite stuck
> having to name functions like isEmpty to things like
> isNamespaceStackEmpty and isNamespaceStringEmpty, and you're always
> going to be worried that somewhere someone else is naming their stack
> or vector functions the same thing.
>


this is a problem of naming conventions...

for example, a fairly common naming convention is something like:
library_subsystem_function.

so, a person would name things more like:
int MyFooLib_MyContainerStuff_IsHashEmpty()
{
...
}

with "MyFooLib" generally being something a bit more accurate.

now, provided people don't create libraries with the same names, then
there is not a clash.

another convention is:
prefixSomeFunctionName();

where prefix is the short name of a library.
however, this needs to be used a little more sparingly, as the chances
of a 2 to 4 letter prefix or similar clashing are far higher than with a
longer name.


> Luckily the project code is quite small and this isn't anything but a
> minor annoyance, but I can't imagine having to deal with it on a
> larger scale. In C++ these things just work themselves out and they
> work themselves out quite well in a very direct manner that is easy to
> detect errors. There are rules like ADL and more complex rules when
> possible overloads are templates, but they're actually not that hard
> to remember especially for the gain you get from them. Honestly this
> issue has bugged me more than any lack of operator overloads, etc...



with a good naming convention, then code scales well into the Mloc range
without too many issues on this front.

granted, yes, not everyone agrees as to the ideal naming conventions,
and a lot of older code has had problems here (often due to people not
properly qualifying names, simply describing the action or type in a
terse form, and then running into naming conflicts).

 
Reply With Quote
 
Ian Collins
Guest
Posts: n/a
 
      08-27-2011
On 08/28/11 09:37 AM, BGB wrote:
> On 8/27/2011 11:38 AM, Juha Nieminen wrote:
>>
>> The major problem in C is not the lack of dynamic binding. It's the
>> lack of RAII and templates. (And, to some extent, exceptions.)

>
> RAII normally only really deals with cases which can be dealt with
> manually though (apart from exceptions, which also don't exist in C, and
> things like longjmp are rarely used).


The beauty of RAII is you don't have to implement it manually! This
eliminates a whole class of common programming errors.

> also, several other major languages, such as Java and C#, also lack RAII
> (with exceptions, this behavior is handled by the use of a "finally"
> clause).


Yet another manual kludge..

--
Ian Collins
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
2011: Which Ruby books have you read? And which would you recommend? Aston J. Ruby 13 03-16-2011 07:36 AM
Which of these features would you give up in a travel camera RPS Digital Photography 7 08-19-2007 11:07 PM
Which of these features would you give up in a travel camera RPS Digital Photography 14 08-14-2007 10:43 AM
which of these two lense would you get sigma 70-300mm f/4-5.6 Macro or Canon 75-300mm f/4-5.6 III -dad Digital Photography 19 11-09-2006 01:40 AM
Which of these players would you choose? Tony Olmstead DVD Video 3 06-28-2004 07:49 AM



Advertisments