Sealed classes and methods: Difference between revisions

From Rosetta Code
Content added Content deleted
(Created a new draft task and added a Wren example.)
 
Line 21: Line 21:
* [[Inheritance/Single]]
* [[Inheritance/Single]]
* [[Inheritance/Multiple]]
* [[Inheritance/Multiple]]

=={{header|Phix}}==
No support, though it would probably not be particularly difficult to add a "final" keyword if ever needed.<br>
Phix supports object orientation for the die-hards (desktop/Phix only), but does not require it be used at all.<br>
In Phix, "private" determines availability from outside [sub-]class code, but there is nothing at all to prevent Child from
having a public method that (internally) invokes a private method of the Parent, and of course/not unlike it would make no difference were name and age made private below.<br>
The Phix compiler can make exactly the same optimisations were it to spot at EOF that a class has not been overidden
as it could were it told up-front.
{{trans|Wren}}
Extended to include an under-age parent
<!--<syntaxhighlight lang="phix">(notonline)-->
<span style="color: #008080;">without</span> <span style="color: #008080;">javascript_semantics</span> <span style="color: #000080;font-style:italic;">-- no classes under p2js, sorry</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">builtins</span><span style="color: #0000FF;">\</span><span style="color: #000000;">structs</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> <span style="color: #000080;font-style:italic;">-- (needed for get_struct_name)</span>
<span style="color: #008080;">class</span> <span style="color: #000000;">Parent</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">name</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">age</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">watch_movie</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">get_struct_name</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">this</span><span style="color: #0000FF;">)!=</span><span style="color: #008000;">"Parent"</span> <span style="color: #008080;">and</span> <span style="color: #000000;">age</span><span style="color: #0000FF;"><</span><span style="color: #000000;">15</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Sorry, %s, you are too young to watch the movie.\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">name</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">else</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s is watching the movie...\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">name</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">class</span>
<span style="color: #008080;">class</span> <span style="color: #000000;">Child</span> <span style="color: #008080;">extends</span> <span style="color: #000000;">Parent</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">class</span>
<span style="color: #000000;">Parent</span> <span style="color: #000000;">p1</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">new</span><span style="color: #0000FF;">({</span><span style="color: #008000;">"Donald"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">42</span><span style="color: #0000FF;">}),</span>
<span style="color: #000000;">p2</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">new</span><span style="color: #0000FF;">({</span><span style="color: #008000;">"Dougal"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">12</span><span style="color: #0000FF;">})</span>
<span style="color: #000000;">p1</span><span style="color: #0000FF;">.</span><span style="color: #000000;">watch_movie</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">p2</span><span style="color: #0000FF;">.</span><span style="color: #000000;">watch_movie</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">Child</span> <span style="color: #000000;">c1</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">new</span><span style="color: #0000FF;">({</span><span style="color: #008000;">"Lisa"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">18</span><span style="color: #0000FF;">}),</span>
<span style="color: #000000;">c2</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">new</span><span style="color: #0000FF;">({</span><span style="color: #008000;">"Fred"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">})</span>
<span style="color: #000000;">c1</span><span style="color: #0000FF;">.</span><span style="color: #000000;">watch_movie</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">c2</span><span style="color: #0000FF;">.</span><span style="color: #000000;">watch_movie</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Donald is watching the movie...
Dougal is watching the movie...
Lisa is watching the movie...
Sorry, Fred, you are too young to watch the movie.
</pre>


=={{header|Wren}}==
=={{header|Wren}}==

Revision as of 13:58, 2 June 2023

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

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

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

Phix

No support, though it would probably not be particularly difficult to add a "final" keyword if ever needed.
Phix supports object orientation for the die-hards (desktop/Phix only), but does not require it be used at all.
In Phix, "private" determines availability from outside [sub-]class code, but there is nothing at all to prevent Child from having a public method that (internally) invokes a private method of the Parent, and of course/not unlike it would make no difference were name and age made private below.
The Phix compiler can make exactly the same optimisations were it to spot at EOF that a class has not been overidden as it could were it told up-front.

Translation of: Wren

Extended to include an under-age parent

without javascript_semantics -- no classes under p2js, sorry
include builtins\structs.e -- (needed for get_struct_name)

class Parent
    string name
    integer age
    procedure watch_movie()
        if get_struct_name(this)!="Parent" and age<15 then
            printf(1,"Sorry, %s, you are too young to watch the movie.\n",{name})
        else
            printf(1,"%s is watching the movie...\n",{name})
        end if
    end procedure
end class

class Child extends Parent
end class

Parent p1 = new({"Donald", 42}),
       p2 = new({"Dougal", 12})
p1.watch_movie()
p2.watch_movie()

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

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.