Commit | Line | Data |
663f8198 |
1 | #!/usr/bin/perl |
2 | |
3 | use strict; |
4 | use warnings; |
5 | |
6 | use Test::More no_plan => 4; |
7 | |
8 | =pod |
9 | |
10 | Scala Style Class Mixin Composition |
11 | |
12 | L<http://scala.epfl.ch/intro/mixin.html> |
13 | |
14 | A class can only be used as a mixin in the definition of another |
15 | class, if this other class extends a subclass of the superclass |
16 | of the mixin. Since ColoredPoint3D extends Point3D and Point3D |
17 | extends Point2D which is the superclass of ColoredPoint2D, the |
18 | code above is well-formed. |
19 | |
20 | class Point2D(xc: Int, yc: Int) { |
21 | val x = xc; |
22 | val y = yc; |
23 | override def toString() = "x = " + x + ", y = " + y; |
24 | } |
25 | |
26 | class ColoredPoint2D(u: Int, v: Int, c: String) extends Point2D(u, v) { |
27 | var color = c; |
28 | def setColor(newCol: String): Unit = color = newCol; |
29 | override def toString() = super.toString() + ", col = " + color; |
30 | } |
31 | |
32 | class Point3D(xc: Int, yc: Int, zc: Int) extends Point2D(xc, yc) { |
33 | val z = zc; |
34 | override def toString() = super.toString() + ", z = " + z; |
35 | } |
36 | |
37 | class ColoredPoint3D(xc: Int, yc: Int, zc: Int, col: String) |
38 | extends Point3D(xc, yc, zc) |
39 | with ColoredPoint2D(xc, yc, col); |
40 | |
41 | |
42 | Console.println(new ColoredPoint3D(1, 2, 3, "blue").toString()) |
43 | |
44 | "x = 1, y = 2, z = 3, col = blue" |
45 | |
46 | =cut |
47 | |
48 | { |
49 | package Point2D; |
50 | use metaclass; |
51 | |
52 | Point2D->meta->add_attribute('$x' => ( |
53 | accessor => 'x', |
54 | init_arg => 'x', |
55 | )); |
56 | |
57 | Point2D->meta->add_attribute('$y' => ( |
58 | accessor => 'y', |
59 | init_arg => 'y', |
60 | )); |
61 | |
62 | sub new { |
63 | my $class = shift; |
64 | $class->meta->new_object(@_); |
65 | } |
66 | |
67 | sub toString { |
68 | my $self = shift; |
69 | "x = " . $self->x . ", y = " . $self->y; |
70 | } |
71 | |
72 | package ColoredPoint2D; |
73 | our @ISA = ('Point2D'); |
74 | |
75 | ColoredPoint2D->meta->add_attribute('$color' => ( |
76 | accessor => 'color', |
77 | init_arg => 'color', |
78 | )); |
79 | |
80 | sub toString { |
81 | my $self = shift; |
82 | $self->SUPER() . ', col = ' . $self->color; |
83 | } |
84 | |
85 | package Point3D; |
86 | our @ISA = ('Point2D'); |
87 | |
88 | Point3D->meta->add_attribute('$z' => ( |
89 | accessor => 'z', |
90 | init_arg => 'z', |
91 | )); |
92 | |
93 | sub toString { |
94 | my $self = shift; |
95 | $self->SUPER() . ', z = ' . $self->z; |
96 | } |
97 | |
98 | package ColoredPoint3D; |
99 | our @ISA = ('Point3D'); |
100 | |
101 | __PACKAGE__->meta->mixin('ColoredPoint2D'); |
102 | |
103 | } |
104 | |
105 | my $colored_point_3d = ColoredPoint3D->new(x => 1, y => 2, z => 3, color => 'blue'); |
106 | isa_ok($colored_point_3d, 'ColoredPoint3D'); |
107 | isa_ok($colored_point_3d, 'Point3D'); |
108 | isa_ok($colored_point_3d, 'Point2D'); |
109 | |
110 | is($colored_point_3d->toString(), |
111 | 'x = 1, y = 2, z = 3, col = blue', |
112 | '... got the right toString method'); |