Re: virtual-by-default rant

2012-03-24 Thread Manu
On 23 March 2012 21:11, Adam D. Ruppe destructiona...@gmail.com wrote:

 Something that *might* help is to do unit tests. Yeah,
 that's kinda ass, but it would catch a stray virtual early.


They're not necessarily 'stray' virtuals, they're inappropriate ones
There's a time and place for virtuals, but there's many more times and
places they shouldn't be :)
It's nice to be able to skim a class and see 'virtual' written clearly all
over it to gather some basic performance/usage information about the class.
The visual cue is important, and the ability to grep for them.

Rememer that virtuals are

Do a unit test that does a traits check for virtuals:

 http://dlang.org/traits.html#**getVirtualFunctionshttp://dlang.org/traits.html#getVirtualFunctions

 if the name isn't on a list of approved virtuals,
 static assert fail.


I've said this all before, but I'll repeat my general reasoning on the
issue. My objection to virtual-by-default, but, acknowledging that can't be
changed, insistence on a virtual keyword is this. (uh oh, manu-rant alert)
:P

The top most compelling reason for switching from an extremely mature,
efficient, reliable, commercially accepted language like C/C++ to something
still relatively experimental (D) is to simplify code and maintenance long
term.
The goal is to do the same work we already do with less lines of code. They
should also be cleaner, tidier, less confusing, more informative lines of
code.
Adding a system like you describe to validate virtuals is not a complexity
I'm interested in implementing, it is just one clear reason to sick with
C++. Imagine presenting that to a building full of programmers who
are sceptical about changing from C++ in the first place? What will they
make of such a crude requirement when they already have a perfectly good
virtual keyword in C++?

D offers some amazing steps forwards in terms of powerful meta-programming.
Many typical C/C++ systems that require maintaining (and synchronising)
ugly tables of data, enums, stupid little functions and macros to do
trivial stuff; these can largely be removed in D. It is possible to invent
systems that take code and comprehend it implicitly, generating the desired
functionality, without having to pollute the classes themselves with extra
rubbish used by such a generator (see: user attributes thread).
Removing this sort of crap is something everyone can appreciate. But if we
have to revert to this behaviour to work around a different set of
problems, then we haven't really gained anything.

Code that remains tidy and maintainable for 10+ years (common in gamedev,
game engines live ~2 console generations on average, often longer), but is
still very fluid and dynamic (how gamedev code differs from other
enterprise code, it changes frequently), and doesn't degrade in performance
due to added complexity over years, is, fundamentally, SIMPLE code. It is
also *LESS* code, the fewer lines, the more maintainable as a rule. And
most certainly, code WITHOUT explicit tables of codegen related data; these
are always the first things to rot and fall out of sync. There are often
weird ancillary systems grown around these things to try and auto-magically
maintain them, which themselves are just redundant noise, and contributes
to further complexity and eventual bitrot. I've seen it time and time
again. This is C++'s biggest shortcoming; the language only goes 90% of the
way, and untold complexity is added to achieve the final 10%.

These such sorts of tables are why I fear an enum based serialisation
system, or an enum based virtual function verification system. Who
maintains these tables? It's only a matter of time before some clever
bugger comes along and writes some fancy system to auto-magically manage
these tables, and then every other programmer comes along, has no idea what
to make of it anymore, and wonders what said clever bugger was smoking.
This is just how it works out in practise. Then said clever bugger quits...
_

This is one of the key pains I hope to eliminate by using D, but I can't
trade performance for it. The bar is high, competition is staunch, games
consoles are fixed hardware. All the performance tuning mechanisms
available in C/C++ must also be available in D (and generally are, plus
more waiting to be taken advantage of). I shouldn't need to add complex
workarounds for something so trivial as the missing virtual keyword :)


Side note..

I'm a language nerd, and I get excited by D, but I'm trying to think
critically about transplanting it realistically into the commercial
environment. I know what happens there, and it can only be adopted if a
significant numer of C++'s shortcoings are overcome, AND no new
shortcomings are added in the process. Most people aren't interested in D,
they may be sceptical and apprehensive to abandon something with 40 years
of maturity and a whole industry of support. They will not take the risk to
their business for a small number of improvements, especially if they lose

Re: virtual-by-default rant

2012-03-24 Thread Artur Skawina
On 03/23/12 20:11, Adam D. Ruppe wrote:
 
 http://dlang.org/traits.html#getVirtualFunctions
 
 if the name isn't on a list of approved virtuals,
 static assert fail.

And you could probably do it in a clean and unintrusive way,
by, for example, extending Object, or doing it on a per-module
basis. If it actually worked...

The obvious problem is that the 'virtual' check pretty much
has to *prevent* devirtualization, or lie about it and always
report the functions as virtual -- otherwise devirtualization
has to happen before the checks, and this could change their
results.

