January 04, 2012
On 01/05/2012 12:26 AM, Manu wrote:
> You just missed a big discussion on IRC about this, where I think I made
> some fair points that people actually agreed with.
>
>     On 1/4/2012 10:53 AM, Manu wrote:
>
>         Oh, and virtual-by-default... completely unacceptable for a
>         systems language.
>           most functions are NOT virtual, and finding the false-virtuals
>         while
>         optimising will be extremely tedious and time consuming.
>
>
>     The only reason to use classes in D is for polymorphic behavior -
>     and that means
>     virtual functions. Even so, a class member function will be called
>     directly if
>     it is private or marked as 'final'.
>
>
> Is this true? Surely the REAL reason to use classes is to allocate using
> the GC?

You can allocate any type using the GC.

> Aren't struct's allocated on the stack, and passed to functions by
> value? Do I need to start using the ref keyword to use GC allocated structs?
>

No.

>     An easy way to find functions that are not overridden (what you
>     called false virtuals) is to add:
>
>        final:
>
>     at the top of your class definition. The compiler will give you
>     errors for any functions that need to be virtual.
>
>     If you don't want polymorphic behavior, use structs instead. Struct
>     member
>     functions are never virtual.
>
>
> I have never written a class in any language where the ratio of virtual
> to non-virtual functions is more than 1:10 or so... requiring that one
> explicitly declared the vastly more common case seems crazy.

Are you sure that is the case?
In my code, most class member functions are true virtual.


January 04, 2012
On 5 January 2012 01:40, Timon Gehr <timon.gehr@gmx.ch> wrote:

> On 01/05/2012 12:26 AM, Manu wrote:
>
>> You just missed a big discussion on IRC about this, where I think I made some fair points that people actually agreed with.
>>
>>    On 1/4/2012 10:53 AM, Manu wrote:
>>
>>        Oh, and virtual-by-default... completely unacceptable for a
>>        systems language.
>>          most functions are NOT virtual, and finding the false-virtuals
>>        while
>>        optimising will be extremely tedious and time consuming.
>>
>>
>>    The only reason to use classes in D is for polymorphic behavior -
>>    and that means
>>    virtual functions. Even so, a class member function will be called
>>    directly if
>>    it is private or marked as 'final'.
>>
>>
>> Is this true? Surely the REAL reason to use classes is to allocate using the GC?
>>
>
> You can allocate any type using the GC.
>
>  Aren't struct's allocated on the stack, and passed to functions by
>> value? Do I need to start using the ref keyword to use GC allocated structs?
>>
>>
> No.
>
>     An easy way to find functions that are not overridden (what you
>>    called false virtuals) is to add:
>>
>>       final:
>>
>>    at the top of your class definition. The compiler will give you
>>    errors for any functions that need to be virtual.
>>
>>    If you don't want polymorphic behavior, use structs instead. Struct
>>    member
>>    functions are never virtual.
>>
>>
>> I have never written a class in any language where the ratio of virtual to non-virtual functions is more than 1:10 or so... requiring that one explicitly declared the vastly more common case seems crazy.
>>
>
> Are you sure that is the case?
> In my code, most class member functions are true virtual.
>

Here's one I'm working on right now (C++).
Base class for a UI system, surely one of the most heavily polymorphic
types of code one can imagine.

Count the virtuals... http://pastebin.com/dLUVvFsL


January 05, 2012
On 01/05/2012 12:54 AM, Manu wrote:
> On 5 January 2012 01:40, Timon Gehr <timon.gehr@gmx.ch
> <mailto:timon.gehr@gmx.ch>> wrote:
>
>     On 01/05/2012 12:26 AM, Manu wrote:
>
>         You just missed a big discussion on IRC about this, where I
>         think I made
>         some fair points that people actually agreed with.
>
>             On 1/4/2012 10:53 AM, Manu wrote:
>
>                 Oh, and virtual-by-default... completely unacceptable for a
>                 systems language.
>                   most functions are NOT virtual, and finding the
>         false-virtuals
>                 while
>                 optimising will be extremely tedious and time consuming.
>
>
>             The only reason to use classes in D is for polymorphic
>         behavior -
>             and that means
>             virtual functions. Even so, a class member function will be
>         called
>             directly if
>             it is private or marked as 'final'.
>
>
>         Is this true? Surely the REAL reason to use classes is to
>         allocate using
>         the GC?
>
>
>     You can allocate any type using the GC.
>
>         Aren't struct's allocated on the stack, and passed to functions by
>         value? Do I need to start using the ref keyword to use GC
>         allocated structs?
>
>
>     No.
>
>             An easy way to find functions that are not overridden (what you
>             called false virtuals) is to add:
>
>                final:
>
>             at the top of your class definition. The compiler will give you
>             errors for any functions that need to be virtual.
>
>             If you don't want polymorphic behavior, use structs instead.
>         Struct
>             member
>             functions are never virtual.
>
>
>         I have never written a class in any language where the ratio of
>         virtual
>         to non-virtual functions is more than 1:10 or so... requiring
>         that one
>         explicitly declared the vastly more common case seems crazy.
>
>
>     Are you sure that is the case?
>     In my code, most class member functions are true virtual.
>
>
> Here's one I'm working on right now (C++).
> Base class for a UI system, surely one of the most heavily polymorphic
> types of code one can imagine.

