www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - A Modest Proposal: Final class instances

reply dsimcha <dsimcha yahoo.com> writes:
Several people have griped in the past that D class methods are virtual by
default.  I've pointed out to them that you can get around this by making the
methods final.  However, this is a bit of a blunt instrument, because some use
cases for a single class may call for polymorphism and other use cases for the
same class may call for fast performance and no polymorphism.  A possible
solution is, given a class:

class Foo {
    // Actual implementation.
}

final class FooFinal : Foo{
    // Dummy that just makes Foo final.
}

And then, when you need performance and not polymorphism, you would invoke
FooFinal instead of Foo.  However, this requires manual forwarding of
constructors and bloats the name space.  A simple syntactic sugar solution to
this dilemma that would add very little complexity to the language would be to
allow final to describe a class instance, as well as a class.  The following
would apply to a final instance:

1.  Method calls don't need to be virtual.
2.  An instance of a subclass cannot be converted to a final instance of the
base class.
3.  A final instance can be implicitly converted to a non-final instance, but
the opposite would not work.

Using final as an instance attribute like this would also allow another useful
feature:  Storing class instances inline in arrays, structs, or other classes.
 Basically, by marking a class instance as final, you'd be telling the
compiler that you do not need and are not using polymorphism in this case,
even if the class hierarchy uses it for other use cases, and therefore, all
relevant optimizations can be made.
May 04 2009
next sibling parent Jason House <jason.james.house gmail.com> writes:
IMHO, this proposal does not go far enough. THose that worry about performance
also care about object size. If a vtable or monitor are needed, then people
will still avoid classes for performance.

dsimcha Wrote:

 Several people have griped in the past that D class methods are virtual by
 default.  I've pointed out to them that you can get around this by making the
 methods final.  However, this is a bit of a blunt instrument, because some use
 cases for a single class may call for polymorphism and other use cases for the
 same class may call for fast performance and no polymorphism.  A possible
 solution is, given a class:
 
 class Foo {
     // Actual implementation.
 }
 
 final class FooFinal : Foo{
     // Dummy that just makes Foo final.
 }
 
 And then, when you need performance and not polymorphism, you would invoke
 FooFinal instead of Foo.  However, this requires manual forwarding of
 constructors and bloats the name space.  A simple syntactic sugar solution to
 this dilemma that would add very little complexity to the language would be to
 allow final to describe a class instance, as well as a class.  The following
 would apply to a final instance:
 
 1.  Method calls don't need to be virtual.
 2.  An instance of a subclass cannot be converted to a final instance of the
 base class.
 3.  A final instance can be implicitly converted to a non-final instance, but
 the opposite would not work.
 
 Using final as an instance attribute like this would also allow another useful
 feature:  Storing class instances inline in arrays, structs, or other classes.
  Basically, by marking a class instance as final, you'd be telling the
 compiler that you do not need and are not using polymorphism in this case,
 even if the class hierarchy uses it for other use cases, and therefore, all
 relevant optimizations can be made.

May 05 2009
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
dsimcha wrote:
 A possible
 solution is, given a class:
 
 class Foo {
     // Actual implementation.
 }
 
 final class FooFinal : Foo{
     // Dummy that just makes Foo final.
 }

With dmd: final class A { } class B : A { } Compiling: test.d(2): Error: class test.B cannot inherit from final class A
May 05 2009
parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 dsimcha wrote:
 A possible
 solution is, given a class:

 class Foo {
     // Actual implementation.
 }

 final class FooFinal : Foo{
     // Dummy that just makes Foo final.
 }

final class A { } class B : A { } Compiling: test.d(2): Error: class test.B cannot inherit from final class A

Uh...I think you misread this. I was inheriting from a non-final class to make it final, not the other way around.
May 05 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
dsimcha wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 dsimcha wrote:
 A possible
 solution is, given a class:

 class Foo {
     // Actual implementation.
 }

 final class FooFinal : Foo{
     // Dummy that just makes Foo final.
 }

final class A { } class B : A { } Compiling: test.d(2): Error: class test.B cannot inherit from final class A

Uh...I think you misread this. I was inheriting from a non-final class to make it final, not the other way around.