Also, my gdc (which i haven't updated for a while) does not
even devirtualize this simple case:

---
private class C {
  int bar() { return 42; }
}

pragma(attribute, externally_visible) int main() {
  C c = new C;
  //writeln(__traits(isVirtualFunction, c.bar));
  return c.bar();
}
---

It needs at least the class or method marked as 'final' to do the
right thing. Note that the isVirtualFunction check returns true even
for the cases where bar() does get inlined. (*VirtualMethod* do not
exist here)

artur


Re: virtual-by-default rant

2012-03-24 Thread Adam D. Ruppe

On Saturday, 24 March 2012 at 14:43:21 UTC, Artur Skawina wrote:
It needs at least the class or method marked as 'final' to do 
the right thing.


Indeed, that's what I'm after.

I'm making another post with an implementation in reply
to manu in a minute.


Re: virtual-by-default rant

2012-03-24 Thread Adam D. Ruppe

On Saturday, 24 March 2012 at 10:56:27 UTC, Manu wrote:
My objection to virtual-by-default, but, acknowledging that 
can't be changed, insistence on a virtual keyword

is this.


I like the idea of a virtual keyword btw.

Adding a system like you describe to validate virtuals is not a 
complexity I'm interested in implementing



You already have! Let me quote one of your previous posts:

I sincerely fear finding myself false-virtual hunting on build 
night until
2am trying to get the game to hold its frame rate (I already do 
this in

C++, but at least you can grep for and validate them!).


In C++, you're hunting for false virtuals right now.

Your solution is to grep for and validate them.


That's what I'm talking about here, but instead of grepping,
using the language's reflection capabilities for an automated
test.

Check out the example I pasted at the end of this message.

The bottom part of that is reusable, the top part is my
test data.

Run it through the compiler with the test code added:

$ dmd test13 -unittest
Warning: A.lol is an unauthorized virtual function
Warning: B.amazing is an unauthorized virtual function


And it greps for virtuals for you, and reports
it at compile time.

If it turns out you want one of them to be virtual,
you add the name to the authorizedVirtuals list.

How would you validate a virtual in C++? If
you have a list of functions you're OK with,
that's exactly what this is!

If you look at the source of each virtual your
grep finds, to ensure it absolutely needs to
be virtual... well, you can do that here too. Between
the warnings and the authorized virtuals list, you know
all the virts here and can review them.


The best way to silence a warning btw is to just
write final on the method.

Your code review process can keep the authorized
virtual list to themselves, so most developers
either add final or break the build. Either way,
no virtuals slip in without review.


Also from an old post:

Aside from that, I want a compile error if someone tries to 
randomly

override stuff.

Warning: C.goodVirtual is an unauthorized virtual function

the code below checks on a per class level, so if you don't
authorize the override, it gets a warning to.

(You can change these to errors by making it static assert
or something instead of pragma(msg).)



Who maintains these tables?


Who decides who can write virtual in C++?




Example follows:


===
module test13;

class A {
void goodVirtual() {}
void lol() {}
}

class B {
int amazing() { return 0; }
}

class C : A {
override void goodVirtual() {}
final void drox() {}
}

template isClass(alias T) if(!is(T)) { enum bool isClass = false; 
}
template isClass(alias T) if(is(T)) { enum bool isClass = is(T == 
class); }


unittest {
enum string[][string] authorizedVirtuals = [
A : [goodVirtual],
B : [],
C : [goodVirtual],
];

import algore = std.algorithm;

foreach(member; __traits(allMembers, test13)) {
static if(isClass!(__traits(getMember, test13, member))) {
			foreach(possibleVirt; __traits(derivedMembers, 
__traits(getMember, test13, member))) {

static if(
__traits(isVirtualMethod, 
__traits(getMember,
__traits(getMember, test13, 
member), possibleVirt))


!algore.canFind(authorizedVirtuals[member], possibleVirt))
{
	pragma(msg, Warning:  ~ member ~ . ~ possibleVirt ~  is 
an unauthorized virtual function);

}
}
}
}
}

void main() {}

===




Re: virtual-by-default rant

2012-03-24 Thread F i L
I think a better system would be to explicitly mark functions are 
virtual, and then use unittesting to catch virtual functions that 
don't need to be.




Re: virtual-by-default rant

2012-03-24 Thread Artur Skawina
On 03/24/12 16:16, Adam D. Ruppe wrote:
 On Saturday, 24 March 2012 at 10:56:27 UTC, Manu wrote:
 My objection to virtual-by-default, but, acknowledging that can't be 
 changed, insistence on a virtual keyword
 is this.
 
 I like the idea of a virtual keyword btw.
 
 Adding a system like you describe to validate virtuals is not a complexity 
 I'm interested in implementing
 
 
 You already have! Let me quote one of your previous posts:
 
 I sincerely fear finding myself false-virtual hunting on build night until
 2am trying to get the game to hold its frame rate (I already do this in
 C++, but at least you can grep for and validate them!).
 
 
 In C++, you're hunting for false virtuals right now.
 
 Your solution is to grep for and validate them.
 
 
 That's what I'm talking about here, but instead of grepping,
 using the language's reflection capabilities for an automated
 test.
 
 Check out the example I pasted at the end of this message.

The question is -- are there false positives? 
(Ie situations where the compiler managed to devirtualize
methods which __traits reported earlier as being virtual)

artur


Re: virtual-by-default rant

2012-03-24 Thread Ary Manzana

On 3/24/12 3:03 AM, Manu wrote:

On 23 March 2012 17:24, Ary Manzana a...@esperanto.org.ar
mailto:a...@esperanto.org.ar wrote:

On 3/18/12 9:23 AM, Manu wrote:

The virtual model broken. I've complained about it lots, and people
always say stfu, use 'final:' at the top of your class.

That sounds tolerable in theory, except there's no 'virtual'
keyword to
keep the virtual-ness of those 1-2 virtual functions I have...
so it's
no good (unless I rearrange my class, breaking the logical
grouping of
stuff in it).
So I try that, and when I do, it complains: Error: variable
demu.memmap.MemMap.machine final cannot be applied to variable,
allegedly a D1 remnant.
So what do I do? Another workaround? Tag everything as final
individually?

My minimum recommendation: D needs an explicit 'virtual'
keyword, and to
fix that D1 bug, so putting final: at the top of your class
works, and
everything from there works as it should.


Is virtual-ness your performance bottleneck?


Frequently. It's often the most expensive 'trivial' operation many
processors can be asked to do. Senior programmers (who have much better
things to waste their time on considering their pay bracket) frequently
have to spend late nights mitigating this even in C++ where virtual
isn't default. In D, I'm genuinely concerned by this prospect. Now I
can't just grep for virtual and fight them off, which is time consuming
alone, I will need to take every single method, one by one, prove it is
never overloaded anywhere (hard to do), before I can even begin the
normal process of de-virtualising it like you do in C++.
The problem is elevated by the fact that many programmers are taught in
university that virtual functions are okay. They come to the company,
write code how they were taught in university, and then we're left to
fix it up on build night when we can't hold our frame rate. virtual
functions and scattered/redundant memory access are usually the first
thing you go hunting for. Fixing virtuals is annoying when the system
was designed to exploit them, it often requires some extensive
refactoring, much harder to fix than a bad memory access pattern, which
might be as simple as rearranging a struct.


Interesting.

I spend most of my work time programming in Ruby, where everything is 
virtual+ :-P


It's good to know that virtual-ness can be a bottleneck.


Re: virtual-by-default rant

2012-03-24 Thread Adam D. Ruppe

On Saturday, 24 March 2012 at 16:27:41 UTC, Artur Skawina wrote:

The question is -- are there false positives?


Yes, almost certainly. This only looks at the function
definition; it is run well before the optimizer.


Re: virtual-by-default rant

2012-03-23 Thread Marco Leise
Am Sun, 18 Mar 2012 04:49:12 +0100
schrieb F i L witte2...@gmail.com:

 On Sunday, 18 March 2012 at 03:27:40 UTC, bearophile wrote:
  F i L:
 
  I'm a bit confused. Reading through the virtual function's 
  docs (http://dlang.org/function.html#virtual-functions) it 
  says:
  
  All non-static non-private non-template member functions are 
  virtual. This may sound inefficient, but since the D compiler 
  knows all of the class hierarchy when generating code, all 
  functions that are not overridden can be optimized to be 
  non-virtual.
 
  This is so much theoretical that I think this should be removed 
  from the D docs. And to be put back when one DMD compiler is 
  able to do this. Otherwise it's just false advertising :-)
 
  Bye,
  bearophile
 
 Dammit, I was afraid someone would say something like that. Well 
 at least it's a good goal. It is a bit of false advertising 
 though, honestly it should just be marked implementation in 
 progress or something like that.
 

the D compiler knows all of the class hierarchy when generating code
This is just wrong, and if that was the base for deciding on virtual as 
default, I believe it is natural to think about it again.

Otherwise it should read if you deal with non exported classes and don't use 
incremental compilation as well as refrain from compiling your code into static 
libraries, a D compiler can optimize methods to be non-virtual. As of the time 
of writing [...] no such compiler exists.

Now I feel better :)

-- Marco



Re: virtual-by-default rant

2012-03-23 Thread F i L

Marco Leise wrote:
the D compiler knows all of the class hierarchy when 
generating code
This is just wrong, and if that was the base for deciding on 
virtual as default, I believe it is natural to think about it 
again.


Yes, further reading has led me to believe that Manu is right in 
his request for a virtual keyword (at least). Final by default is 
a great concept on paper, but unless it's possible across Lib 
boundaries (which I'm not sure it is) then to me it does seem a 
bit backwards given that efficiency is a key feature of D and 
most programmers are already used to fixed by default anyways.





Re: virtual-by-default rant

2012-03-23 Thread Timon Gehr

On 03/23/2012 02:47 PM, F i L wrote:

...  and most programmers are already used
to fixed by default anyways.



This assertion is unjustified.



Re: virtual-by-default rant

2012-03-23 Thread F i L

On Friday, 23 March 2012 at 13:58:00 UTC, Timon Gehr wrote:

On 03/23/2012 02:47 PM, F i L wrote:

...  and most programmers are already used
to fixed by default anyways.



This assertion is unjustified.


Given that the four most popular languages today (Java, C, C++, 
and C#) all function this way, I'd say it's fairly accurate. But 
I also didn't to say Final by default should be default in D 
(though I wouldn't really disagree with that direction either), I 
do think D should have a virtual keyword.




Re: virtual-by-default rant

2012-03-23 Thread F i L
Given that the four most popular languages today (Java, C, C++, 
and C#) all function this way, I'd say it's fairly accurate. 
But I also didn't to say Final by default should be default in 
D (though I wouldn't really disagree with that direction 
either), I do think D should have a virtual keyword.


Whoops, that's wrong. Java is virtual by default. So I guess 
you're right, my statements aren't really justified.





Re: virtual-by-default rant

2012-03-23 Thread Ary Manzana

On 3/18/12 9:23 AM, Manu wrote:

The virtual model broken. I've complained about it lots, and people
always say stfu, use 'final:' at the top of your class.

That sounds tolerable in theory, except there's no 'virtual' keyword to
keep the virtual-ness of those 1-2 virtual functions I have... so it's
no good (unless I rearrange my class, breaking the logical grouping of
stuff in it).
So I try that, and when I do, it complains: Error: variable
demu.memmap.MemMap.machine final cannot be applied to variable,
allegedly a D1 remnant.
So what do I do? Another workaround? Tag everything as final individually?

My minimum recommendation: D needs an explicit 'virtual' keyword, and to
fix that D1 bug, so putting final: at the top of your class works, and
everything from there works as it should.


Is virtual-ness your performance bottleneck?


Re: virtual-by-default rant

2012-03-23 Thread Manu
On 23 March 2012 17:24, Ary Manzana a...@esperanto.org.ar wrote:

 On 3/18/12 9:23 AM, Manu wrote:

 The virtual model broken. I've complained about it lots, and people
 always say stfu, use 'final:' at the top of your class.

 That sounds tolerable in theory, except there's no 'virtual' keyword to
 keep the virtual-ness of those 1-2 virtual functions I have... so it's
 no good (unless I rearrange my class, breaking the logical grouping of
 stuff in it).
 So I try that, and when I do, it complains: Error: variable
 demu.memmap.MemMap.machine final cannot be applied to variable,
 allegedly a D1 remnant.
 So what do I do? Another workaround? Tag everything as final individually?

 My minimum recommendation: D needs an explicit 'virtual' keyword, and to
 fix that D1 bug, so putting final: at the top of your class works, and
 everything from there works as it should.


 Is virtual-ness your performance bottleneck?


Frequently. It's often the most expensive 'trivial' operation many
processors can be asked to do. Senior programmers (who have much better
things to waste their time on considering their pay bracket) frequently
have to spend late nights mitigating this even in C++ where virtual isn't
default. In D, I'm genuinely concerned by this prospect. Now I can't just
grep for virtual and fight them off, which is time consuming alone, I will
need to take every single method, one by one, prove it is never overloaded
anywhere (hard to do), before I can even begin the normal process of
de-virtualising it like you do in C++.
The problem is elevated by the fact that many programmers are taught in
university that virtual functions are okay. They come to the company, write
code how they were taught in university, and then we're left to fix it up
on build night when we can't hold our frame rate. virtual functions and
scattered/redundant memory access are usually the first thing you go
hunting for. Fixing virtuals is annoying when the system was designed to
exploit them, it often requires some extensive refactoring, much harder to
fix than a bad memory access pattern, which might be as simple as
rearranging a struct.


Re: virtual-by-default rant

2012-03-23 Thread Adam D. Ruppe

Something that *might* help is to do unit tests. Yeah,
that's kinda ass, but it would catch a stray virtual early.


Do a unit test that does a traits check for virtuals:

http://dlang.org/traits.html#getVirtualFunctions

if the name isn't on a list of approved virtuals,
static assert fail.

You'd then maintain the list of approved virtuals
in the unit test, where it is easier to check over.


idk though, I've never worked on a project like this.


Re: virtual-by-default rant

2012-03-19 Thread Dmitry Olshansky

On 19.03.2012 2:17, Artur Skawina wrote:

On 03/18/12 15:37, Dmitry Olshansky wrote:

On 18.03.2012 5:23, Manu wrote:

The virtual model broken. I've complained about it lots, and people
always say stfu, use 'final:' at the top of your class.

That sounds tolerable in theory, except there's no 'virtual' keyword to
keep the virtual-ness of those 1-2 virtual functions I have... so it's
no good (unless I rearrange my class, breaking the logical grouping of
stuff in it).
So I try that, and when I do, it complains: Error: variable
demu.memmap.MemMap.machine final cannot be applied to variable,
allegedly a D1 remnant.
So what do I do? Another workaround? Tag everything as final individually?

My minimum recommendation: D needs an explicit 'virtual' keyword, and to
fix that D1 bug, so putting final: at the top of your class works, and
everything from there works as it should.


Following this thread and observing that you don't trust optimizer and compiler 
in many cases or have to double check them anyway, I have a suggestion: do 
virtual dispatch by hand via func-pointer table and use structs.

I'm serious, with a bit of metaprogramming it wouldn't be half bad, and as a 
bonus you don't have to pay for a monitor field per object as classes do, and 
in general less compiler magic to keep track of. You also gain the ability to 
fine tune their layout, the performance maniac side of yours must see the 
potential it brings :)


I was going to suggest the very same thing - but there are (at least) two 
problems
with that approach:

1) pass-by-value -- it's dangerous, ugly to work-around (and compiler bugs don't
help, like the one where just having a this(this) causes problems); the
workarounds also have compiler/ABI issues (like the 'File' case posted in 
D.learn
some time ago, or GDC not passing/returning the pseudo-refs in registers)


GDC not passing pseudo-refs in registers is cleanly a non-issue, in a 
sense, that it's not a good excuse at all, as well the other bugs.
All in all, nobody is going to kill you if in performance sensitive code 
you'd use pointers:


BigStruct* my_big = allocateSomewhere(...ctor_args...); //ultimately 
using emplace




2) no inheritance. ie 'struct A{}; struct B{A super; alias super this;}' cannot 
be
written as just 'struct B:A {}' - which would not be just syntax sugar, but 
also
allow (more) implicit conversions, (explicit) function overrides etc.



Template mixins? I envision:
struct Foo{
mixin Inherit!(Bar);
}

I see that it is not a cake-walk but acceptable for the special nature 
of requirements.



So - yes, D structs should be enough for everything, but right now they're still
missing some required basic features. Ideally class would just be sugar, and
everything should be expressible using just structs - obviously in a much more
verbose, but 100% compatible way (incl vtables, monitors etc)


Yes, that the point. And if one doesn't like this kind of compiler 
sugar, he is free to synthesize Xylitol.




--
Dmitry Olshansky


Re: virtual-by-default rant

2012-03-19 Thread Artur Skawina
On 03/19/12 08:30, Dmitry Olshansky wrote:
 On 19.03.2012 2:17, Artur Skawina wrote:
 On 03/18/12 15:37, Dmitry Olshansky wrote:
 On 18.03.2012 5:23, Manu wrote:
 The virtual model broken. I've complained about it lots, and people
 always say stfu, use 'final:' at the top of your class.

 That sounds tolerable in theory, except there's no 'virtual' keyword to
 keep the virtual-ness of those 1-2 virtual functions I have... so it's
 no good (unless I rearrange my class, breaking the logical grouping of
 stuff in it).
 So I try that, and when I do, it complains: Error: variable
 demu.memmap.MemMap.machine final cannot be applied to variable,
 allegedly a D1 remnant.
 So what do I do? Another workaround? Tag everything as final individually?

 My minimum recommendation: D needs an explicit 'virtual' keyword, and to
 fix that D1 bug, so putting final: at the top of your class works, and
 everything from there works as it should.

 Following this thread and observing that you don't trust optimizer and 
 compiler in many cases or have to double check them anyway, I have a 
 suggestion: do virtual dispatch by hand via func-pointer table and use 
 structs.

 I'm serious, with a bit of metaprogramming it wouldn't be half bad, and as 
 a bonus you don't have to pay for a monitor field per object as classes do, 
 and in general less compiler magic to keep track of. You also gain the 
 ability to fine tune their layout, the performance maniac side of yours 
 must see the potential it brings :)

 I was going to suggest the very same thing - but there are (at least) two 
 problems
 with that approach:

 1) pass-by-value -- it's dangerous, ugly to work-around (and compiler bugs 
 don't
 help, like the one where just having a this(this) causes problems); the
 workarounds also have compiler/ABI issues (like the 'File' case posted 
 in D.learn
 some time ago, or GDC not passing/returning the pseudo-refs in registers)
 
 GDC not passing pseudo-refs in registers is cleanly a non-issue, in a sense, 
 that it's not a good excuse at all, as well the other bugs.

