January 26, 2013
On Fri, Jan 25, 2013 at 11:32:19PM +0100, Szymon wrote:
> Ah, perfectly clear now. Thanks guys. At one point I though maybe it was about move semantics but it indeed about something much more fundamental. And indeed surprising coming from C++.
[...]

When moving to D, one thing to keep in mind is that you should not expect C/C++ struct and D struct to behave the same way, because they do not.

In D, a struct is a value type, and basically behaves like a glorified int. This means assignment with = (shallow-)copies the struct, structs are allocated on the stack by default (unless you explicitly use new), etc.. Be aware that using struct ctors/dtors is fraught with peril; the simplest cases do work, but there are some bugs with complicated dtors and some unexpected behaviour with @disable ctors. If you need a complicated dtor, chances are you want to be using a class anyway. Same goes for postblit ctors (the analogue of copy ctors): there are some bugs related to this, and IMO, if you need to do complicated stuff in a postblit, you should just use a class.

In D, a class is a reference type, which means they are always passed by reference, and assignment with = only copies the reference, NOT the object. By default, they are allocated on the heap (unless you use emplace), and generally, ctors and dtors work in a much more predictable and stable way. (But be aware that dtors may not run when you expect, because the GC may not collect the object immediately after it's out of use.) Class objects are not deep-copied unless you provide a method to do that yourself.

In summary, if you want something that behaves like an int, but just happens to have a couple of extra fields, use a struct. If you want complex behaviours like ctors, dtors, copy/cloning semantics, polymorphism, etc., spare yourself the pain and just use a class. (It *is* possible to pull some tricks along these lines with structs, but like I said, there is a risk of running into some bugs in that area, so it's best to steer clear until these issues have been fixed.)


T

-- 
"I suspect the best way to deal with procrastination is to put off the procrastination itself until later. I've been meaning to try this, but haven't gotten around to it yet. " -- swr
January 26, 2013
On Fri, Jan 25, 2013 at 02:53:31PM -0800, Walter Bright wrote: [...]
> If you stick to bread and butter code, you shouldn't have problems. If you use advanced features out to the edge, you're more likely to run into issues.

And I have to add that so far, I haven't found any problems that are showstoppers (in the sense that there's no way to work around it). Almost all of the bugs I've found have workarounds that aren't too painful. (They may look a bit ugly at times, but they work, and let you get the job done.)

Even with advanced features, when you run into bugs it's almost always possible to recast your code in a way that *doesn't* use that specific combination of advanced features that exhibit the bug. You may not be able to write idealistic, perfect code in that case, but things will still work.


[...]
> >Is it true that D has GC problems?
> 
> All GC's have problems. GC isn't a "fire and forget" way to deal with memory management. However, the GC is reliable and works well if you use it with awareness of how it works.
[...]

I have to say that while the current GC certainly could do with some significant improvements, *I've* certainly never run into any major problems with it yet.

There have been reports of performance loss in some cases, but there are ways to disable/re-enable the GC which you can use to minimize the problem around critical pieces of code.

In any case, the GC *is* being worked on, and hopefully we'll see a much better incarnation of it in the near future.

(Not to mention that having a GC makes it much easier to write certain kinds of code. Complex string manipulations, for example, are an utter pain in the neck in C/C++. The simplest operations require meticulous care and copious tricky pointer arithmetics to prevent buffer overflows and memory leaks. In D, you just write string operations with impunity and they Just Work(tm). And the resulting code is much more readable.)


T

-- 
Your inconsistency is the only consistent thing about you! -- KD
January 26, 2013
> We better get this right and not hurry about this.

I will open a new, separate thread about this tomorrow. Seems to me more appropriate. Then we can discuss about this important but missing feature in detail.

> What languages have that feature, and what makes it important? To me it seems rather niche and is easily worked around within the language.
>
>
> Andrei

Sorry I was tired and had misunderstood the relation to D problems which keep you back from using it in production. I will write a few sentences about this tomorrow.
January 26, 2013
On Friday, 25 January 2013 at 21:33:15 UTC, q66 wrote:
>> D's GC does not have serious problems. The only issue is controversial status of GC.
>>
>
> D's GC has inherent issues with false positives, sometimes freeing memory that you don't really want freed, causing (sometimes hidden) bugs that are pretty much impossible to debug.

That is very wrong. False positive are the exact opposite : memory that isn't freed.

And it statistically never occurs on 64 bits systems.
January 26, 2013
On Friday, 25 January 2013 at 23:02:10 UTC, Walter Bright wrote:
> On 1/25/2013 1:33 PM, q66 wrote:
>> D's GC has inherent issues with false positives, sometimes freeing memory that
>> you don't really want freed, causing (sometimes hidden) bugs that are pretty
>> much impossible to debug.
>
> There are zero reported examples of this happening.
>

I had an issue like like in D < 2.061 .
January 26, 2013
Walter Bright wrote:

> Yes, and it is in use for production code.

What do you mean by this statement?

Do those companies publish their reliance on D?

How many people make there living on "production code" written in D with a time perspective of at least five years?

-manfred
January 26, 2013
26-Jan-2013 04:42, H. S. Teoh пишет:
> On Fri, Jan 25, 2013 at 11:32:19PM +0100, Szymon wrote:
>> Ah, perfectly clear now. Thanks guys. At one point I though maybe it
>> was about move semantics but it indeed about something much more
>> fundamental. And indeed surprising coming from C++.
> [...]
>
> When moving to D, one thing to keep in mind is that you should not
> expect C/C++ struct and D struct to behave the same way, because they do
> not.
>
> In D, a struct is a value type, and basically behaves like a glorified
> int. This means assignment with = (shallow-)copies the struct, structs
> are allocated on the stack by default (unless you explicitly use new),
> etc.. Be aware that using struct ctors/dtors is fraught with peril; the
> simplest cases do work, but there are some bugs with complicated dtors
> and some unexpected behaviour with @disable ctors. If you need a
> complicated dtor, chances are you want to be using a class anyway. Same
> goes for postblit ctors (the analogue of copy ctors): there are some
> bugs related to this, and IMO, if you need to do complicated stuff in a
> postblit, you should just use a class.

In general postblit/dtor are working but I wouldn't recommend using them in complex code (least you want to file a bug report) like with statements, or array-literals [ Struct(...), Struct(...), Struct(...)], and of course built-in associative arrays(!).

Another thing of importance is that pass-by-value is automated to move (simple bitwise-copy) where applicable as D structs can't have internal references. And you don't have to define move constructor or rely on sombody to define it.

>
> In D, a class is a reference type, which means they are always passed by
> reference, and assignment with = only copies the reference, NOT the
> object. By default, they are allocated on the heap (unless you use
> emplace), and generally, ctors and dtors work in a much more predictable
> and stable way. (But be aware that dtors may not run when you expect,
> because the GC may not collect the object immediately after it's out of
> use.) Class objects are not deep-copied unless you provide a method to
> do that yourself.
>
> In summary, if you want something that behaves like an int, but just
> happens to have a couple of extra fields, use a struct. If you want
> complex behaviours like ctors, dtors, copy/cloning semantics,
> polymorphism, etc., spare yourself the pain and just use a class. (It
> *is* possible to pull some tricks along these lines with structs, but
> like I said, there is a risk of running into some bugs in that area, so
> it's best to steer clear until these issues have been fixed.)
>
>
> T
>


-- 
Dmitry Olshansky
January 26, 2013
26-Jan-2013 03:48, Rob T пишет:
> On Friday, 25 January 2013 at 22:29:44 UTC, Adam D. Ruppe wrote:
>> On Friday, 25 January 2013 at 22:22:44 UTC, Szymon wrote:
>>> So structs in D are always passed by-value? That is unfortunate...
>>
>> It has both pointers and ref but they both only work with lvalues,
>> regardless of const:
>>
>> struct S {}
>>
>> void test(const ref S s) {}
>> void test2(const S* s) {}
>>
>> S getS() { return S(); }
>>
>> void main() {
>>         S s;
>>         test(s); // ok
>>         test2(&s); // ok
>>         test(getS()); // not ok (line 12)
>>         test2(&getS()); // not ok (line 13)
>> }
>>
>> test.d(12): Error: function test.test (ref const(S) s) is not callable
>> using argument types (S)
>> test.d(12): Error: getS() is not an lvalue
>> test.d(13): Error: getS() is not an lvalue
>
> It should be mentioned that there's a solution of sorts, but it is a
> pain to have to do and does not scale up when you have multiple ref
> arguments.
>
> void test(const ref S s)
> {
>     // implementation
>     ...
>     return;
> }
> void test(const S s)
> {
>      test( s ); // calls test(const ref S s)
>      return;
> }

void test(const S s){ return test(s); }

D is not Java and allows returning void functions directly ;)


-- 
Dmitry Olshansky
January 26, 2013
On Friday, 25 January 2013 at 23:24:54 UTC, Andrei Alexandrescu wrote:

> Thank you for asking. We have been strongly focused on quality improvement since last year but judging from this thread we need to work more on it (and the derived community sentiment).
>
> Andrei

And that is true, during 2012 and by now 1495 bug fixed and closed:

http://d.puremagic.com/issues/buglist.cgi?chfieldto=Now&query_format=advanced&chfield=bug_status&chfieldfrom=2012-01-01&bug_status=RESOLVED&bug_status=VERIFIED&bug_status=CLOSED&component=DMD&product=D

That is just so Awesome! Great thanks to everybody involved!

The bad news is there are still some TDPL bugs:

http://d.puremagic.com/issues/buglist.cgi?keywords=tdpl&query_format=advanced&keywords_type=allwords&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&component=DMD&product=D

These probably would require more attention because TDPL is the _only_ printed
source of the language.
Not so big amount although, so using D per TDPL looks pretty safe.

Oleg.
January 26, 2013
Am Fri, 25 Jan 2013 22:38:51 +0100
schrieb "Jonathan M Davis" <jmdavisProg@gmx.com>:

> On Friday, January 25, 2013 22:33:14 q66 wrote:
> > > D's GC does not have serious problems. The only issue is controversial status of GC.
> > 
> > D's GC has inherent issues with false positives, sometimes freeing memory that you don't really want freed, causing (sometimes hidden) bugs that are pretty much impossible to debug.
> 
> I've _never_ heard of it freeing something when it shouldn't.

I've seen that when porting GDC. Usually happens if the GC fails to scan the stack or more often it misses some TLS ranges. Never saw that with dmd though.

IIRC toStringz is also dangerous. You have to make sure that the C library does not store the pointer or also store it manually so the GC can find it. (This is not different from passing other C/D pointers, but with toStringz it's easy to miss).