April 19, 2014
On Saturday, 19 April 2014 at 05:08:06 UTC, froglegs wrote:
>
>> Also possible in C# with structs, interop annotations and unsafe blocks.
>
>  And now you aren't using the language, but a (very) poor subset of a language that doesn't even support templates.
>

Doesn't change the fact it is possible, but hey lets sell C++ agenda.

>
>>> C++ exposes SSE/AVX intrinsics, C# does not.
>>
>> That is not correct.
>>
>> 1 - Nowhere in the ANSI/ISO C++ are SSE/AVX intrinsics defined, those are compiler extensions. So equal foot with the C# EMCA standard;
>
>  Duh, but every C++ compiler exposes this, so it is defacto standard. C++ has plenty of non-standard standards, such as #pragma once.
>
>
>> 3 - .NET Native and RyuJIT have official support for SIMD instructions, GPGPU support is also planned
>
>   I see on MS website an article about having a vector data type. While interesting that isn't the same as exposing the actual instructions, which will limit potential gains.
>
>  The aricle http://blogs.msdn.com/b/dotnet/archive/2014/04/07/the-jit-finally-proposed-jit-and-simd-are-getting-married.aspx
>
>
>  Additionally .NET native will be MS only--

Except it already exists today with Mono. Microsoft is just making the official .NET do something, Xamarin has been doing the last years already, both in static native compilation and SIMD support.

Any language can expose SIMD instructions, there is nothing special about them in C++, because like every other language, they are compiler extensions. Regardless of being a defacto standard or not.

If I take the C# side on this, even though I also like C++, is because we are in a D forum, and having a C# native toolchain will certanly help young developers understand we don't need VMs for memory safe systems programming languages.

Oberon compilers in the mid-90's were producing code that was as good as C compilers back then. On those days I still wrote a couple applications 100% in Assembly.

I think many value too much C and C++ compilers, because they forget how long they have been around, and also never used alternative system programming languages back when C and C++ compilers used to suck.


--
Paulo
April 19, 2014
On Thursday, 17 April 2014 at 22:04:17 UTC, Walter Bright wrote:
> On 4/17/2014 1:03 PM, John Colvin wrote:
>> E.g. you can implement some complicated function foo that writes to a
>> user-provided output range and guarantee that all GC usage is in the control of
>> the caller and his output range.
>
> As mentioned elsewhere here, it's easy enough to do a unit test for this.

Erm, no? You can possibly track GC calls by using custom druntime fork but you can't track origins of such calls in source tree without compiler help.

I hope Don's DConf talk will convince you how useful enforcing such model is ;)

>> The advantage of having this as language instead of documentation is the
>> turtles-all-the-way-down principle: if some function deep inside the call chain
>> under foo decides to use a GC buffer then it's a compile-time-error.
>
> And that's how @nogc works.

And it is not good enough for practical reasons, i.e. we won't be able to use @nogc for most of the Phobos.
April 19, 2014
On 2014-04-18 23:48:43 +0000, Walter Bright <newshound2@digitalmars.com> said:

> On 4/18/2014 3:02 PM, Michel Fortin wrote:
>> Objective-C enables ARC by default for all pointers to Objective-C objects.
>> Since virtually all Objective-C APIs deal with Objective-C objects (or integral
>> values), if you limit yourself to Objective-C APIs you're pretty much memory-safe.
> 
> "pretty much" isn't really what we're trying to achieve with @safe.

A lot of D code is memory safe too, but not all. Is D memory-safe? Yes, if you limit yourself to the @safe subset (and avoid the few holes remaining in it). Same thing for Objective-C: there exists a subset of the language that is memory safe, and pretty much everyone limit itself to that subset already, unless there's a reason to go lower-level and use C.

In other words, unmanaged pointers are the assembler of Objective-C. It's unsafe and error prone, but it lets you optimize things when the need arise.