Since all classes inherit from Object, this does indeed do what you asked for. Try it. You'll find it "finalizes" the class. I'd also suggest trying out some calls to virtual functions in a final class, and running the result through obj2asm to see what happens.
May 05 2009
parent div0 <div0 users.sourceforge.net> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Walter Bright wrote:
 dsimcha wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 dsimcha wrote:
 A possible
 solution is, given a class:

 class Foo {
     // Actual implementation.
 }

 final class FooFinal : Foo{
     // Dummy that just makes Foo final.
 }

final class A { } class B : A { } Compiling: test.d(2): Error: class test.B cannot inherit from final class A

Uh...I think you misread this. I was inheriting from a non-final class to make it final, not the other way around.

Since all classes inherit from Object, this does indeed do what you asked for. Try it. You'll find it "finalizes" the class. I'd also suggest trying out some calls to virtual functions in a final class, and running the result through obj2asm to see what happens.

Hey thats great. Now all we need is the 'virtual' keyword to go with some the methods of the final class... :O -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFKAJy0T9LetA9XoXwRAl0sAJ41lAoVEz9iYJZvfr2Cn9yl7ZNBwgCgxXGB MI+3ICSwL7OGMRx0Nd2c+2c= =uClG -----END PGP SIGNATURE-----
May 05 2009
prev sibling next sibling parent BCS <ao pathlink.com> writes:
Reply to dsimcha,

 Several people have griped in the past that D class methods are
 virtual by default.  I've pointed out to them that you can get around
 this by making the methods final.  However, this is a bit of a blunt
 instrument, because some use cases for a single class may call for
 polymorphism and other use cases for the same class may call for fast
 performance and no polymorphism.  A possible solution is, given a
 class:
 
 class Foo {
 // Actual implementation.
 }
 final class FooFinal : Foo{
 // Dummy that just makes Foo final.
 }
 And then, when you need performance and not polymorphism, you would
 invoke FooFinal instead of Foo.  However, this requires manual
 forwarding of constructors and bloats the name space.  A simple
 syntactic sugar solution to this dilemma that would add very little
 complexity to the language would be to allow final to describe a class
 instance, as well as a class.  The following would apply to a final
 instance:
 
 1.  Method calls don't need to be virtual.
 2.  An instance of a subclass cannot be converted to a final instance
 of the
 base class.
 3.  A final instance can be implicitly converted to a non-final
 instance, but
 the opposite would not work.
 Using final as an instance attribute like this would also allow
 another useful
 feature:  Storing class instances inline in arrays, structs, or other
 classes.
 Basically, by marking a class instance as final, you'd be telling the
 compiler that you do not need and are not using polymorphism in this
 case,
 even if the class hierarchy uses it for other use cases, and
 therefore, all relevant optimizations can be made.
 

You can't make an instance final without creating a new type (code bloat) because even if you can generate non virtual calls into the object, interior calls will still be virtual. One solution to this would be to rerun the code gen for the classes methods (and all base class methods) without virtual calls. OTOH you could do that for even non-final types: generate a set of methods with (where possible) non-virtual internal calls (that could require re-running the code gen on base class methods) that is used only for this class and a set with virtual calls for types that derive from it. This would result in a lot more code but it could (depending on usage) be a lot faster code.
May 05 2009
prev sibling parent Stewart Gordon <smjg_1998 yahoo.com> writes:
dsimcha wrote:
<snip>
 1.  Method calls don't need to be virtual.
 2.  An instance of a subclass cannot be converted to a final instance of the
 base class.
 3.  A final instance can be implicitly converted to a non-final instance, but
 the opposite would not work.
 
 Using final as an instance attribute like this would also allow another useful
 feature:  Storing class instances inline in arrays, structs, or other classes.
  Basically, by marking a class instance as final, you'd be telling the
 compiler that you do not need and are not using polymorphism in this case,
 even if the class hierarchy uses it for other use cases, and therefore, all
 relevant optimizations can be made.

So the class would be contained by value, and method calls would bypass the vtable. Effectively, the class would become more like a struct in these instances. There are two difficulties I can see: - either the final instance would still need a vtable to support methods calling each other, or there'd have to be internally two versions of each method - containment by value means that one would have to deal with copying of instances, in ways that you wouldn't have to worry about if you were using the same class normally. Stewart.
May 05 2009