March 18, 2012
On 3/18/12, deadalnix <deadalnix@gmail.com> wrote:
> Le 18/03/2012 17:49, Timon Gehr a écrit :
>> On 03/18/2012 05:25 PM, FeepingCreature wrote:
>>>
>>> Advantages: internally consistent, no need for completely new syntax, "final class" can be deprecated (it never worked well anyway).
>>>
>>
>> final class means that the class cannot be inherited from.
>
> What is the point to inherit is no virtual method exists ?
>

Final classes might be useful for e.g. leaf classes.
March 18, 2012
On 19 March 2012 06:41, David Nadlinger <see@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
March 18, 2012
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
March 19, 2012
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
March 19, 2012
Le 18/03/2012 18:06, Simen Kjærås a écrit :
> On Sun, 18 Mar 2012 18:07:10 +0100, deadalnix <deadalnix@gmail.com> wrote:
>
>> Le 18/03/2012 17:49, Timon Gehr a écrit :
>>> On 03/18/2012 05:25 PM, FeepingCreature wrote:
>>>>
>>>> Advantages: internally consistent, no need for completely new syntax,
>>>> "final class" can be deprecated (it never worked well anyway).
>>>>
>>>
>>> final class means that the class cannot be inherited from.
>>
>> What is the point to inherit is no virtual method exists ?
>
> Access to protected members.

That is a reason, but I never saw that except for dirty hacks :D
March 19, 2012
Le 18/03/2012 19:57, Andrej Mitrovic a écrit :
> On 3/18/12, deadalnix<deadalnix@gmail.com>  wrote:
>> Le 18/03/2012 17:49, Timon Gehr a écrit :
>>> On 03/18/2012 05:25 PM, FeepingCreature wrote:
>>>>
>>>> Advantages: internally consistent, no need for completely new syntax,
>>>> "final class" can be deprecated (it never worked well anyway).
>>>>
>>>
>>> final class means that the class cannot be inherited from.
>>
>> What is the point to inherit is no virtual method exists ?
>>
>
> Final classes might be useful for e.g. leaf classes.

This doesn't address the question.
March 19, 2012
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
March 19, 2012
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 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


-- 
Dmitry Olshansky
March 19, 2012
Having a final class is conceptually different from having a class with only final methods. You can legitimately inherit from a class with no virtual methods and add to its interface and implement other methods using its final ones. The final class concept is extremely useful when you just don't want to be inherited from. For instance, Your class may be closely tied to an implementation and inheriting from it would wreck the implementation.

On Mon, Mar 19, 2012 at 2:04 PM, deadalnix <deadalnix@gmail.com> wrote:
> Le 18/03/2012 18:06, Simen Kjærås a écrit :
>>
>> On Sun, 18 Mar 2012 18:07:10 +0100, deadalnix <deadalnix@gmail.com> wrote:
>>
>>> Le 18/03/2012 17:49, Timon Gehr a écrit :
>>>>
>>>> On 03/18/2012 05:25 PM, FeepingCreature wrote:
>>>>>
>>>>>
>>>>> Advantages: internally consistent, no need for completely new syntax, "final class" can be deprecated (it never worked well anyway).
>>>>>
>>>>
>>>> final class means that the class cannot be inherited from.
>>>
>>>
>>> What is the point to inherit is no virtual method exists ?
>>
>>
>> Access to protected members.
>
>
> That is a reason, but I never saw that except for dirty hacks :D



-- 
Bye,
Gor Gyolchanyan.
March 19, 2012
Le 19/03/2012 14:38, Gor Gyolchanyan a écrit :
> Having a final class is conceptually different from having a class
> with only final methods. You can legitimately inherit from a class
> with no virtual methods and add to its interface and implement other
> methods using its final ones. The final class concept is extremely
> useful when you just don't want to be inherited from. For instance,
> Your class may be closely tied to an implementation and inheriting
> from it would wreck the implementation.
>

It looks like a bad usage of inheritance. If you want to use these methods, why not use composition ?

It make no sense to use such an inherited class in a polymorphic context, so why use inheritance at all ?