Apparently that is not true.

>
> Count the virtuals... http://pastebin.com/dLUVvFsL

9/~65 approx 1:6.
January 05, 2012
On Jan 4, 2012, at 3:26 PM, Manu wrote:
> 
> If a library makes liberal (and completely unnecessary) virtual calls to the point where it performs too poorly on some architecture; lets say ARM, or PPC (architectures that will suffer far more than x86 form virtual calls), I can no longer use this library in my project... What a stupid position to be in. The main strength of any language is its wealth of libraries available, and a bad language decision prohibiting use of libraries for absolutely no practical reason is just broken by my measure.

If a library is written without consideration to what is virtual and what is not, its performance will be the least of your problems.  Either way, this ship has long since sailed.  The impact of reversing this setting would be enormous.
January 05, 2012
Manu:

> I'm not referring to vector OPERATIONS. I only refer to the creation of a type to identify these registers...

Please, try to step back a bit and look at this problem from a bit more distance. D has vector operations, and so far they have received only a tiny amount of love. Are you able to find some ways to solve some of your problems using a hypothetical much better implementation of D vector operations? Please, think about the possibilities of this syntax.

Think about future CPU evolution with SIMD registers 128, then 256, then 512, then 1024 bits long. In theory a good compiler is able to use them with no changes in the D code that uses vector operations.

Intrinsics are an additive change, adding them later is possible. But I think fixing the syntax of vector ops is more important. I have some bug reports in Bugzilla about vector ops that are sleeping there since two years or so, and they are not about implementation performance.

I think the good Hara will be able to implement those syntax fixes in a matter of just one day or very few days if a consensus is reached about what actually is to be fixed in D vector ops syntax.

Instead of discussing about *adding* something (register intrinsics) I suggest to discuss about what to fix about the *already present* vector op syntax. This is not a request to just you Manu, but to this whole newsgroup.

Bye,
bearophile
January 05, 2012
On 1/4/2012 3:21 PM, bearophile wrote:
>> The only reason to use classes in D is for polymorphic behavior - and that
>> means virtual functions.
>
> I don't agree, in some cases I use final class instances instead of
> heap-allocated structs even when I don't need polymorphic behaviour just to
> avoid pointer syntax (there is also a bit higher probability of destructors
> being called, compared to heap-allocated structs). In some cases I've used a
> final class just to be able to use a this() with no arguments :-)


There's no reason to avoid pointer syntax, because D has:

1. ref types

2. automatic dereferencing of pointers
January 05, 2012
On 5/01/12 12:42 AM, bearophile wrote:
> Manu:
>
>> I'm not referring to vector OPERATIONS. I only refer to the creation of a
>> type to identify these registers...
>
> Please, try to step back a bit and look at this problem from a bit more distance. D has vector operations, and so far they have received only a tiny amount of love. Are you able to find some ways to solve some of your problems using a hypothetical much better implementation of D vector operations? Please, think about the possibilities of this syntax.
>
> Think about future CPU evolution with SIMD registers 128, then 256, then 512, then 1024 bits long. In theory a good compiler is able to use them with no changes in the D code that uses vector operations.
>
> Intrinsics are an additive change, adding them later is possible. But I think fixing the syntax of vector ops is more important. I have some bug reports in Bugzilla about vector ops that are sleeping there since two years or so, and they are not about implementation performance.
>
> I think the good Hara will be able to implement those syntax fixes in a matter of just one day or very few days if a consensus is reached about what actually is to be fixed in D vector ops syntax.
>
> Instead of discussing about *adding* something (register intrinsics) I suggest to discuss about what to fix about the *already present* vector op syntax. This is not a request to just you Manu, but to this whole newsgroup.
>
> Bye,
> bearophile

D has no alignment support, so there is no way to specify that you want a float[4] to be aligned on 16-bytes, which means there is no way for the compiler to generate code to exploit SSE well. It has to be conservative and assume unaligned.

Suppose alignment support is added:

alias align(16) float[4] vec4f;

vec4f a, b;
...
a[0] = a[3];
a[1] = a[2];
a[2] = b[0];
a[3] = b[1];

Is it reasonable to expect compilers to generate a single shuffle instruction from this? What about more complicated code like computing a dot product. What D code do I write to get the compiler to generate the expected machine code?

