Re: virtual-by-default rant
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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