Something that should work in theory, but does not behave as expected,
*is* an issue, if it means you can't actually use that solution right now.
[Note the GDC problem may or may not still be there; i tried it a while ago;
 the other issues cause enough trouble anyway] 

 All in all, nobody is going to kill you if in performance sensitive code 
 you'd use pointers:
 
 BigStruct* my_big = allocateSomewhere(...ctor_args...); //ultimately using 
 emplace

struct A{}
struct B{A sup; alias sup this;}
void f1(A* a) {/*...*/}
// Fail:
void f2(B* b) {f1(b);/*...*/}
A* b = new B;

// And, yes, void f1(ref A a); etc would work, but then it's just a question
// of time before you'll end up searching the whole project for erroneous struct
// copies, instead of virtuals. And the virtual methods are easier to find...

 2) no inheritance. ie 'struct A{}; struct B{A super; alias super this;}' 
 cannot be
 written as just 'struct B:A {}' - which would not be just syntax sugar, 
 but also
 allow (more) implicit conversions, (explicit) function overrides etc.

 
 Template mixins? I envision:
 struct Foo{
 mixin Inherit!(Bar);
 }
 
 I see that it is not a cake-walk but acceptable for the special nature of 
 requirements.

This thread was about larger non-trivial projects, and the difficulty in finding
all methods that do not need to be virtual -- i don't know if replacing the 
whole
class hierarchy with a template-mixin-wrapped-in-structs hierarchy would really 
be
such a good idea. ;)
Also, see the above example - doing struct inheritance by hand, w/o compiler 
help,
quickly gets ugly and dangerous.

 So - yes, D structs should be enough for everything, but right now they're 
 still
 missing some required basic features. Ideally class would just be sugar, 
 and
 everything should be expressible using just structs - obviously in a much 
 more
 verbose, but 100% compatible way (incl vtables, monitors etc)
 
 Yes, that the point. And if one doesn't like this kind of compiler sugar, he 
 is free to synthesize Xylitol.