>> The point being, D could have managed and unmanaged pointers (like Objective-C
>> with ARC has), make managed pointers the default, and let people escape pointer
>> management if they want to inside @system/@trusted functions.
> 
> Yeah, it could, and the design of D has tried really hard to avoid such. "Managed C++" was a colossal failure.
> 
> I've dealt with systems with multiple pointer types before (16 bit X86) and I was really, really happy to leave that **** behind.

Yet, there's C++ and its proliferation of library-implemented managed pointer types (shared_ptr, unique_ptr, weak_ptr, scoped_ptr, and various equivalents in libraries). Whether they're a success or a patch for shortcomings in the language, they're used everywhere despite the various mutually incompatible forms and being all leaky and arcane to use.

And if I'm not mistaken, this is where the @nogc subset of D is headed. Already, and with good reason, people are suggesting using library managed pointers (such as RefCounted) as a substitute to raw pointers in @nogc code. That doesn't automatically make @nogc a failure — C++ is a success after all — but it shows that you can't live in a modern world without managed pointers. If multiple pointer types really dooms a language (your theory) then the @nogc D subset is doomed too.

Yet, ARC-managed pointers are a huge success in Objective-C. I think the trick is to not bother people with various pointer types in regular code. Just make sure the default pointer type works everywhere in higher-level code, and then provide clear ways to escape that management and work at a lower level when you need to optimize a function or interface with external C code.

D thrives with raw pointers only because its GC implementation happens to manage raw pointers. That's a brillant idea that makes things simpler, but this also compromises performance at other levels. I don't think there is a way out of that performance issue keeping raw pointers the default, even though I'd like to be proven wrong.

-- 
Michel Fortin
michel.fortin@michelf.ca
http://michelf.ca

April 19, 2014
On Saturday, 19 April 2014 at 10:07:46 UTC, Jacob Carlborg wrote:
> On 2014-04-18 18:17, Brad Anderson wrote:
>
>> Problems like how toUpperInPlace would still allocate (with
>> gusto) could much more easily be recognized and fixed with @nogc available.
>
> toUpperInPlace should be removed.

Nonsense. It still works 99% of the time (I think only a subset of 100 letters in all of Unicode are affect, and even then, another 100 of them *shrink* on toUpper). It is really useful. It avoids *needles* allocations. Removing it would be more harmful than useful.

I'm pretty confident that most of the time it is used, people don't care *that* much that *absolutely* no allocation takes place. They just don't want to be wasteful.

> It cannot work reliable in place.

Rename "toUpperMaybeInPlace".

Then, for those that absolutely *can't* allocate provide a better interface. For example:
`void toUpper(S, O)(S s, ref O o);`

Burden on the caller to make it "inplace" from that (or to allocate accordingly when inplace is not possible).
April 19, 2014
On Saturday, 19 April 2014 at 11:21:05 UTC, Tobias Pankrath wrote:
> On Saturday, 19 April 2014 at 10:31:28 UTC, Jacob Carlborg wrote:
>> On 2014-04-19 12:21, bearophile wrote:
>>
>>> Better to move it in std.ascii instead of removing it.
>>
>> The current implementation works with more characters than ASCII.
>
> Or replace characters whose upper case representation is bigger than the lower case representation with U+FFFD or similar.

Replacing a character with FFFD is only acceptable if it was invalid to begin with. Doing it because it's convenient is not acceptable.
April 19, 2014
On Saturday, 19 April 2014 at 13:34:13 UTC, Michel Fortin wrote:
> Yet, ARC-managed pointers are a huge success in Objective-C. I think the trick is to not bother people with various pointer types in regular code.

But you have to take the following into account:

1. Objective-C has a separate type for RC objects (although you have a toll-free bridge for some of CF).

2. Objective-C started out with inefficient manual RC, then required some restrictions on that when introducing ARC that removed some overhead, so the ARC overhead is less noticable.

ARC isn't trivial to implement:

