Sealed classes and methods: Difference between revisions

Content added Content deleted
(→‎{{header|C}}: Simplified code a bit.)
(→‎{{header|Go}}: Now uses the C entry's idea of passing a type identifier.)
Line 122: Line 122:
Consequently, a Go struct and its methods are effectively sealed unless the struct is embedded in another one. However, the only way to prevent embedding from outside the package would be to make the struct private to its package which may not be an acceptable solution unless it and/or its methods could be exposed indirectly.
Consequently, a Go struct and its methods are effectively sealed unless the struct is embedded in another one. However, the only way to prevent embedding from outside the package would be to make the struct private to its package which may not be an acceptable solution unless it and/or its methods could be exposed indirectly.


Fortunately, as the following example shows, the Wren technique for sealing methods can still be used provided we pass a further parameter (a type identifier) to the method so that it knows whether its being called with a pointer to a 'parent' or to a 'child' instance. This information is needed because the type system is such that the runtime type of the receiver will always be 'parent'.
The Wren approach isn't feasible because, as the following example shows, the parent method always thinks its receiver is a parent even though it may be a child!

We can still prevent 'Fred' from watching the movie on age grounds though the code needed to do this would prevent an under age parent from watching the movie as well.
<syntaxhighlight lang="go">package main
<syntaxhighlight lang="go">package main


import "fmt"
import "fmt"

type typeid int

const (
PARENT typeid = iota
CHILD
)


type parent struct {
type parent struct {
Line 138: Line 143:
}
}


func (p parent) watchMovie() {
func (p *parent) watchMovie(id typeid) {
fmt.Printf("The type of %s is %T\n", p.name, p)
if id == CHILD && p.age < 15 {
if p.age < 15 {
fmt.Printf("Sorry, %s, you are too young to watch the movie.\n", p.name)
fmt.Printf("Sorry, %s, you are too young to watch the movie.\n", p.name)
} else {
} else {
Line 148: Line 152:


func main() {
func main() {
p := parent{"Donald", 42}
p := &parent{"Donald", 42}
p.watchMovie()
p.watchMovie(PARENT)
c1 := child{parent{"Lisa", 18}}
c1 := &child{parent{"Lisa", 18}}
c2 := child{parent{"Fred", 10}}
c2 := &child{parent{"Fred", 10}}
c1.watchMovie()
c1.watchMovie(CHILD)
c2.watchMovie()
c2.watchMovie(CHILD)
}</syntaxhighlight>
}</syntaxhighlight>


{{out}}
{{out}}
<pre>
<pre>
The type of Donald is main.parent
Donald is watching the movie...
Donald is watching the movie...
The type of Lisa is main.parent
Lisa is watching the movie...
Lisa is watching the movie...
The type of Fred is main.parent
Sorry, Fred, you are too young to watch the movie.
Sorry, Fred, you are too young to watch the movie.

</pre>
</pre>