I'm saying use structs instead of classes is a good suggestion, but *right 
now*
the language and compiler do not provide enough support to make this practical.
There's a lot of room for (backwards compatible) improvements, though.

artur


Re: virtual-by-default rant

2012-03-19 Thread Dmitry Olshansky

On 19.03.2012 14:45, Artur Skawina wrote:

On 03/19/12 08:30, Dmitry Olshansky wrote:

On 19.03.2012 2:17, Artur Skawina wrote:

On 03/18/12 15:37, Dmitry Olshansky wrote:

On 18.03.2012 5:23, Manu wrote:

The virtual model broken. I've complained about it lots, and people
always say stfu, use 'final:' at the top of your class.

That sounds tolerable in theory, except there's no 'virtual' keyword to
keep the virtual-ness of those 1-2 virtual functions I have... so it's
no good (unless I rearrange my class, breaking the logical grouping of
stuff in it).
So I try that, and when I do, it complains: Error: variable
demu.memmap.MemMap.machine final cannot be applied to variable,
allegedly a D1 remnant.
So what do I do? Another workaround? Tag everything as final individually?

My minimum recommendation: D needs an explicit 'virtual' keyword, and to
fix that D1 bug, so putting final: at the top of your class works, and
everything from there works as it should.


Following this thread and observing that you don't trust optimizer and compiler 
in many cases or have to double check them anyway, I have a suggestion: do 
virtual dispatch by hand via func-pointer table and use structs.

I'm serious, with a bit of metaprogramming it wouldn't be half bad, and as a 
bonus you don't have to pay for a monitor field per object as classes do, and 
in general less compiler magic to keep track of. You also gain the ability to 
fine tune their layout, the performance maniac side of yours must see the 
potential it brings :)


I was going to suggest the very same thing - but there are (at least) two 
problems
with that approach:

1) pass-by-value -- it's dangerous, ugly to work-around (and compiler bugs don't
 help, like the one where just having a this(this) causes problems); the
 workarounds also have compiler/ABI issues (like the 'File' case posted in 
D.learn
 some time ago, or GDC not passing/returning the pseudo-refs in registers)


GDC not passing pseudo-refs in registers is cleanly a non-issue, in a sense, 
that it's not a good excuse at all, as well the other bugs.


Something that should work in theory, but does not behave as expected,
*is* an issue, if it means you can't actually use that solution right now.
[Note the GDC problem may or may not still be there; i tried it a while ago;
  the other issues cause enough trouble anyway]


All in all, nobody is going to kill you if in performance sensitive code you'd 
use pointers:

BigStruct* my_big = allocateSomewhere(...ctor_args...); //ultimately using 
emplace


struct A{}
struct B{A sup; alias sup this;}
void f1(A* a) {/*...*/}
// Fail:
void f2(B* b) {f1(b);/*...*/}
A* b = new B;

// And, yes, void f1(ref A a); etc would work, but then it's just a question
// of time before you'll end up searching the whole project for erroneous struct
// copies, instead of virtuals. And the virtual methods are easier to find...



Sure sounds like fun challenge, that's my start before being killed by 
compiler internal error (damn, it's an *issue* after all)


Assertion failure: 't' on line 7911 in file 'mtype.c'

Anyway here is the code:

struct A{
  int a;
}

template Inherit(alias X)
{
  X __super;
  alias __super this;
}


struct B{
  mixin Inherit!A;
  int b;
}

struct PolyPtr(X)//no opaque pointers or loose polymorphism
{
X* _payload;
static if(is(typeof(X.init.__super)))
{
alias typeof(X.init.__super) Super;
//chain up the rest of possible super classes
@property auto getSuper(){ return 
PolyPtr!Super(_payload.__super); }
alias getSuper this;
}
//  alias _payload this;//multiple alias this, sigh
auto opDispatch(string s)(){ return mixin(_payload.~s); }
}

template create(X)
{
PolyPtr!X create(X, T...)(T args){
return PolyPtr!X(args);
}   
}

void f1(PolyPtr!A a) {/*...*/}
void f2(PolyPtr!B b) {f1(b);/*...*/}


void main(){
auto b = create!B(42, 31);
}





2) no inheritance. ie 'struct A{}; struct B{A super; alias super this;}' cannot 
be
 written as just 'struct B:A {}' - which would not be just syntax sugar, 
but also
 allow (more) implicit conversions, (explicit) function overrides etc.



Template mixins? I envision:
struct Foo{
 mixin Inherit!(Bar);
}

I see that it is not a cake-walk but acceptable for the special nature of 
requirements.


This thread was about larger non-trivial projects, and the difficulty in finding
all methods that do not need to be virtual -- i don't know if replacing the 
whole
class hierarchy with a template-mixin-wrapped-in-structs hierarchy would really 
be
such a good idea. ;)
Also, see the above example - doing struct inheritance by hand, w/o compiler 
help,
quickly gets ugly and dangerous.


So - yes, D structs should be enough for everything, but right now they're still
missing some required basic features. Ideally class would just be sugar, and
everything should be expressible 

Re: virtual-by-default rant

2012-03-19 Thread deadalnix

Le 18/03/2012 22:36, James Miller a écrit :

On 19 March 2012 06:41, David Nadlingers...@klickverbot.at  wrote:

On Sunday, 18 March 2012 at 17:24:15 UTC, F i L wrote:


[…] I know LDC has a  LTO flag.



Unfortunately it doesn't (-O4/-O5 are defunct), but working on seamless LTO
integration (and better optimization pass scheduling in general) would be
low-hanging fruit for anybody wanting to join LDC development.

David


I think that simply adding a `virtual` keyword that explicitly makes
things virtual, even if they would otherwise be final, makes sense.
Keep all the current semantics the same, relegate use of `virtual` to
the 'advanced' section of D usage, everybody is happy.

I'm with Manu in the case of I don't trust the compiler. I'm
perfectly happy for the compile to optimize short sections of code
that I probably could optimize myself, but its not much of an issue,
but I am reluctant to rely on the tooling to make decisions for me.
For small programs, where it doesn't matter if it's half as fast as it
could be, but that just means 2ms vs 1ms, I don't care. But in
intensive programs, then I want to be sure that the compiler will do
what I want.

--
James Miller


+1


Re: virtual-by-default rant

2012-03-18 Thread Mike Parker

On 3/18/2012 12:27 PM, bearophile wrote:

F i L:


