Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #9326 > unrolled thread
| Started by | "A" <a@a.a> |
|---|---|
| First post | 2011-08-25 23:58 +0200 |
| Last post | 2011-08-26 07:30 -0700 |
| Articles | 11 on this page of 51 — 20 participants |
Back to article view | Back to comp.lang.c++
which of these 3 casts would you prefer? "A" <a@a.a> - 2011-08-25 23:58 +0200
Re: which of these 3 casts would you prefer? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2011-08-25 16:19 -0700
Re: which of these 3 casts would you prefer? Robert Wessel <robertwessel2@yahoo.com> - 2011-08-25 18:59 -0500
Re: which of these 3 casts would you prefer? "Alf P. Steinbach" <alf.p.steinbach:usenet@gmail.com> - 2011-08-26 08:02 +0200
Re: which of these 3 casts would you prefer? "Duga Chernobyl" <duga_c3@gmx.com> - 2011-08-26 10:05 +0200
Re: which of these 3 casts would you prefer? "A" <a@a.a> - 2011-08-26 14:40 +0200
Re: which of these 3 casts would you prefer? Leigh Johnston <leigh@i42.co.uk> - 2011-08-26 13:59 +0100
Re: which of these 3 casts would you prefer? "Duga Chernobyl" <duga_c3@gmx.com> - 2011-08-26 15:19 +0200
Re: which of these 3 casts would you prefer? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2011-08-26 21:27 +0000
Re: which of these 3 casts would you prefer? "Alf P. Steinbach" <alf.p.steinbach:usenet@gmail.com> - 2011-08-27 01:28 +0200
Re: which of these 3 casts would you prefer? "Duga Chernobyl" <duga_c3@gmx.com> - 2011-08-27 10:23 +0200
Re: which of these 3 casts would you prefer? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2011-08-27 12:10 +0000
Re: which of these 3 casts would you prefer? RaZiel <raziel_206_@hotmail.com> - 2011-08-27 21:55 +0200
Re: which of these 3 casts would you prefer? Miles Bader <miles@gnu.org> - 2011-09-01 08:03 +0900
Re: which of these 3 casts would you prefer? BGB <cr88192@hotmail.com> - 2011-08-31 23:11 -0700
Re: which of these 3 casts would you prefer? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2011-09-01 19:34 +0000
Re: which of these 3 casts would you prefer? Joshua Maurice <joshuamaurice@gmail.com> - 2011-09-01 15:37 -0700
Re: which of these 3 casts would you prefer? gwowen <gwowen@gmail.com> - 2011-09-02 00:30 -0700
Re: which of these 3 casts would you prefer? Miles Bader <miles@gnu.org> - 2011-09-03 18:26 +0900
Re: which of these 3 casts would you prefer? Edek <edek.pienkowski@gmail.com> - 2011-08-26 15:29 +0200
Re: which of these 3 casts would you prefer? BGB <cr88192@hotmail.com> - 2011-08-27 09:35 -0700
Re: which of these 3 casts would you prefer? Juha Nieminen <nospam@thanks.invalid> - 2011-08-27 18:38 +0000
Re: which of these 3 casts would you prefer? Noah Roberts <roberts.noah@gmail.com> - 2011-08-27 12:32 -0700
Re: which of these 3 casts would you prefer? BGB <cr88192@hotmail.com> - 2011-08-27 14:51 -0700
Re: which of these 3 casts would you prefer? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2011-08-29 14:10 +0000
Re: which of these 3 casts would you prefer? BGB <cr88192@hotmail.com> - 2011-08-30 07:23 -0700
Re: which of these 3 casts would you prefer? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2011-08-29 11:32 +0000
Re: which of these 3 casts would you prefer? BGB <cr88192@hotmail.com> - 2011-08-27 14:37 -0700
Re: which of these 3 casts would you prefer? Ian Collins <ian-news@hotmail.com> - 2011-08-28 10:06 +1200
Re: which of these 3 casts would you prefer? BGB <cr88192@hotmail.com> - 2011-08-27 15:27 -0700
Re: which of these 3 casts would you prefer? Ian Collins <ian-news@hotmail.com> - 2011-08-28 10:47 +1200
Re: which of these 3 casts would you prefer? Noah Roberts <roberts.noah@gmail.com> - 2011-08-27 15:42 -0700
Re: which of these 3 casts would you prefer? Nobody <nobody@nowhere.com> - 2011-08-28 04:15 +0100
Re: which of these 3 casts would you prefer? Noah Roberts <roberts.noah@gmail.com> - 2011-08-27 15:52 -0700
Re: which of these 3 casts would you prefer? BGB <cr88192@hotmail.com> - 2011-08-28 01:54 -0700
Re: which of these 3 casts would you prefer? Keith H Duggar <duggar@alum.mit.edu> - 2011-09-04 19:16 -0700
Re: which of these 3 casts would you prefer? Juha Nieminen <nospam@thanks.invalid> - 2011-08-29 18:16 +0000
Re: which of these 3 casts would you prefer? Noah Roberts <roberts.noah@gmail.com> - 2011-08-29 16:35 -0700
Re: which of these 3 casts would you prefer? Nobody <nobody@nowhere.com> - 2011-08-30 04:13 +0100
Re: which of these 3 casts would you prefer? Juha Nieminen <nospam@thanks.invalid> - 2011-08-30 06:03 +0000
Re: which of these 3 casts would you prefer? BGB <cr88192@hotmail.com> - 2011-08-30 07:12 -0700
Re: which of these 3 casts would you prefer? Juha Nieminen <nospam@thanks.invalid> - 2011-08-31 06:16 +0000
Re: which of these 3 casts would you prefer? BGB <cr88192@hotmail.com> - 2011-09-01 03:05 -0700
Re: which of these 3 casts would you prefer? Juha Nieminen <nospam@thanks.invalid> - 2011-09-01 07:00 +0000
Re: which of these 3 casts would you prefer? BGB <cr88192@hotmail.com> - 2011-08-31 13:21 -0700
Re: which of these 3 casts would you prefer? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2011-08-28 19:30 +0000
Re: which of these 3 casts would you prefer? Noah Roberts <roberts.noah@gmail.com> - 2011-08-27 12:19 -0700
Re: which of these 3 casts would you prefer? Dombo <dombo@disposable.invalid> - 2011-08-28 12:08 +0200
Re: which of these 3 casts would you prefer? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2011-08-28 19:44 +0000
Re: which of these 3 casts would you prefer? Noah Roberts <roberts.noah@gmail.com> - 2011-08-28 13:41 -0700
Re: which of these 3 casts would you prefer? Anand Hariharan <mailto.anand.hariharan@gmail.com> - 2011-08-26 07:30 -0700
Page 3 of 3 — ← Prev page 1 2 [3]
| From | BGB <cr88192@hotmail.com> |
|---|---|
| Date | 2011-08-30 07:12 -0700 |
| Message-ID | <j3irdi$spq$1@news.albasani.net> |
| In reply to | #9441 |
On 8/29/2011 11:16 AM, Juha Nieminen wrote:
> BGB<cr88192@hotmail.com> 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).
>
> You write as if the lack of RAII was only a minor inconvenience. I don't
> agree with that.
>
> One of the major problems with that lack, which means that resources
> have to be managed manually, is that this management burden is "contagious".
> With that I mean that if you have a type which needs to be destroyed
> manually, that requirement is transferred to any other type that wants
> to use that type as a member. (In other words, if you have eg. a struct
> that needs to be constructed and destructed by explicitly calling some
> functions, if you want to use that struct as a member of another struct,
> you need to write equivalent construction/destruction functions for *that*
> struct too, and the need to manually call them is "inherited" by that
> struct. And so on. It can become quite complicated and burdensome.)
>
well, this comes down to coding style:
most data types of this sort are not allocated/freed directly, but are
allocated/freed via function calls.
say:
FOO_Context *ctx;
ctx=FOO_NewContext(...);
...
FOO_FreeContext(ctx);
however, rarely does this seem like a big deal.
also, the matter of multiple entry/exit points and releasing things also
has a typically straightforward solution:
if for some function it becomes awkward, it means the function is
probably doing too much and needs to be broken down into smaller ones.
typically, 5-25 lines is a good limit for a function size, as well as
the usual practice that a function only does a single conceptual
operation (as opposed to a function which does "this, that, and this
other thing"...).
> It also makes generic programming a lot more difficult. If you make,
> for example, a generic container, you have no way of knowing whether
> the elements need to be properly destroyed before freeing them or not.
> If you want your container to support such elements, you have to offer
> some kind of construction/destruction paradigm, which can be inconvenient,
> and in the case of elements that don't need it, needless overhead.
>
typical answers:
one generally doesn't use generic containers (containers are created on
an as-needed basis);
typically containers are homogenous;
for complex non-uniform data types, typically a vtable and/or a pointer
to a destructor function can be used.
this is again why, as noted before, one memorizes/internalizes things
like hashing, linked lists, and sorting algorithms, as one often needs
to deal with them on a fairly regular basis (one memorizes basic
algorithms much as one memorizes things like lists of API functions, ...).
not that it has to be done in some sort of rote/school style way, but
one tends to memorize things after dealing with them a few times.
>> 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).
>
> This is actually a problem in Java because if you have to manage any
> resource other than memory, you run into the problem of having to free
> the resource manually (at least if the resource should be freed as soon
> as possible; the finalizer mechanism in Java doesn't guarantee when
> destructors will be called, or even that they will be called at all).
>
> The 'finally' block only handles a subset of cases that RAII does, and
> it's nevertheless more burdensome because you have to implement it
> manually. (At least it's safer than anything in C, which is a plus.)
potentially...
but then again, a typical pattern in C becomes:
int BAR_Sub_DoSomething(...)
{
FOO_Context *ctx;
int i;
ctx=FOO_NewContext(...);
...
i=FOO_GetFinalValue(ctx);
FOO_FreeContext(ctx);
return(i);
}
then the form of a function becomes itself a convention.
if success/failure status is involved, typically this is handled either
with "if()" blocks, or folding the next step into its own function (the
use of "goto" is nasty and so typically not done).
in Java, the usual strategy is to introduce ones' own release methods
(rather than trying to rely on finally).
for some data types, it is also common to create ones' own mini
allocator/free system.
public class Foo
{
private static Foo freeList;
private Foo next;
public static final Foo newFoo()
{
Foo tmp;
if(freeList)
{
tmp=freeList;
freeList=tmp.next;
tmp.next=null;
return tmp;
}
tmp=new Foo();
return tmp;
}
public static final void freeFoo(Foo tmp)
{
...
tmp.next=freeList;
freeList=tmp;
}
public void free()
{
freeFoo(this);
}
}
as well as things like:
Foo obj=Foo.newFoo();
try {
...
}finally {
obj.free();
}
because, unlike some people seem to claim, the GC is a good deal more
hit-or-miss in practice when it comes to non-trivial usage patterns (and
GC cycles are not always free).
for my own scripting language, I have a delete keyword (partly itself
inherited from ActionScript, which presumably got it from C++).
however, sadly, at the moment there is no good way to prove that no one
tries to access an object after freeing it (a potential safety/security
concern), but it is a tradeoff (however, like Flash, in my language it
is not required that the VM accept the request to delete something, and
it may potentially reject it in some cases, although at the moment it
will actually just free whatever is given to it provided the code has
the needed permissions).
granted, the addition of VM-level permissions checking (using a
POSIX-style model) was itself a subject of debate (others argued for
sandboxing and trying to make sure that sandboxed code could never get
any references to secure objects, worrying that any sort of security
checking would be too slow/complex/... to be usable).
or such...
[toc] | [prev] | [next] | [standalone]
| From | Juha Nieminen <nospam@thanks.invalid> |
|---|---|
| Date | 2011-08-31 06:16 +0000 |
| Message-ID | <4e5dd1d6$0$4380$7b1e8fa0@news.nbl.fi> |
| In reply to | #9480 |
BGB <cr88192@hotmail.com> wrote: > On 8/29/2011 11:16 AM, Juha Nieminen wrote: >> One of the major problems with that lack, which means that resources >> have to be managed manually, is that this management burden is "contagious". >> With that I mean that if you have a type which needs to be destroyed >> manually, that requirement is transferred to any other type that wants >> to use that type as a member. (In other words, if you have eg. a struct >> that needs to be constructed and destructed by explicitly calling some >> functions, if you want to use that struct as a member of another struct, >> you need to write equivalent construction/destruction functions for *that* >> struct too, and the need to manually call them is "inherited" by that >> struct. And so on. It can become quite complicated and burdensome.) >> > > well, this comes down to coding style: > most data types of this sort are not allocated/freed directly, but are > allocated/freed via function calls. How does that change what I said? It doesn't matter if it's allocated and freed directly or via function calls. (Heck, malloc() and free() *are* function calls.) My point is that this manual construction/destruction requirement is "inherited" by anything that wants to use those types. For example, if you create a new struct that has such a type as a member, this struct will now also have to be constructed/destructed manually, and so on. The language offers no means to automatize and hide this in any way. >> It also makes generic programming a lot more difficult. If you make, >> for example, a generic container, you have no way of knowing whether >> the elements need to be properly destroyed before freeing them or not. >> If you want your container to support such elements, you have to offer >> some kind of construction/destruction paradigm, which can be inconvenient, >> and in the case of elements that don't need it, needless overhead. >> > > typical answers: > one generally doesn't use generic containers (containers are created on > an as-needed basis); > typically containers are homogenous; Containers being homogeneous has nothing to do with genericness. A container being generic means that you can use it with any type, rather than it being fixed to a single hard-coded type, even if the container is homogeneous. Even if the container is hard-coded for one single type, if that type requires construction and destruction, it makes the implementation of the container more complicated and more error-prone. > this is again why, as noted before, one memorizes/internalizes things > like hashing, linked lists, and sorting algorithms, as one often needs > to deal with them on a fairly regular basis (one memorizes basic > algorithms much as one memorizes things like lists of API functions, ...). Having to implement the same algorithms over and over has never been a good programming practice. That's why generic programming is such a great aid in this. > then the form of a function becomes itself a convention. You see, these coding conventions exist solely because of the deficiencies of the language, rather than because they are good programming practices. With RAII they become unneeded, and the resulting code becomes simpler, more straightforward and easier to read.
[toc] | [prev] | [next] | [standalone]
| From | BGB <cr88192@hotmail.com> |
|---|---|
| Date | 2011-09-01 03:05 -0700 |
| Message-ID | <j3mb8b$rcj$1@news.albasani.net> |
| In reply to | #9538 |
On 8/30/2011 11:16 PM, Juha Nieminen wrote:
> BGB<cr88192@hotmail.com> wrote:
>> On 8/29/2011 11:16 AM, Juha Nieminen wrote:
>>> One of the major problems with that lack, which means that resources
>>> have to be managed manually, is that this management burden is "contagious".
>>> With that I mean that if you have a type which needs to be destroyed
>>> manually, that requirement is transferred to any other type that wants
>>> to use that type as a member. (In other words, if you have eg. a struct
>>> that needs to be constructed and destructed by explicitly calling some
>>> functions, if you want to use that struct as a member of another struct,
>>> you need to write equivalent construction/destruction functions for *that*
>>> struct too, and the need to manually call them is "inherited" by that
>>> struct. And so on. It can become quite complicated and burdensome.)
>>>
>>
>> well, this comes down to coding style:
>> most data types of this sort are not allocated/freed directly, but are
>> allocated/freed via function calls.
>
> How does that change what I said? It doesn't matter if it's allocated
> and freed directly or via function calls. (Heck, malloc() and free() *are*
> function calls.)
>
> My point is that this manual construction/destruction requirement is
> "inherited" by anything that wants to use those types. For example, if
> you create a new struct that has such a type as a member, this struct
> will now also have to be constructed/destructed manually, and so on.
> The language offers no means to automatize and hide this in any way.
>
well, when you create the new type / structs and functions, you wrap the
old ones.
so, no big deal, one creates/destroys objects in a similar way,
regardless of how many levels are involved.
alternatively, one can treat them all as the root type by using function
pointers to handle the case of the destruction of subtypes:
struct FOO_SomeType_s {
void *data; //member
void (*deinit)(FOO_SomeType *self);
...
};
then:
void FOO_FreeSomeType(FOO_SomeType *self)
{
if(self->deinit)
self->deinit(self);
free(self);
}
in practice, it is all "not really a big deal".
for added safety though, one can use a garbage collector in place of
malloc/free, and give the GC the ability to call destructors, creating a
mechanism vaguely similar to Java's finalizer system.
>>> It also makes generic programming a lot more difficult. If you make,
>>> for example, a generic container, you have no way of knowing whether
>>> the elements need to be properly destroyed before freeing them or not.
>>> If you want your container to support such elements, you have to offer
>>> some kind of construction/destruction paradigm, which can be inconvenient,
>>> and in the case of elements that don't need it, needless overhead.
>>>
>>
>> typical answers:
>> one generally doesn't use generic containers (containers are created on
>> an as-needed basis);
>> typically containers are homogenous;
>
> Containers being homogeneous has nothing to do with genericness. A container
> being generic means that you can use it with any type, rather than it being
> fixed to a single hard-coded type, even if the container is homogeneous.
>
> Even if the container is hard-coded for one single type, if that type
> requires construction and destruction, it makes the implementation of the
> container more complicated and more error-prone.
>
this seems like hair-splitting IMO.
only one of 2 possibilities exist:
the container is responsible for destroying its contents, in which case
it will do so;
it will not be responsible for doing so, and it will be the
responsibility of the client to destroy all container contents and then
destroy the container.
IMO probably one of the most common "containers" in C is the internally
linked-list (every member points to the next one) in which in the common
case destroying the container and destroying its contents are equivalent.
cur=first;
while(cur)
{
nxt=cur->next;
FOO_FreeFoo(cur);
cur=nxt;
}
>> this is again why, as noted before, one memorizes/internalizes things
>> like hashing, linked lists, and sorting algorithms, as one often needs
>> to deal with them on a fairly regular basis (one memorizes basic
>> algorithms much as one memorizes things like lists of API functions, ...).
>
> Having to implement the same algorithms over and over has never been a
> good programming practice. That's why generic programming is such a great
> aid in this.
>
but, it is common practice, no different from a manual transmission, or
filling out and filing paperwork, ...
like "just do it", "doesn't matter if it is clean or elegant, just make
it work", ...
>> then the form of a function becomes itself a convention.
>
> You see, these coding conventions exist solely because of the deficiencies
> of the language, rather than because they are good programming practices.
> With RAII they become unneeded, and the resulting code becomes simpler,
> more straightforward and easier to read.
well, as noted, it is not C's job to be programmer friendly.
usually, it is used for things like implementing back-end libraries,
often with the front-end application-development done in a different
language, for example: C++, Java, C#, Ruby, Python, Lua, or some other
custom-designed language.
but, one may develop their libraries in C, since it may not be known in
advance which language may need to interface with the library code, and
in most ways C is the least common denominator (and for many types of
library, using C++ will not bring so much benefit internally if the
external API has to be C-like anyways).
[toc] | [prev] | [next] | [standalone]
| From | Juha Nieminen <nospam@thanks.invalid> |
|---|---|
| Date | 2011-09-01 07:00 +0000 |
| Message-ID | <4e5f2d9c$0$2816$7b1e8fa0@news.nbl.fi> |
| In reply to | #9578 |
BGB <cr88192@hotmail.com> wrote: > but, it is common practice, no different from a manual transmission, or > filling out and filing paperwork, ... > > well, as noted, it is not C's job to be programmer friendly. I think these summarize perfectly the kind of mentality that the language produces, and the reason why I hate the language so much. C++ might not be as "programmer friendly" as many other high-level languages, but at least it offers significantly more tools to aid the programmer *without* the compromises of those higher-level languages (such as increased memory consumption or the requirement of a very complex runtime environment and JIT compiler to make the program even acceptably fast, and which often do not exist in most systems, especially the embedded ones.) If someone wants to create big projects in C, even if C++ or other languages would be perfecly good for the job, that's fine. However, when these same people start preaching how the defects of the language are "normal" and "not a big deal", rather than "yeah, it's bad, but you just have to live with it", that's rationalizing.
[toc] | [prev] | [next] | [standalone]
| From | BGB <cr88192@hotmail.com> |
|---|---|
| Date | 2011-08-31 13:21 -0700 |
| Message-ID | <j3nfb6$g6d$1@news.albasani.net> |
| In reply to | #9582 |
On 9/1/2011 12:00 AM, Juha Nieminen wrote: > BGB<cr88192@hotmail.com> wrote: >> but, it is common practice, no different from a manual transmission, or >> filling out and filing paperwork, ... >> >> well, as noted, it is not C's job to be programmer friendly. > > I think these summarize perfectly the kind of mentality that the > language produces, and the reason why I hate the language so much. > > C++ might not be as "programmer friendly" as many other high-level > languages, but at least it offers significantly more tools to aid the > programmer *without* the compromises of those higher-level languages > (such as increased memory consumption or the requirement of a very > complex runtime environment and JIT compiler to make the program even > acceptably fast, and which often do not exist in most systems, especially > the embedded ones.) > yes, well, this is true at least. > If someone wants to create big projects in C, even if C++ or other > languages would be perfecly good for the job, that's fine. However, > when these same people start preaching how the defects of the language > are "normal" and "not a big deal", rather than "yeah, it's bad, but you > just have to live with it", that's rationalizing. I am not entirely sure I see the distinction though. I have never been claiming here that C is as nice/programmer-friendly/... as C++, rather that it is technically usable (absent running into big problems which would render it "technically unusable", as it seemed some others were trying to assert). (examples of things I consider "unusable" would be things like trying to write an OS kernel purely in standard Java and on generic PC-style hardware, but this excludes cases where there is a common and reasonably effective workaround). as noted, I don't actually dislike C++ either, just there are a few cases where it isn't ideal either, and as I see it, a lot of my own code happens to fall into this case. so, it is a tradeoff... one sacrifices some level of niceness, to gain certain other features and capabilities. elsewhere, one can sacrifice some of these capabilities (if they are not useful in a given case), and gain some nice features. I think probably each language has found an effective local minima WRT its costs, but each has different cost-sets. it is much like, there are also cases where ASM is the ideal solution, and other cases where a higher-level script language (such as JavaScript / Python / Lua / ...) are more ideal. if something is used outside of its ideal usage domain, then it is generally perceived as "worse" than whatever is dominant in the area. or such...
[toc] | [prev] | [next] | [standalone]
| From | Jorgen Grahn <grahn+nntp@snipabacken.se> |
|---|---|
| Date | 2011-08-28 19:30 +0000 |
| Message-ID | <slrnj5l5qe.gtj.grahn+nntp@frailea.sa.invalid> |
| In reply to | #9362 |
On Sat, 2011-08-27, Juha Nieminen wrote: > BGB <cr88192@hotmail.com> 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. Well, I think the handiness and convenience are important, too. When I use C, one of the things I hate the most is coming up with different names for (for example) is_empty(const Foo*) and is_empty(Bar*). It really hurts readability. For example, a C application I work on contains half a dozen linked list types. They're implemented as just one List_t type, with void* as values, and we have to write down /as comments/ what type the List_t is supposed to contain. I could easily write half a dozen type-safe wrapper structs with associated next/prev/clear etc operations ... but the operation names would be too long to be manageable. They would be Subsystem_List_of_FooBar_next() Subsystem_List_of_FooBar_prev() Subsystem_List_of_FooBar_clear() and my coworkers would find using those /more/ painful than the current lack of typing. And they would probably be right. /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o .
[toc] | [prev] | [next] | [standalone]
| From | Noah Roberts <roberts.noah@gmail.com> |
|---|---|
| Date | 2011-08-27 12:19 -0700 |
| Message-ID | <77f9fdd1-300b-4049-af43-52622f0c3575@x11g2000prk.googlegroups.com> |
| In reply to | #9333 |
On Aug 26, 5:40 am, "A" <a...@a.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?
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.
[toc] | [prev] | [next] | [standalone]
| From | Dombo <dombo@disposable.invalid> |
|---|---|
| Date | 2011-08-28 12:08 +0200 |
| Message-ID | <4e5a139d$0$30711$5fc3050@news.tiscali.nl> |
| In reply to | #9363 |
Op 27-Aug-11 21:19, Noah Roberts schreef: > 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. Though I agree with most of what you say here (and your story is all to familiar to me), personally I prefer to avoid to having to use casts in the first place. When I see code with a lot of casts I tend to get nervous. Though C++ style casts are much more precise, I still get worried when I see many of them. If casts cannot be avoided (which sometimes is the case) the C++ style casts are to be preferred for the reasons stated in this thread.
[toc] | [prev] | [next] | [standalone]
| From | Jorgen Grahn <grahn+nntp@snipabacken.se> |
|---|---|
| Date | 2011-08-28 19:44 +0000 |
| Message-ID | <slrnj5l6kc.gtj.grahn+nntp@frailea.sa.invalid> |
| In reply to | #9363 |
On Sat, 2011-08-27, Noah Roberts wrote:
> On Aug 26, 5:40 am, "A" <a...@a.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?
>
> 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
[snip excellent thedailywtf.com material]
Sometimes I wonder if the critics aren't right after all -- that C++
is too complicated for its users to understand. But then so is any
other language, damn it!
/Jorgen
PS. Interesting spelling of "hierarchy". Still unsure if its
intentional ;-)
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
[toc] | [prev] | [next] | [standalone]
| From | Noah Roberts <roberts.noah@gmail.com> |
|---|---|
| Date | 2011-08-28 13:41 -0700 |
| Message-ID | <45c702d0-ae3c-4618-9152-0b476301a38f@b9g2000prd.googlegroups.com> |
| In reply to | #9413 |
On Aug 28, 12:44 pm, Jorgen Grahn <grahn+n...@snipabacken.se> wrote: > On Sat, 2011-08-27, Noah Roberts wrote: > > On Aug 26, 5:40 am, "A" <a...@a.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? > > > 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 > > [snip excellent thedailywtf.com material] > > Sometimes I wonder if the critics aren't right after all -- that C++ > is too complicated for its users to understand. But then so is any > other language, damn it! Perhaps C++ puts too much power in the hands of people who can't use it responsibly, but I think also that there are many people who will just write crap code no matter what language they're using. I mean, the person in question actually told me that, "The document/view architecture is considered outdated," when I suggested we NOT mix business and UI code into the same classes. Using Java or C# or some other supposedly "easy" language would not have made his code any better, it only perhaps would have lessened some of the consequences regarding poor casting. Even then though, I seriously doubt it would have made any difference. I'm currently working with someone who seems to think globals are the best thing since sliced bread and is actually AGAINST factoring them out of functions that could easily work with parameters instead. This time the language is C, which is supposedly "simpler" than C++ (which again seems to be hated). Put such a developer in "simple", weakly- typed language or something and he'll do the same thing...it just doesn't matter. In fact in many cases it may get much worse because now they're not limited to multiple uses of the same type when multi- purposing a global variable...they can use it as a string here and a double over there. The casts that C++ offers introduce a small safety against some of what can happen when people do bad things, which EVERYONE does. The C style casts just are not equipped for the introduction of things that C ++ adds to C, like multiple-inheritance and stronger typing. They won't fix broken coders though and I really don't think that C++ is to blame for the kinds of poor approaches I've seen in the industry, with surprising frequency and at surprisingly high levels of authority. A good language might protect you from making basic mistakes in grammar or semantics, but if your statements are nonsense to begin with then no amount of simplicity is going to create sense of them.
[toc] | [prev] | [next] | [standalone]
| From | Anand Hariharan <mailto.anand.hariharan@gmail.com> |
|---|---|
| Date | 2011-08-26 07:30 -0700 |
| Message-ID | <849a55ff-43e2-4f8c-ad5e-826044ae6a01@g9g2000yqb.googlegroups.com> |
| In reply to | #9331 |
On Aug 26, 3:05 am, "Duga Chernobyl" <duga...@gmx.com> wrote:
> Dnia 25-08-2011 o 23:58:56 A <a...@a.a> napisał(a):
>
> > int Callback(void *pThis)
> > {
> > TMyClass *pMC = (TMyClass*)pThis; // C style
>
(...)
> The first is used in c and should be used only in C.
The cast is not needed in C.
- Anand
[toc] | [prev] | [standalone]
Page 3 of 3 — ← Prev page 1 2 [3]
Back to top | Article view | comp.lang.c++
csiph-web