Sealed classes and methods

Revision as of 11:38, 2 June 2023 by PureFox (talk | contribs) (Created a new draft task and added a Wren example.)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

In object-oriented programming, a sealed or final class is one which cannot be inherited from.

Sealed classes and methods is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
Definition

Classes are sometimes made non-subclasssable in this way if the author feels that it would not be useful or even undesirable for subclasses to be created from them. Moreover, in a compiled language, knowing that a class cannot be subclassed, may enable optimizations to be made.

Rather than sealing the entire class, it may be possible to just seal certain 'public' methods for the same reasons and with the same potential benefits. 'private' methods should be effectively sealed anyway.

Task

If your language supports the object oriented paradigm, explain what support it has for sealed classes and/or methods and, if there is no support, what if anything can be done to simulate them. If possible illustrate your answer with an example.

If your language does not support the object oriented paradigm (or its inheritance aspect), you may either simply say so, omit the task altogether or describe any equivalent structure(s) and restrictions on use which the language does have.

Reference
Related task

Wren

Although Wren is an object-oriented language, it does not support sealed classes or methods. Nor does it have 'private' methods. All instance methods (though not constructors or static methods) are automatically inherited by subclasses.

It might be argued that such a restriction would be out of place anyway in a simple embedded scripting language, particularly when libraries can only be distributed in source code form at the present time.

Nevertheless, it is possible to simulate sealed methods by simply stopping them from executing normally at runtime unless they are being accessed by an object of the same class. In fact, as the following example shows, this technique allows methods to be conditionally (rather than absolutely) sealed where the circumstances warrant this.

Note that:

1. To seal the entire class one would need to apply the same technique to all instance methods though this would be very tedious in practice for classes having a lot of methods.

2. With the exception of Object and Sequence, it is not possible to inherit from Wren's built-in classes anyway for technical reasons. Nor is it possible to inherit from 'foreign' classes i.e. classes which are instantiated from C rather than Wren.

3. Using the 'is' operator (i.e. a is C) to detect the type of 'a' wouldn't work here as this would return 'true' if 'a' were either a 'C' object or an object of a subclass of 'C'. It is possible to spoof the 'is' operator by overriding its normal behavior, though this is definitely not recommended!

class Parent {
    construct new(name, age) {
        _name = name
        _age  = age
    }

    watchMovie() {
        if (this.type != Parent && _age < 15) {
            System.print("Sorry, %(_name), you are too young to watch the movie.")
        } else {
            System.print("%(_name) is watching the movie...")
        }
    }
}

class Child is Parent {
    construct new(name, age) {
        super(name, age)
    }
}

var p = Parent.new("Donald", 42)
p.watchMovie()

var c1 = Child.new("Lisa", 18)
var c2 = Child.new("Fred", 10)
c1.watchMovie()
c2.watchMovie()
Output:
Donald is watching the movie...
Lisa is watching the movie...
Sorry, Fred, you are too young to watch the movie.