I'm a bit confused. Reading through the virtual function's docs
(http://dlang.org/function.html#virtual-functions) it says:

All non-static non-private non-template member functions are
virtual. This may sound inefficient, but since the D compiler
knows all of the class hierarchy when generating code, all
functions that are not overridden can be optimized to be
non-virtual.


This is so much theoretical that I think this should be removed from the D 
docs. And to be put back when one DMD compiler is able to do this. Otherwise 
it's just false advertising :-)

Bye,
bearophile


It says can be optimized, not are optimized. Big difference.


Re: virtual-by-default rant

2012-03-18 Thread David Nadlinger

On Sunday, 18 March 2012 at 03:27:40 UTC, bearophile wrote:

F i L:
All non-static non-private non-template member functions are 
virtual. This may sound inefficient, but since the D compiler 
knows all of the class hierarchy when generating code, all 
functions that are not overridden can be optimized to be 
non-virtual.


This is so much theoretical that I think this should be removed 
from the D docs. And to be put back when one DMD compiler is 
able to do this. Otherwise it's just false advertising :-)


Is this even possible without LTO/WPO? Extending a class defined 
in a library you link in (and for which codegen already happened) 
is certainly possible…


David


Re: virtual-by-default rant

2012-03-18 Thread Manu
On 18 March 2012 04:47, F i L witte2...@gmail.com wrote:

 I'm a bit confused. Reading through the virtual function's docs (
 http://dlang.org/function.**html#virtual-functionshttp://dlang.org/function.html#virtual-functions)
 it says:

 All non-static non-private non-template member functions are virtual.
 This may sound inefficient, but since the D compiler knows all of the class
 hierarchy when generating code, all functions that are not overridden can
 be optimized to be non-virtual.

 So if all functions are automatically optimized to non-virtual where
 applicable, then the final keyword is for conceptual access limitation
 only. This makes a lot of sense to me. Is there something I'm not getting
 that makes you want an explicit virtual keyword?


It's not dependable. Virtually everything meets those criteria and will be
virtual, but I want to be confident that NOTHING is EVER virtual, unless I
absolutely say so.
D knows nothing about the class hierarchy when generating code, I don't
know how it can make that claim? Anything that's not private can be
extended by another module, and only the linker could ever know out about
that.
Aside from that, I want a compile error if someone tries to randomly
override stuff. virtuals are a heinous crime, and should only be used
explicitly. It should not be possible for someone to accidentally create a
virtual.


Re: virtual-by-default rant

2012-03-18 Thread Manu
On 18 March 2012 06:42, Andrei Alexandrescu seewebsiteforem...@erdani.org
 wrote:

 On 3/17/12 9:24 PM, Manu wrote:

 Yeah, I'm not really into that. I group things conceptually.
 Either way, I've never written a class where non-virtuals don't outweigh
 virtuals in the realm of 20:1.


 Then probably struct is what you're looking for.


No, I definitely want a class. ref type, gc mem, etc.
struct doesn't support virtual at all. I have 2 virtuals, this particular
class has around 50 public methods, almost all of which are trivial
accessors, called extremely heavily in hot loops. More similar classes to
come.

I've never in 15 years seen a large-ish class where the majority of methods
are virtual. Who writes code like that? It's never come up in my industry
at least.
Maybe you'll occasionally see it in a small interface class, but D has real
interfaces...


On 18 March 2012 11:00, David Nadlinger s...@klickverbot.at wrote:

 Is this even possible without LTO/WPO? Extending a class defined in a
 library you link in (and for which codegen already happened) is certainly
 possible…


It's not possible without LTO, which is crazy. Depending on an advanced
optimiser to generate the most basic code is a clear mistake.

I think we just need the ability to state 'final:' and mark explicit
'virtual's, the problem is mitigated without breaking the language. I can
live with a policy where everyone is instructed to write code that way.


Re: virtual-by-default rant

2012-03-18 Thread F i L

Manu wrote:
D knows nothing about the class hierarchy when generating code, 
I don't know how it can make that claim?


How does D not know about class hierarchy when generating code? 
That doesn't make sense to me. It *has* to know to even generate 
code.



Anything that's not private can be
extended by another module, and only the linker could ever know 
out about that.


This shouldn't be an issue:

export void method() // virtual
export final void method() // non-virtual

Aside from that, I want a compile error if someone tries to 
randomly override stuff.


This only really applies if the compiler can't optimize virtuals 
away. If the compiler was very good, then getting compiler errors 
would only make extending object structure a pain, IMO. I can see 
how one programmer might accidentally create a function with the 
same name as the base classes name, and how that would be 
annoying. That's why...



virtuals are a heinous crime, and should only be used
explicitly. It should not be possible for someone to 
accidentally create a virtual.


...I don't think having a virtual keyword would be a bad thing. 
Still, I think conceptually saying you _can't_ override this 
makes more sense than saying you _can_ override this when the 
biggest reason for using Classes is to build extendable object 
types.


I think at the end of the day both arguments are highly 
arbitrary. virtual and final keywords could probably exist 
peacefully, and wouldn't dent the learning curve by much, so I 
don't have any strong argument against virtual. It's just not the 
one I'd choose.





Re: virtual-by-default rant

2012-03-18 Thread Jacob Carlborg

On 2012-03-18 04:27, bearophile wrote:

F i L:


I'm a bit confused. Reading through the virtual function's docs
(http://dlang.org/function.html#virtual-functions) it says:

All non-static non-private non-template member functions are
virtual. This may sound inefficient, but since the D compiler
knows all of the class hierarchy when generating code, all
functions that are not overridden can be optimized to be
non-virtual.


This is so much theoretical that I think this should be removed from the D 
docs. And to be put back when one DMD compiler is able to do this. Otherwise 
it's just false advertising :-)


I agree that can be misleading. But I think the D docs should be about 
the D language and not DMD implementation of D.


--
/Jacob Carlborg


Re: virtual-by-default rant

2012-03-18 Thread Manu
On 18 March 2012 13:59, F i L witte2...@gmail.com wrote:

 Manu wrote:

 D knows nothing about the class hierarchy when generating code, I don't
 know how it can make that claim?


 How does D not know about class hierarchy when generating code? That
 doesn't make sense to me. It *has* to know to even generate code.


I mean it can't possibly know the complete 'final' class hierarchy, ie, the
big picture. Anything anywhere could extend it. The codegen must assume
such.


 Aside from that, I want a compile error if someone tries to randomly
 override stuff.


 This only really applies if the compiler can't optimize virtuals away. If
 the compiler was very good, then getting compiler errors would only make
 extending object structure a pain, IMO. I can see how one programmer might
 accidentally create a function with the same name as the base classes name,
 and how that would be annoying. That's why...


Are you saying someone might accidentally override something that's not
virtual? That's what 'override' is for. If a method is final, it is a
compile error to override in any way, you either need to make the base
virtual, or explicitly 'override' on the spot if you want to do that.


 virtuals are a heinous crime, and should only be used
 explicitly. It should not be possible for someone to accidentally create
 a virtual.


 ...I don't think having a virtual keyword would be a bad thing. Still, I
 think conceptually saying you _can't_ override this makes more sense than
 saying you _can_ override this when the biggest reason for using Classes
 is to build extendable object types.


I see it precisely the other way around. You still need strict control over
precisely HOW to extend that thing. The virtual methods are the exception,
not the common case. Explicit virtual even gives a nice informative cue to
the programmer just how they are supposed to work with/extend something.
You can clearly see what can/should to be extended.
Add to that the requirement for an advanced optimiser to clean up the mess
with LTO, and the fact a programmer can never have confidence in the final
state of the function, I want it the other way around.
I sincerely fear finding myself false-virtual hunting on build night until
2am trying to get the game to hold its frame rate (I already do this in
C++, but at least you can grep for and validate them!). Or cutting content
because we didn't take the time required to manually scan for false
virtuals that could have given us more frame time.

I think at the end of the day both arguments are highly arbitrary. virtual
 and final keywords could probably exist peacefully, and wouldn't dent the
 learning curve by much, so I don't have any strong argument against
 virtual. It's just not the one I'd choose.


You're welcome to it, but granted that, I have an additional fear that
someone with your opinion is capable of writing classes in libs that I
might really like to use, but can't, because they are a severe performance
hazard. It will be a shame if there is eventually a wealth of D libraries,
and only some of them are usable in realtime code because the majority of
programmers are blind to this problem. (Again, this is also common in C++.
I've encountered many libraries over the years that we had to reject, or
even more costly, remove later on after integrating and realising they were
unusable)


Re: virtual-by-default rant

2012-03-18 Thread deadalnix

Le 18/03/2012 02:23, Manu a écrit :

The virtual model broken. I've complained about it lots, and people
always say stfu, use 'final:' at the top of your class.

That sounds tolerable in theory, except there's no 'virtual' keyword to
keep the virtual-ness of those 1-2 virtual functions I have... so it's
no good (unless I rearrange my class, breaking the logical grouping of
stuff in it).
So I try that, and when I do, it complains: Error: variable
demu.memmap.MemMap.machine final cannot be applied to variable,
allegedly a D1 remnant.
So what do I do? Another workaround? Tag everything as final individually?

My minimum recommendation: D needs an explicit 'virtual' keyword, and to
fix that D1 bug, so putting final: at the top of your class works, and
everything from there works as it should.


This problem isn't virtual by default at all. It would just flip the 
problem around.


It just show the need of keyword to express the opposite of final, 
virtual. The same problem occur with const immutable, you cannot go back 
to the mutable world when you use « const: » for example.


Re: virtual-by-default rant

2012-03-18 Thread deadalnix

Le 18/03/2012 03:47, F i L a écrit :

I'm a bit confused. Reading through the virtual function's docs
(http://dlang.org/function.html#virtual-functions) it says:

All non-static non-private non-template member functions are virtual.
This may sound inefficient, but since the D compiler knows all of the
class hierarchy when generating code, all functions that are not
overridden can be optimized to be non-virtual.



The compiler can. But ATM, it doesn't.

This is an implementation issue, not a language design issue.


Re: virtual-by-default rant

2012-03-18 Thread F i L

Manu wrote:
I mean it can't possibly know the complete 'final' class 
hierarchy, ie, the
big picture. Anything anywhere could extend it. The codegen 
must assume

such.


I still don't understand why you think this. The compiler must 
understand the full hierarchy it's compiling, and like I said 
before, there are very distinct rules as to what should get 
virtualed across a lib boundary.



Are you saying someone might accidentally override something 
that's not
virtual? That's what 'override' is for. If a method is final, 
it is a
compile error to override in any way, you either need to make 
the base
virtual, or explicitly 'override' on the spot if you want to do 
that.


I was saying that I see how:

class Base { // author: Bob
void commonNamedMethod() {}
}

// ~

class Foo : Base { // author: Steve
// didn't look at base class, before writing:
void commonNamedMethod() {}
// therefor didn't realize he overwrote it
}

is a valid concern of having things default to virtual. I just 
don't think it would happen often, but I've been known to be 
wrong.




The virtual methods are the exception, not the common case.


I don't thinks it's so black and white, and that's why I like 
having the compiler make the optimization. I think marking 
(public) methods you know for sure who's functionality you don't 
want overwritten is often a smaller case than methods who's 
functionality could *potentially* be overwritten. By letting the 
compiler optimize un-overwritten methods, you're giving the Class 
users more freedom over the grey areas without sacrificing 
performances.


However, I also think the level of freedom is largely dependent 
on the situation. Given the fact that you write highly optimized 
and tightly controlled core game engine code, I can see why your 
perspective leans towards control.


Given this specialization unbalance, I think that both virtual 
and final should be available.




Explicit virtual even gives a nice informative cue to
the programmer just how they are supposed to work with/extend 
something. You can clearly see what can/should to be extended.


This is a good argument. If nothing else, I think there should be 
a way for Class authors to specify (in a way code-completion can 
understand) a method attribute which marks a it as being designed 
to be overwritten.



I sincerely fear finding myself false-virtual hunting on build 
night until
2am trying to get the game to hold its frame rate (I already do 
this in
C++, but at least you can grep for and validate them!). Or 
cutting content
because we didn't take the time required to manually scan for 
false

virtuals that could have given us more frame time.


I think tool that maps hierarchy (showing override) would be best.
like: dmd -hierarchymap.txt


You're welcome to it, but granted that, I have an additional 
fear that
someone with your opinion is capable of writing classes in libs 
that I
might really like to use, but can't, because they are a severe 
performance

hazard.


I would argue that any such performance critical libraries should 
be tightly finalized in the first place. I think you're 
assuming the compiler can't, in good faith, optimize out virtual 
functions. Whereas I'm assuming it can.




Re: virtual-by-default rant

2012-03-18 Thread David Nadlinger

On Sunday, 18 March 2012 at 13:54:20 UTC, F i L wrote:
[…] I think you're assuming the compiler can't, in good 
faith, optimize out virtual functions. Whereas I'm assuming it 
can.


Which is wrong as long as you don't do link-time optimization, 
and DMD probably won't in the foreseeable future. I tried to 
explain that above, think extending Thread, which has already 
been compiled into druntime, from your application (which is a 
bad example, because thread member method calls are most probably 
not performance sensitive, but you get the point).


That's just for the technical details, though, as far as the 
actual language design is concerned, I don't think virtual by 
default is an unreasonable choice.


David


Re: virtual-by-default rant

2012-03-18 Thread Dmitry Olshansky

On 18.03.2012 5:23, Manu wrote:

The virtual model broken. I've complained about it lots, and people
always say stfu, use 'final:' at the top of your class.

That sounds tolerable in theory, except there's no 'virtual' keyword to
keep the virtual-ness of those 1-2 virtual functions I have... so it's
no good (unless I rearrange my class, breaking the logical grouping of
stuff in it).
So I try that, and when I do, it complains: Error: variable
demu.memmap.MemMap.machine final cannot be applied to variable,
allegedly a D1 remnant.
So what do I do? Another workaround? Tag everything as final individually?

My minimum recommendation: D needs an explicit 'virtual' keyword, and to
fix that D1 bug, so putting final: at the top of your class works, and
everything from there works as it should.


Following this thread and observing that you don't trust optimizer and 
compiler in many cases or have to double check them anyway, I have a 
suggestion: do virtual dispatch by hand via func-pointer table and use 
structs.


I'm serious, with a bit of metaprogramming it wouldn't be half bad, and 
as a bonus you don't have to pay for a monitor field per object as 
classes do, and in general less compiler magic to keep track of. You 
also gain the ability to fine tune their layout, the performance maniac 
side of yours must see the potential it brings :)


And since you have a few of virtuals anyway and keep them in constant 
check it should be double and be much less of a hassle then hunting down 
and second-guessing the compiler on every single step.


Bottom line thought: there is a point when a given feature doesn't bring 
significant convenience for a specific use case, it's then better to 
just stop pushing it over.


--
Dmitry Olshansky


Re: virtual-by-default rant

2012-03-18 Thread David Nadlinger

On Sunday, 18 March 2012 at 14:27:04 UTC, David Nadlinger wrote:
Which is wrong as long as you don't do link-time optimization, 
and DMD probably won't in the foreseeable future. I tried to 
explain that above, think extending Thread, which has already 
been compiled into druntime, from your application (which is a 
bad example, because thread member method calls are most 
probably not performance sensitive, but you get the point).


Also note that this applies to the general case where you get 
passed in an arbitrary instance only – if the place where an 
object is created is in the same translation unit where its 
methods are invoked, the compiler _might_ be able to prove the 
runtime type of the instance even without LTO.


David


Re: virtual-by-default rant

2012-03-18 Thread David Nadlinger

On Sunday, 18 March 2012 at 14:46:55 UTC, David Nadlinger wrote:

On Sunday, 18 March 2012 at 14:27:04 UTC, David Nadlinger wrote:
Which is wrong as long as you don't do link-time optimization, 
and DMD probably won't in the foreseeable future. I tried to 
explain that above, think extending Thread, which has already 
been compiled into druntime, from your application (which is a 
bad example, because thread member method calls are most 
probably not performance sensitive, but you get the point).


Also note that this applies to the general case where you get 
passed in an arbitrary instance only – if the place where an 
object is created is in the same translation unit where its 
methods are invoked, the compiler _might_ be able to prove the 
runtime type of the instance even without LTO.


And thinking even more about it, devirtualization could also be 
performed by present-day DMD when directly generating an 
executable with all the modules being passed in via at the 
command line. This might actually be good enough for smaller 
projects which don't use separate libraries or incremental 
compilation.


David




Re: virtual-by-default rant

2012-03-18 Thread Andrei Alexandrescu

On 3/18/12 6:37 AM, Manu wrote:

On 18 March 2012 06:42, Andrei Alexandrescu
seewebsiteforem...@erdani.org
mailto:seewebsiteforem...@erdani.org wrote:
Then probably struct is what you're looking for.


No, I definitely want a class. ref type, gc mem, etc.
struct doesn't support virtual at all. I have 2 virtuals, this
particular class has around 50 public methods, almost all of which are
trivial accessors, called extremely heavily in hot loops. More similar
classes to come.


Then perhaps it's a good idea to move accessors outside and take 
advantage of UFCS.



I've never in 15 years seen a large-ish class where the majority of
methods are virtual. Who writes code like that? It's never come up in
my industry at least.


I consider thick interfaces and shallow hierarchies good design. An 
interface that's too small invites inherit to extend approaches and 
casts. The fact that Java made extend a keyword that really means 
narrow is quite ironic.



Andrei




Re: virtual-by-default rant

2012-03-18 Thread Andrei Alexandrescu

On 3/18/12 6:59 AM, F i L wrote:

Manu wrote:

D knows nothing about the class hierarchy when generating code, I
don't know how it can make that claim?


How does D not know about class hierarchy when generating code? That
doesn't make sense to me. It *has* to know to even generate code.


It knows about ancestors of each type but not about descendants.

Andrei



Re: virtual-by-default rant

2012-03-18 Thread Andrei Alexandrescu

On 3/18/12 8:39 AM, deadalnix wrote:

It just show the need of keyword to express the opposite of final,
virtual. The same problem occur with const immutable, you cannot go back
to the mutable world when you use « const: » for example.


Yah, ~const etc. have been suggested a couple of times. Helps casts too.

Andrei


Re: virtual-by-default rant

2012-03-18 Thread deadalnix

Le 18/03/2012 16:26, Andrei Alexandrescu a écrit :

On 3/18/12 8:39 AM, deadalnix wrote:

It just show the need of keyword to express the opposite of final,
virtual. The same problem occur with const immutable, you cannot go back
to the mutable world when you use « const: » for example.


Yah, ~const etc. have been suggested a couple of times. Helps casts too.

Andrei


This seems definitively an issue to me. ~const/~final, or 
mutable/virtual would be a huge benefice to the « : » syntax. And youa 
re right, it is also a big plus for casting. I would argue for teh last 
one, especially for the const case, because mutable oppose to both const 
and immutable, so it isn't the opposite of const.


The case is very similar to public/private/protected, and each have it's 
own keyword, and it doesn't seems armful.


Note that the same issue exist for shared (but that one doesn't work 
anyway).


Re: virtual-by-default rant

2012-03-18 Thread Martin Nowak
This is so much theoretical that I think this should be removed from  
the D docs. And to be put back when one DMD compiler is able to do  
this. Otherwise it's just false advertising :-)


Is this even possible without LTO/WPO? Extending a class defined in a  
library you link in (and for which codegen already happened) is  
certainly possible…


David


This is not even possible with LTO because new classes
could be loaded at runtime.
Could somebody please fix this.


Re: virtual-by-default rant

2012-03-18 Thread deadalnix

Le 18/03/2012 17:02, Martin Nowak a écrit :

This is so much theoretical that I think this should be removed from
the D docs. And to be put back when one DMD compiler is able to do
this. Otherwise it's just false advertising :-)


Is this even possible without LTO/WPO? Extending a class defined in a
library you link in (and for which codegen already happened) is
certainly possible…

David


This is not even possible with LTO because new classes
could be loaded at runtime.
Could somebody please fix this.


That is limited to export classes. In this case, final/virtual should be 
managed very precisely anyway if performance matter.


Re: virtual-by-default rant

2012-03-18 Thread David Nadlinger

On Sunday, 18 March 2012 at 16:02:04 UTC, Martin Nowak wrote:
Is this even possible without LTO/WPO? Extending a class 
defined in a library you link in (and for which codegen 
already happened) is certainly possible…


David


This is not even possible with LTO because new classes
could be loaded at runtime.


Sure, you can't just devirtualize everything you come across even 
with LTO, but it greatly increases the portion of calls where you 
can deduce the actual type of an instance.


David



Re: virtual-by-default rant

2012-03-18 Thread F i L

David Nadlinger wrote:
Which is wrong as long as you don't do link-time optimization, 
and DMD probably won't in the foreseeable future.


Are GDC and LDC limited by DMD in this regard? I know LDC has a 
LTO flag.


If GDC/LDC supports LTO and/or DMD will in the eventual future, 
then I think defaulting to final is best. If you're saying that 
even with LTO you wouldn't be able to do automatic 
de-virtualization ever, then I think Manu might be right in 
saying the model is backwards. I don't know enough about LTO to 
comment either way though.


FeepingCreature wrote:

class Foo : Bar final {
}

as alternative syntax for

class Foo : Bar { final {
} }

Advantages: internally consistent, no need for completely new 
syntax, final class can be deprecated (it never worked well 
anyway).


Alternate aspects of this syntax change:

void foo(ObjectThing ot, int a, int b) with (ot) {
}

void bar() synchronized {
}


+1 This syntax makes a lot of sense.



Re: virtual-by-default rant

2012-03-18 Thread David Nadlinger

On Sunday, 18 March 2012 at 17:24:15 UTC, F i L wrote:

[…] I know LDC has a  LTO flag.


Unfortunately it doesn't (-O4/-O5 are defunct), but working on 
seamless LTO integration (and better optimization pass scheduling 
in general) would be low-hanging fruit for anybody wanting to 
join LDC development.


David


Re: virtual-by-default rant

2012-03-18 Thread James Miller
On 19 March 2012 06:41, David Nadlinger s...@klickverbot.at wrote:
 On Sunday, 18 March 2012 at 17:24:15 UTC, F i L wrote:

 […] I know LDC has a  LTO flag.


 Unfortunately it doesn't (-O4/-O5 are defunct), but working on seamless LTO
 integration (and better optimization pass scheduling in general) would be
 low-hanging fruit for anybody wanting to join LDC development.

 David

I think that simply adding a `virtual` keyword that explicitly makes
things virtual, even if they would otherwise be final, makes sense.
Keep all the current semantics the same, relegate use of `virtual` to
the 'advanced' section of D usage, everybody is happy.

I'm with Manu in the case of I don't trust the compiler. I'm
perfectly happy for the compile to optimize short sections of code
that I probably could optimize myself, but its not much of an issue,
but I am reluctant to rely on the tooling to make decisions for me.
For small programs, where it doesn't matter if it's half as fast as it
could be, but that just means 2ms vs 1ms, I don't care. But in
intensive programs, then I want to be sure that the compiler will do
what I want.

--
James Miller


Re: virtual-by-default rant

2012-03-18 Thread Artur Skawina
On 03/18/12 15:37, Dmitry Olshansky wrote:
 On 18.03.2012 5:23, Manu wrote:
 The virtual model broken. I've complained about it lots, and people
 always say stfu, use 'final:' at the top of your class.

 That sounds tolerable in theory, except there's no 'virtual' keyword to
 keep the virtual-ness of those 1-2 virtual functions I have... so it's
 no good (unless I rearrange my class, breaking the logical grouping of
 stuff in it).
 So I try that, and when I do, it complains: Error: variable
 demu.memmap.MemMap.machine final cannot be applied to variable,
 allegedly a D1 remnant.
 So what do I do? Another workaround? Tag everything as final individually?

 My minimum recommendation: D needs an explicit 'virtual' keyword, and to
 fix that D1 bug, so putting final: at the top of your class works, and
 everything from there works as it should.
 
 Following this thread and observing that you don't trust optimizer and 
 compiler in many cases or have to double check them anyway, I have a 
 suggestion: do virtual dispatch by hand via func-pointer table and use 
 structs.
 
 I'm serious, with a bit of metaprogramming it wouldn't be half bad, and as a 
 bonus you don't have to pay for a monitor field per object as classes do, and 
 in general less compiler magic to keep track of. You also gain the ability to 
 fine tune their layout, the performance maniac side of yours must see the 
 potential it brings :)

I was going to suggest the very same thing - but there are (at least) two 
problems
with that approach:

1) pass-by-value -- it's dangerous, ugly to work-around (and compiler bugs don't
   help, like the one where just having a this(this) causes problems); the 
   workarounds also have compiler/ABI issues (like the 'File' case posted in 
D.learn
   some time ago, or GDC not passing/returning the pseudo-refs in registers)
