February 24, 2015
On Tue, Feb 24, 2015 at 08:21:53PM +0000, ketmar via Digitalmars-d wrote:
> On Tue, 24 Feb 2015 20:11:17 +0000, weaselcat wrote:
> 
> > On Tuesday, 24 February 2015 at 20:04:27 UTC, Andrei Alexandrescu wrote:
> >> On 2/24/15 12:03 PM, weaselcat wrote:
> >>> On Tuesday, 24 February 2015 at 19:40:35 UTC, Andrei Alexandrescu wrote:
> >>>> ...
> >>>
> >>> Off-topic, sorry Are we still going to get a Trusted block, or just going to use trusted lambdas?(They're kind of ugly TBH)
> >>
> >> We're going to lambdas. Ugliness is a feature.
> > Stroustrup would be proud ;)
> 
> yet he made the whole language ugly, instead of making only ugly things ugly. ;-)

Actually, it's worse than that. He made things that shouldn't be ugly, ugly, and things that *don't* look ugly are outright wrong.

For example, naked pointers have built-in, convenient syntax. They are also extremely dangerous, and almost all C++ code containing raw pointers have bugs one way or another.

For-loops have very nice syntax... except that unless you're writing the most inane, trivial loops, your code probably has bugs -- off-by-1 errors, wrong loop conditions, etc..

Calling malloc/free is also easy... and your program probably has memory leak bugs too. Not to mention type-safety bugs if you're not careful about what you cast that void* into. But hey, writing:

	// Woohoo, bare pointer! Let's dance!
	void *p = malloc(1234);

sure looks prettier than:

	// Repeat after me: Don't repeat yourself... don't repeat
	// yourself... don't repeat yourself...
	MyType *p = (MyType *)malloc(sizeof(MyType));


Well, new/delete is prettier (as far as C++ goes anyway)... But wait, you still have memory leaks.  Augh...

And what about cleaning up resources after you're done with them?

	void func() {
		Resource *res = acquireResource();
		doStuff(res);
		freeResource(res);
	}

Easy, right? Yeah, except that doStuff throws exceptions, so you have resource leakage. Solution? Write a long convoluted wrapper class with a dtor that cleans up. And a copy ctor that makes sure initializing one resource from another works correctly. And operator=() to make sure assignments work correctly. Oh but wait, your ctor is not exception-safe, so better rewrite *that* to use RAII too. Which means more copy ctors, more operator=()... oh wait, your copy ctor is not const-correct so it doesn't get called when you have a const object. Yeah, and your operator=() too. And ...

After it's all said and done, what used to be a 3-line function has exploded into a monstrosity who knows how many lines long, with arcane incantations of auto_ptr<>, shared_ptr<>, and all that fancy stuff that no newbie ever has the hope of parsing, let alone understanding.

	http://bartoszmilewski.com/2013/09/19/edward-chands/

Favorite quote:

	C++ has become an extremely complex language. There are
	countless ways of doing the same thing — almost all of them
	either plain wrong, dangerous, unmaintainable, or all of the
	above. The problem is that most code compiles and even runs. The
	mistakes and shortcomings are discovered much later, often after
	the product has been released.

Yep, that's exactly why D has ruined my life, I just can't go back to that C++ garbage anymore.


T

-- 
Don't throw out the baby with the bathwater. Use your hands...
February 24, 2015
On Tuesday, 24 February 2015 at 19:40:35 UTC, Andrei Alexandrescu wrote:
> I modified Walter's sample code to this: http://dpaste.dzfl.pl/f3d854feede9. It uses malloc for both the array and the reference count, and also uses @trusted minimally. I inserted assert()s here and there to clarify the workings. Nothing big except for the careful use of @trusted.

Doesn't look like it follows the "philosophy behind" @trusted.

Conceptually, you should be able to insert exceptions everywhere outside the called @trusted function and retain memory safety. The way the code is written you have to move outside the @trusted function to prove memory safety.
February 24, 2015
On 2/24/2015 11:55 AM, Steven Schveighoffer wrote:
> Note, you need to GC.addRange all the elements if the type has references, or
> else you cannot have GC pointers in the array.

Yes. I deliberately left that out in order to keep attention focused on the use of 'return ref'.


> Ironically, if those elements are references, but are reference counted
> references, then you wouldn't need to addRange. An interesting problem...

Correct, but (aside from the performance hit) it wouldn't be a bug to scan them unnecessarily in the GC.

One way is to have a scheme whereby, with introspection, a type can be determined to be ref counted. Then, using static if, doing the addRange would only be necessary if:

1. the element type contained indirections
2. those indirections were not ref counted


