D - more or less power than C++?
Kevin Bealer
Kevin_member at pathlink.com
Sat Mar 4 02:51:49 PST 2006
In article <dubckj$1e4$1 at digitaldaemon.com>, Walter Bright says...
>
>
>"Kevin Bealer" <Kevin_member at pathlink.com> wrote in message
>news:dub5c4$2lo2$1 at digitaldaemon.com...
>> Constructors and destructors in C++ have become something much larger than
>> memory cleanup. They provide a syntactic tool that plays almost the same
>> role
>> as (and complements well with) assertions and contract programming.
>>
>> For instance, in C++ I can write a mutex class like this (I'll use D
>> notation):
>>
>> class Mutex {
>> , void Lock();
>> , void Unlock();
>> , bool is_Locked();
>> };
>>
>> ,class MutexHolder {
>> , this(Mutex x);
>> ,
>> , void Lock() { assert(! am_locked); x.Lock(); am_locked = true; }
>> , void Unlock() { assert(am_locked); x.Unlock(); am_locked = false; }
>> ,
>> , ~this()
>> , {
>> , if (am_locked) {
>> , assert(my_x.isLocked());
>> , my_x.Unlock();
>> , }
>> , }
>> ,}
>>
>> If you insert enough assert() tests, you can virtually guarantee that you
>> either
>> have perfect locking, or die (or hang) at the point of the first usage
>> error.
>>
>> But the ability to check for correct state, or unlock things, in the
>> destructor
>> is CRUCIAL to this kind of testing. I worked for a few years in C
>> language file
>> system code that did not have these guarantees. We were constantly
>> hunting down
>> mysterious hangs. Doing locking via object lifetime is an excellent way
>> to
>> enforce a kind of whole-system behavior -- that is what's powerful.
>>
>> But D can't do this kind of thing, AFAIK. The RIIA works for a class, but
>> I
>> can't nest classes this way. I can't tell class Foo that it owns Bar in
>> "auto"
>> mode. I suspect that this would interact badly with "dup" if it was
>> implemented. I'm not sure what to do about that, unless there is an
>> "opDup()"
>> method (I like this idea, but its another been-discussed idea.).
>
>Is it really necessary to tell the compiler you own a class member, rather
>than doing it by convention?
Maybe not necessary... particularly with on_scope_exit() etc. It's so useful in
C++ relative to C. That said, it maybe partly just due to my expectations.
I think it boils down to this - in C++ the lifetime of objects can be
influenced by other objects, and as part of algorithms. And
algorithms and code can be influenced by the lifetime of objects. In
D the lifetime of objects is influenced by code, but not the other way
around.
Maybe this is just the cost of GC. It seems like both methods could coexist,
but if enough features are added to D it will weigh as much as C++. I'll have
to think about whether there are other cases that auto/on_scope can't do.
>> If you write a class in C++ to wrap an integer for some reason,
>> its only 4 bytes.
>
>So it is with a D struct.
>
>> You can replace a set of integers (this is usually done if you have at
>> least a
>> pair of ints) with "managed" ints or int-pairs, that guarantee some
>> property.
>> If the guarantee is done via debug-mode-only testing, the class really
>> does turn
>> into primitive types in release mode.
>
>debug
>{ struct myint
> {
> ... management code ...
> }
>}
>else
>{
> alias int myint;
>}
I guess what I'm saying is that in C++ you have incremental power over the
functionality. If you want a virtual table but no operators, you can have it.
Operators but no virtual table, okay. Each feature is turned on seperately. In
D there is struct, which has some stuff, and class, which has everything and a
very different personality.
This is starting to sound like a complaint, but actually I like D's way. All
that syntax is why C++ is so treacherous for anyone who doesn't have a law
degree in it. The first ten times you write operator=(), you need to look at
the book. But C++'s a-la carte is powerful, if you want to spend time crafting
the classes. It's a tradeoff. D makes a lot of common sense tradeoffs. In C++
you can build uncopyable classes, inherit from classes that have no code (i.e.
traits programming) etc. D tosses a lot of semi-obscure flexibility and lets
some of it in through other doors. Again, good decision, but there are small
ramifications here and there.
I'll just force myself to stop typing now. ;)
>> Unfortunately, if I have a container of D structs, getting one out and
>> calling a
>> method, copies the value out - I can't set fields via "container[i].x =
>> 5;" the
>> last time I checked.
>
>Can you post an example of this?
Yes. As I mentioned elsewhere, "foo * opIndex(int i)" fixes this.
struct foo {
| int x = 0;
| int y = 0;
|
| int set_x(int q)
| {
| x = q;
| return x;
| }
};
struct holds_foo {
| foo[] foos;
|
| // this one fails.
| foo opIndex(int i)
| {
| return foos[i];
| }
|
| /+ This one works here.
| foo * opIndex(int i)
| {
| return & foos[i];
| }+/
};
int floo()
{
| holds_foo hoho;
| hoho.foos.length = 10;
|
| hoho[0].set_x(11);
|
| printf("ho ho %d.\n", hoho[0].x);
|
| return 0;
}
int main(char[][] args)
{
| printf("okay then\n");
|
| floo();
|
| printf("okay now\n");
|
| return 0;
}
>> I'm also thinking there is one restriction that may make this easier - if
>> the
>> auto class could only be owned by a function scope (as currently) OR
>> another
>> auto class - this would fix the unknown-delete-order issue for auto
>> classes,
>> because it would mean that every auto class knew it was not garbage (and
>> inductively, its children arent garbage) at destruct time.
>
>I'll have to think about that.
>
>
More information about the Digitalmars-d
mailing list