2) no inheritance. ie 'struct A{}; struct B{A super; alias super this;}' cannot 
be
   written as just 'struct B:A {}' - which would not be just syntax sugar, but 
also
   allow (more) implicit conversions, (explicit) function overrides etc.

So - yes, D structs should be enough for everything, but right now they're still
missing some required basic features. Ideally class would just be sugar, and
everything should be expressible using just structs - obviously in a much more
verbose, but 100% compatible way (incl vtables, monitors etc)

After all, real programmers don't use classes. :)

artur


virtual-by-default rant

2012-03-17 Thread Manu
The virtual model broken. I've complained about it lots, and people always
say stfu, use 'final:' at the top of your class.

That sounds tolerable in theory, except there's no 'virtual' keyword to
keep the virtual-ness of those 1-2 virtual functions I have... so it's no
good (unless I rearrange my class, breaking the logical grouping of stuff
in it).
So I try that, and when I do, it complains: Error: variable
demu.memmap.MemMap.machine final cannot be applied to variable, allegedly
a D1 remnant.
So what do I do? Another workaround? Tag everything as final individually?

My minimum recommendation: D needs an explicit 'virtual' keyword, and to
fix that D1 bug, so putting final: at the top of your class works, and
everything from there works as it should.


Re: virtual-by-default rant