> I think a system of making sure a piece of data is always destroyed in the same
> thread it was created (unless of course, the thread is gone, in which case it
> doesn't matter), should be fine.

Yup, and I believe this is an orthogonal issue.

February 24, 2015
On Tuesday, 24 February 2015 at 20:46:28 UTC, H. S. Teoh wrote:
> 	http://bartoszmilewski.com/2013/09/19/edward-chands/
I'm not generally one to read comments on blogs, but the replies to that blog are jawdropping.

I have to assume most of these people are either new to C++ or are being forced to write these replies at gunpoint.

>Yep, that's exactly why D has ruined my life, I just can't go back to
that C++ garbage anymore.

Working with C++ after using D does leave one feeling... disillusioned.
February 24, 2015
Andrei Alexandrescu wrote:

> I modified Walter's sample code to this: http://dpaste.dzfl.pl/f3d854feede9. It uses malloc for both the array and the reference count, and also uses @trusted minimally. I inserted assert()s here and there to clarify the workings. Nothing big except for the careful use of @trusted.
> 
> I'll use this as a basis of some exegesis.
> 
> 1. The code is a bit more complicated than it should. Overall this is not a biggie; regular D users are not supposed to write reference counted slices casually. But I was bummed that e.g. I found no way to call emplace() @safe-ly.
> 
> 2. Michel's point (https://issues.dlang.org/show_bug.cgi?id=14221) reveals the largest issue with RC/GC integration. We need to find a fix for it if we want to have the GC lift cycles.
> 
> 3. opIndex ("here's the magic") is the most interesting part of the proposal. It disallows unsafe use such as:
> 
> @safe ref int fun()
> {
>     auto a = RCArray!int([1, 2, 3]);
>     return a[1];
> }
> 
> Nice. I'd go as far as saying that barring implementation bugs, with DIP25 in tow, and after we fix 14221, it's impossible to get an invalid memory access with RCArray in @safe code. This (we offer a way to design @safe arrays and more generally structs that are @safe) is interesting and important.
> 
> That said there is a rub. The part that deallocates memory in the destructor must be @trusted. That is fine, but the trustworthiness of that code depends on the "return" attribute in opIndex. Furthermore, if the author of RCSlice forgets to put "return" there, the compiler won't help - it just allows wrong code like fun() above to compile and run (causing dangling pointer use).
> 
> So: does DIP25 allow safe slices? Looks that way, though a proof would
> be nice. Does it allow other safe interesting structs that own data?
> Very likely. Does it allow really sophisticated ownership schemes? We
> need to explore that. Does it protect against bugs in implementations of
> safe ownership schemes that explicitly release memory? Not too well. I
> think the prevalent idiom will be to accompany such artifacts with
> unittests that make sure unsafe uses (such as fun() above) do not compile.
> 
> 
> Andrei

Is there any plan to allow safe conversions to T[] (in restricted circumstances, of course)?
February 24, 2015
On Tue, Feb 24, 2015 at 09:13:42PM +0000, weaselcat via Digitalmars-d wrote:
> On Tuesday, 24 February 2015 at 20:46:28 UTC, H. S. Teoh wrote:
[...]
> >Yep, that's exactly why D has ruined my life, I just can't go back to
> that C++ garbage anymore.
> 
> Working with C++ after using D does leave one feeling... disillusioned.

That's putting it rather mildly. :-P

Some time ago I revisited one of my old C++ programs, hoping to optimize performance a bit by using a hash table to cache the results of certain expensive computations.  I was somewhat elated that *finally* after all these years hash tables finally made it into the C++ standard... For all their warts, D's AA's have left me confident that this would be a small change...  Boy was I wrong. Everything from the horrible syntax to built-in structs *not* being supported as hash keys by default, to needing to write my own hash function, *and* having to pass it around all over the place, etc.., ...  after several hours of fighting with the language for something that would be just a couple dozen lines of code in D at the most, I threw up my hands and ditched the whole idea.

C++11 feels a lot like "too little, too late" to me. I'd rather rewrite the whole thing in D and spare myself the pain. For all of its current flaws, D is still way ahead of C++ in terms of usability. I've stopped caring about C++ and have not bothered to find out what C++14 (or is it C++15 now?) has in store -- if past experience is anything to go by, it will just be another "too little, too late".


T

-- 
"How are you doing?" "Doing what?"
February 24, 2015
On Tue, 24 Feb 2015 21:13:42 +0000, weaselcat wrote:

> Working with C++ after using D does leave one feeling... disillusioned.

that's why i'm not even considering c++ for writing new code anymore. either D, or good old C, if D is not appropriate.

actually, i haven't written a line of c++ for several years now. and i wrote almost no new C code for years too -- thanks to seampless interop between D and C.

February 24, 2015
On Tuesday, 24 February 2015 at 20:46:28 UTC, H. S. Teoh wrote:
> On Tue, Feb 24, 2015 at 08:21:53PM +0000, ketmar via Digitalmars-d wrote:
>> On Tue, 24 Feb 2015 20:11:17 +0000, weaselcat wrote:
>> 
>> > On Tuesday, 24 February 2015 at 20:04:27 UTC, Andrei Alexandrescu wrote:
>> >> On 2/24/15 12:03 PM, weaselcat wrote:
>> >>> On Tuesday, 24 February 2015 at 19:40:35 UTC, Andrei Alexandrescu
>> >>> wrote:
>> >>>> ...
>> >>>
>> >>> Off-topic, sorry Are we still going to get a Trusted block, or
>> >>> just going to use trusted lambdas?(They're kind of ugly TBH)
>> >>
>> >> We're going to lambdas. Ugliness is a feature.
>> > Stroustrup would be proud ;)
>> 
>> yet he made the whole language ugly, instead of making only ugly
>> things ugly. ;-)
>
> Actually, it's worse than that. He made things that shouldn't be ugly,
> ugly, and things that *don't* look ugly are outright wrong.
>
> For example, naked pointers have built-in, convenient syntax. They are
> also extremely dangerous, and almost all C++ code containing raw
> pointers have bugs one way or another.
>
> For-loops have very nice syntax... except that unless you're writing the
> most inane, trivial loops, your code probably has bugs -- off-by-1
> errors, wrong loop conditions, etc..
>
> Calling malloc/free is also easy... and your program probably has memory
> leak bugs too. Not to mention type-safety bugs if you're not careful
> about what you cast that void* into. But hey, writing:
>
> 	// Woohoo, bare pointer! Let's dance!
> 	void *p = malloc(1234);
>
> sure looks prettier than:
>
> 	// Repeat after me: Don't repeat yourself... don't repeat
> 	// yourself... don't repeat yourself...
> 	MyType *p = (MyType *)malloc(sizeof(MyType));
>
>
> Well, new/delete is prettier (as far as C++ goes anyway)... But wait,
> you still have memory leaks.  Augh...
>
> And what about cleaning up resources after you're done with them?
>
> 	void func() {
> 		Resource *res = acquireResource();
> 		doStuff(res);
> 		freeResource(res);
> 	}
>
> Easy, right? Yeah, except that doStuff throws exceptions, so you have
> resource leakage. Solution? Write a long convoluted wrapper class with a
> dtor that cleans up. And a copy ctor that makes sure initializing one
> resource from another works correctly. And operator=() to make sure
> assignments work correctly. Oh but wait, your ctor is not
> exception-safe, so better rewrite *that* to use RAII too. Which means
> more copy ctors, more operator=()... oh wait, your copy ctor is not
> const-correct so it doesn't get called when you have a const object.
> Yeah, and your operator=() too. And ...
>
> After it's all said and done, what used to be a 3-line function has
> exploded into a monstrosity who knows how many lines long, with arcane
> incantations of auto_ptr<>, shared_ptr<>, and all that fancy stuff that
> no newbie ever has the hope of parsing, let alone understanding.
>
> 	http://bartoszmilewski.com/2013/09/19/edward-chands/
>
> Favorite quote:
>
> 	C++ has become an extremely complex language. There are
> 	countless ways of doing the same thing — almost all of them
> 	either plain wrong, dangerous, unmaintainable, or all of the
> 	above. The problem is that most code compiles and even runs. The
> 	mistakes and shortcomings are discovered much later, often after
> 	the product has been released.
>
> Yep, that's exactly why D has ruined my life, I just can't go back to
> that C++ garbage anymore.
>
>
> T

Almost all those warts are caused by the C compatibility and affect also D to certain extent.

Any language that tries to achieve copy-paste compatibility with C will suffer from it.

--
Paulo
February 24, 2015
On Tuesday, 24 February 2015 at 19:40:35 UTC, Andrei Alexandrescu wrote:
> So: does DIP25 allow safe slices? Looks that way

I believe it does, but at the cost of forced reference counting. As I pointed out, the `ref` solution is not applicable to slices, therefore it needs to return an RCArray. This in turn forces an inc/dec whenever it is sliced or copied, and - maybe worse - it requires all consumers to support RCArray (or whatever other idiosyncratic RC implementation users come up with).
February 24, 2015
On 2/24/15 1:33 PM, Ivan Timokhin wrote:
> Is there any plan to allow safe conversions to T[] (in restricted
> circumstances, of course)?

We'd want to avoid it because that would necessitate the whole "scope" paraphernalia - e.g you can convert a reference counted slice to something like scope(T[]).

A possible option would be to allow the user to go "I want to use GC with this slice from now on" which gives back the T[] and lets the GC take care of it.

But generally I think we should let reference counted slices and built-in slices coexist. Generic range-based code is easy to write so factoring the nature of the slice away may be an option.


Andrei