http://clang.llvm.org/docs/AutomaticReferenceCounting.html

> D thrives with raw pointers only because its GC implementation happens to manage raw pointers. That's a brillant idea that makes things simpler, but this also compromises performance at other levels. I don't think there is a way out of that performance issue keeping raw pointers the default, even though I'd like to be proven wrong.

Depends on how you look at it. GC does not really have a horrible performance issue, it has a terrible latency issue.

If you can put everything that is latency sensitive into separate units then having background collection isn't all that bad. That is ok if you only read from the GC heap in the real time and write into non-GC buffers in real time (or have a backdoor into the GC heap during collection).

If you can establish isolates of some sort (with multiple threads), then you can segment GC and reduce latency.

If you take a graph that is 100% immutable, then you can GC-handle that graph as a single object. So, if you get semantics for "freezing" graphs (conversion to immutable) then you probably can cut down on collection time too. As the gap between memory bus speed and memory capacity increases, then more an more memory will stay "mostly untouched". There is obviously opportunities for optimizing a GC for that, but you need the right semantics. Semantics beyond const-types.

Surely, you can have both GC, and acceptable performance. I agree with Paulo Pinto on that point. But not with C-like semantics.
April 19, 2014
On 4/19/2014 3:10 AM, Jacob Carlborg wrote:
> On 2014-04-18 22:25, Walter Bright wrote:
>
>> dmd could do a better job of escape analysis, and do this automatically.
>
> That would be really nice. Is this long hanging fruit or does it require a lot
> of work?

It requires a decent working knowledge of data flow analysis techniques, and some concentrated effort.

April 19, 2014
On 4/19/2014 6:14 AM, Dicebot wrote:
> On Thursday, 17 April 2014 at 22:04:17 UTC, Walter Bright wrote:
>> On 4/17/2014 1:03 PM, John Colvin wrote:
>>> E.g. you can implement some complicated function foo that writes to a
>>> user-provided output range and guarantee that all GC usage is in the control of
>>> the caller and his output range.
>>
>> As mentioned elsewhere here, it's easy enough to do a unit test for this.
>
> Erm, no? You can possibly track GC calls by using custom druntime fork but you
> can't track origins of such calls in source tree without compiler help.

@nogc is there to help.


>>> The advantage of having this as language instead of documentation is the
>>> turtles-all-the-way-down principle: if some function deep inside the call chain
>>> under foo decides to use a GC buffer then it's a compile-time-error.
>>
>> And that's how @nogc works.
>
> And it is not good enough for practical reasons, i.e. we won't be able to use
> @nogc for most of the Phobos.

The first step is to identify the parts of Phobos that unnecessarily use the GC. @nogc will help a lot with this.
April 19, 2014
On Saturday, 19 April 2014 at 17:41:58 UTC, Walter Bright wrote:
> The first step is to identify the parts of Phobos that unnecessarily use the GC. @nogc will help a lot with this.

Unless I missed it, I think we still haven't answered the issue with throwing exceptions. I'm in particular interested in asserts and Errors.

Will "assert" be usable in @nogc code? Because if not, then basically *none* of phobos will be @nogc.

Also, I don't think statically pre-allocating the error is an acceptable workaround.

EG:

assert(arr.length, "arr is empty.");

vs

version (assert)
{
    static Error e = new Error("arr is empty.");
    if (!arr.length) throw e;
}
April 19, 2014
On Saturday, 19 April 2014 at 17:51:38 UTC, monarch_dodra wrote:
> Also, I don't think statically pre-allocating the error is an acceptable workaround.

Just in case that's not clear, I mean for the generic "assert(...)". For throwing actual run-time exceptions, I think it's fine to require a static preallocation in an @nogc.

Though it does raise the issue of things such as global state (what if a catcher changes the msg?), exception threading, and finaly, purity.

Seems @nogc prevents both a the same time "can throw" and "pure" ... ?