2012-03-17 Thread Bernard Helyer

On Sunday, 18 March 2012 at 01:23:42 UTC, Manu wrote:
My minimum recommendation: D needs an explicit 'virtual' 
keyword, and to
fix that D1 bug, so putting final: at the top of your class 
works, and

everything from there works as it should.


Agreed. Final by default is a proposition long gone, but that 
seems reasonable.


Re: virtual-by-default rant

2012-03-17 Thread Simen Kjærås

On Sun, 18 Mar 2012 02:23:31 +0100, Manu turkey...@gmail.com wrote:

The virtual model broken. I've complained about it lots, and people  
always

say stfu, use 'final:' at the top of your class.

That sounds tolerable in theory, except there's no 'virtual' keyword to
keep the virtual-ness of those 1-2 virtual functions I have... so it's no
good (unless I rearrange my class, breaking the logical grouping of stuff
in it).
So I try that, and when I do, it complains: Error: variable
demu.memmap.MemMap.machine final cannot be applied to variable,  
allegedly

a D1 remnant.
So what do I do? Another workaround? Tag everything as final  
individually?


class Foo {
final {
// Final functions here.
}
// Virtual functions here.
}

Good?



My minimum recommendation: D needs an explicit 'virtual' keyword, and to
fix that D1 bug, so putting final: at the top of your class works, and
everything from there works as it should.