If we get alignment support and lots of work goes into optimizing vector ops for this then we can go a long with without intrinsics, but I don't think we'll ever be able to completely remove the need for intrinsics.
January 05, 2012
On 1/4/2012 3:26 PM, Manu wrote:
> Is this true? Surely the REAL reason to use classes is to allocate using the GC?
> Aren't struct's allocated on the stack, and passed to functions by value? Do I
> need to start using the ref keyword to use GC allocated structs?

struct S { ... }

S* s = new S(); // struct is allocated on the GC


> I have never written a class in any language where the ratio of virtual to
> non-virtual functions is more than 1:10 or so... requiring that one explicitly
> declared the vastly more common case seems crazy.

I found the opposite to be true when I use OOP in C++. Either scheme is valid, saying one is crazy or prohibitive way overstates the case.

(I have had a lot of bad experiences in C++ with accidentally overriding a non-virtual function. It's perfectly valid in C++, but man does your code behave bizarrely when you do it.)

In any sensible class design, you're going to have to decide which functions are overrideable and which are not. There's no way around it, and no magic default.


> The thing I'm most worried about is people forgetting to declare 'final:' on a
> class, or junior programmers who DON'T declare final, perhaps because they don't
> understand it, or perhaps because they have 1-2 true-virtuals, and the rest are
> just defined in the same place... This is DANGEROUS.

It isn't dangerous, it is just less optimal. What is dangerous is (in C++) the ability to override a non-virtual function, and the use of non-virtual destructors.

It's also true that D's design makes it possible for a compiler to make direct calls if it is doing whole-program analysis and determines that there are no overrides of it.
January 05, 2012
On 1/4/2012 4:30 PM, Sean Kelly wrote:
> If a library is written without consideration to what is virtual and what is
> not, its performance will be the least of your problems.

I agree. Such is a massive failure in designing a polymorphic type, and the language can't help with that.
January 05, 2012
On 4 January 2012 09:39, Manu <turkeyman@gmail.com> wrote:
> This conversation has meandered into one very specific branch, but I just
> want to add my 2c to the OP.
> I agree, I want D to be a useful systems language too. These are my issues
> to that end:
>
>  * __forceinline ... I wasn't aware this didn't exist... and yes, despite all this discussion, I still depend on this all the time. People are talking about implementing forceinline by immitating macros using mixins... crazy? Here's a solid reason I avoid mixins or procedurally generated code (and the preprocessor in C for that matter, in favour of __forceinline): YOU CAN DEBUG IT. In an inline function, the code exists in the source file, just like any other function, you can STEP THE DEBUGGER through it, and inspect the values easily. This is an underrated requirement. I would waste hours on many days if I couldn't do this. I would only ever use string mixins for the most obscure uses, preferring inline functions for the sake of debugging 99% of the time.
>
>  * vector type ... D has exactly no way to tell the compiler to allocate 128bit vector registers, load/store, and pass then to/from functions. That is MOST of the register memory on virtually every modern processor, and D can't address it... wtf?
>
>  * inline assembler needs pseudo registers ... The inline assembler is pretty crap, immitating C which is out-dated. Registers in assembly code should barely ever be addressed directly, they should only be addressed by TYPE, allowing the compiler to allocate available registers (and/or manage storing the the stack where required) as with any other code. Inline assembly without pseudo-registers is almost always an un-optimisation, and this is also the reason why almost all C programmers use hardware opcode intrinsics instead of inline assembly. There is no way without using intrinsics in C to allow the compiler to perform optimal register allocation, and this is still true for D, and in my opinion, just plain broken.
>
>  * __restrict ... I've said this before, but not being able to hint that the compiler ignore possible pointer aliasing is a big performance problem, especially when interacting with C libs.
>
>  * multiple return values (in registers) ... (just because I opened a topic
> about it before) This saves memory accesses in common cases where i want to
> return (x, y), or (retVal, errorCode) for instance.
>
> Walter made an argument "The same goes for all those language extensions you
> mentioned. Those are not part of Standard C. They are vendor extensions.
> Does that mean that C is not actually a systems language? No."
> This is absurd... are you saying that you expect Iain to add these things to
> GDC to that people can use them, and then create incompatible D code with
> the 'standard' compiler?
> Why would you intentionally fragment the compiler support of language
> features rather than just making trivial (but important) features that
> people do use part of the language?
>

Code that gdc emits is incompatible with the standard D compiler, if that's what you want to call it, and any vendor extensions won't contribute to that being more of the case.

Regardless, there is little reason to want to use a forced inline with gdc.  Just like in c++ when you define all methods in the class definition, gdc considers all methods as candidates for inlining. Similarly, when -inline is passed, the same is also done for normal functions that are considered inlinable by the frontend.  These functions marked as inline are treated in the same way as a function declared 'inline' in C or C++, and will be treated as such by the backend.


-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';