I agree that a virtual keyword would sometimes be a boon. With the solution
outlined above, I find it a minor nit, though.


Re: virtual-by-default rant

2012-03-17 Thread Walter Bright

On 3/17/2012 6:23 PM, Manu wrote:

Tag everything as final individually?


You can use:

final
{
... all the final members ...
}

instead of individual tags.


Re: virtual-by-default rant

2012-03-17 Thread Manu
On 18 March 2012 03:49, Simen Kjærås simen.kja...@gmail.com wrote:

 On Sun, 18 Mar 2012 02:23:31 +0100, Manu turkey...@gmail.com wrote:

  The virtual model broken. I've complained about it lots, and people always
 say stfu, use 'final:' at the top of your class.

 That sounds tolerable in theory, except there's no 'virtual' keyword to
 keep the virtual-ness of those 1-2 virtual functions I have... so it's no
 good (unless I rearrange my class, breaking the logical grouping of stuff
 in it).
 So I try that, and when I do, it complains: Error: variable
 demu.memmap.MemMap.machine final cannot be applied to variable, allegedly
 a D1 remnant.
 So what do I do? Another workaround? Tag everything as final individually?


 class Foo {
final {
// Final functions here.
}
// Virtual functions here.
 }

 Good?


Ah, didn't think of braces... got stuck on the ':' approach.
That's no less ugly though, in fact, it's considerably more ugly. more
brace spam + indentation levels for nothing.


My minimum recommendation: D needs an explicit 'virtual' keyword, and to
 fix that D1 bug, so putting final: at the top of your class works, and
 everything from there works as it should.


 I agree that a virtual keyword would sometimes be a boon. With the solution
 outlined above, I find it a minor nit, though.


I'm still mortified that people won't do it or just forget, and every
method ever will be virtual.


Re: virtual-by-default rant

2012-03-17 Thread F i L

On Sunday, 18 March 2012 at 01:23:42 UTC, Manu wrote:
The virtual model broken. I've complained about it lots, and 
people always

say stfu, use 'final:' at the top of your class.

That sounds tolerable in theory, except there's no 'virtual' 
keyword to
keep the virtual-ness of those 1-2 virtual functions I have... 
so it's no
good (unless I rearrange my class, breaking the logical 
grouping of stuff

in it).
So I try that, and when I do, it complains: Error: variable
demu.memmap.MemMap.machine final cannot be applied to 
variable, allegedly

a D1 remnant.
So what do I do? Another workaround? Tag everything as final 
individually?


My minimum recommendation: D needs an explicit 'virtual' 
keyword, and to
fix that D1 bug, so putting final: at the top of your class 
works, and

everything from there works as it should.


what's so bad with:

   class Test
   {
   final {
   void nonVirtualMethod1() { ... }
   void nonVirtualMethod2() { ... }
   void nonVirtualMethod3() { ... }
   void nonVirtualMethod4() { ... }
   }

   void virtualMethod1() { ... }
   void virtualMethod2() { ... }
   }

I actually think this model makes a lot of sense because when
you're starting out with just an object concept, explicitly
specifying these functions I don't want overridden on the few
you're positive you don't want final is, at least to me, more
inline with how my thought process works. Optimize after the
object model is more concrete.

However, I don't think that having the option of doing it in
reverse would be a bad idea either:

   // dmd -explicitVirtual test.d

   class Test
   {
   void nonVirtualMethod1() { ... }
   void nonVirtualMethod2() { ... }
   void nonVirtualMethod3() { ... }
   void nonVirtualMethod4() { ... }

   virtual {
   void virtualMethod1() { ... }
   void virtualMethod2() { ... }
   }
   }


Re: virtual-by-default rant

2012-03-17 Thread F i L

F i L wrote:

specifying these functions I don't want overridden on the few
you're positive you don't want final is...


**you're positive you *DO* want final is...




Re: virtual-by-default rant

2012-03-17 Thread F i L

Manu wrote:
That's no less ugly though, in fact, it's considerably more 
ugly. more

brace spam + indentation levels for nothing.


I actually like the bracket+indentation as a section separator 
indicator. Usually I'll group fields/methods by common 
attribute:


class Window
{
private {
string _title;
int _x, _y;
// etc...
}

@property {
auto title() { return _title; }
auto x() { return _x; }
auto y() { return _y; }
// etc...
}
}

// Or...

struct Vector2(T)
{
T x, y;

@property {
auto xy() { return this; }
auto yx() { return Vector2(y, x); }
}

@property static {
auto zero() { return Vector2(0, 0); }
auto one()  { return Vector2(1, 1); }
// etc...
}
}

But I'm also use to C# code which is usually indented twice 
before you even get to functions (namespace - class - method).


Re: virtual-by-default rant

2012-03-17 Thread Manu
On 18 March 2012 04:14, F i L witte2...@gmail.com wrote:

 Manu wrote:

 That's no less ugly though, in fact, it's considerably more ugly. more
 brace spam + indentation levels for nothing.


 I actually like the bracket+indentation as a section separator indicator.
 Usually I'll group fields/methods by common attribute:

class Window
{
private {
string _title;
int _x, _y;
// etc...
}

@property {
auto title() { return _title; }
auto x() { return _x; }
auto y() { return _y; }
// etc...
}
}

// Or...

struct Vector2(T)
{
T x, y;

@property {
auto xy() { return this; }
auto yx() { return Vector2(y, x); }
}

@property static {
auto zero() { return Vector2(0, 0); }
auto one()  { return Vector2(1, 1); }
// etc...
}
}

 But I'm also use to C# code which is usually indented twice before you
 even get to functions (namespace - class - method).


Yeah, I'm not really into that. I group things conceptually.
Either way, I've never written a class where non-virtuals don't outweigh
virtuals in the realm of 20:1. There needs to be a way to declare it the
other way around without polluting my indentation levels.
final: at the top and explicit 'virtual' would make a big difference.


Re: virtual-by-default rant

2012-03-17 Thread F i L
I'm a bit confused. Reading through the virtual function's docs 
(http://dlang.org/function.html#virtual-functions) it says:


All non-static non-private non-template member functions are 
virtual. This may sound inefficient, but since the D compiler 
knows all of the class hierarchy when generating code, all 
functions that are not overridden can be optimized to be 
non-virtual.


So if all functions are automatically optimized to non-virtual 
where applicable, then the final keyword is for conceptual 
access limitation only. This makes a lot of sense to me. Is there 
something I'm not getting that makes you want an explicit 
virtual keyword?


Re: virtual-by-default rant

2012-03-17 Thread bearophile
F i L:

 I'm a bit confused. Reading through the virtual function's docs 
 (http://dlang.org/function.html#virtual-functions) it says:
 
 All non-static non-private non-template member functions are 
 virtual. This may sound inefficient, but since the D compiler 
 knows all of the class hierarchy when generating code, all 
 functions that are not overridden can be optimized to be 
 non-virtual.

This is so much theoretical that I think this should be removed from the D 
docs. And to be put back when one DMD compiler is able to do this. Otherwise 
it's just false advertising :-)

Bye,
bearophile


Re: virtual-by-default rant

2012-03-17 Thread F i L

On Sunday, 18 March 2012 at 03:27:40 UTC, bearophile wrote:

F i L:

I'm a bit confused. Reading through the virtual function's 
docs (http://dlang.org/function.html#virtual-functions) it 
says:


All non-static non-private non-template member functions are 
virtual. This may sound inefficient, but since the D compiler 
knows all of the class hierarchy when generating code, all 
functions that are not overridden can be optimized to be 
non-virtual.


This is so much theoretical that I think this should be removed 
from the D docs. And to be put back when one DMD compiler is 
able to do this. Otherwise it's just false advertising :-)


Bye,
bearophile


Dammit, I was afraid someone would say something like that. Well 
at least it's a good goal. It is a bit of false advertising 
though, honestly it should just be marked implementation in 
progress or something like that.




Re: virtual-by-default rant

2012-03-17 Thread Andrei Alexandrescu

On 3/17/12 9:24 PM, Manu wrote:

Yeah, I'm not really into that. I group things conceptually.
Either way, I've never written a class where non-virtuals don't outweigh
virtuals in the realm of 20:1.


Then probably struct is what you're looking for.

Andrei