File: Polymorphism.schelp

package info (click to toggle)
supercollider 1%3A3.10.0%2Brepack-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 45,496 kB
  • sloc: cpp: 283,513; lisp: 74,040; ansic: 72,252; sh: 23,016; python: 7,175; makefile: 1,087; perl: 766; java: 677; yacc: 314; lex: 175; ruby: 136; objc: 65; xml: 15
file content (145 lines) | stat: -rw-r--r-- 4,421 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
title:: Polymorphism
summary:: the ability of different classes to respond to a message in different ways
categories:: Language>OOP
related:: Reference/Messages, Reference/Classes, Guides/Intro-to-Objects

section:: Introduction

Polymorphism is the ability of different classes to respond to a message in different ways. A message generally has some underlying meaning and it is the responsibility of each class to respond in a way appropriate to that meaning.

For example, the code::value:: message means "give me the effective value of this object".

The value method is implemented by these classes (among others):
definitionlist::
## Function : || this.value(args)
## Object : || this.value()
## Ref : || this.value
::

Let's look at how these classes implement the value message.

subsection:: Object

Here's the value method in class link::Classes/Object:: :
code::
value { ^this }
::
It simply returns itself. Since all classes inherit from class Object this means that unless a class overrides code::value::, the object will respond to code::value:: by returning itself.
code::
5.postln;			// posts itself
5.value.postln;		// value returns itself
'a symbol'.postln;
'a symbol'.value.postln;
[1,2,3].value.postln;
//etc...
::

subsection:: Function
In class link::Classes/Function:: the value method is a primitive:
code::
value { arg ... args;
    _FunctionValue
    // evaluate a function with args
    ^this.primitiveFailed
}
::

code::_FunctionValue:: is a C code primitive, so it is not possible to know just by looking at it what it does. However what it does is to evaluate the function and return the result.
code::
{ 5.squared }.postln;			// posts Instance of Function
{ 5.squared }.value.postln;		// posts 25
::

subsection:: Ref
The link::Classes/Ref:: class provides a way to create an indirect reference to an object. It can be used to pass a value by reference. Ref objects have a single instance variable called code::value::.
The code::value:: method returns the value of the instance variable code::value::. Here is a part of the class definition for Ref:
code::
Ref : AbstractFunction
{
    var <>value;

	*new { arg thing; ^super.new.value_(thing) }
    set { arg thing; value = thing }
    get { ^value }
    dereference { ^value }
    asRef { ^this }

    // behave like a stream
    next { ^value }

    printOn { arg stream;
        stream << "`(" << value << ")";
    }
    storeOn { arg stream;
        stream << "`(" <<< value << ")";
    }
}
::
Here is how it responds :
code::
Ref.new(123).postln;
Ref.new(123).value.postln;
::

Ref also implements a message called code::dereference:: which is another good example of polymorphism. As implemented in Ref, dereference just returns the value instance variable which is no different than what the value method does.
So what is the need for it? That is explained by how other classes respond to dereference. The dereference message means "remove any Ref that contains you".
In class Object dereference returns the object itself, again just like the value message. The difference is that no other classes override this method. So that dereference of a Function is still the Function.
definitionlist::
## Object : || this.dereference()
## Ref : || this.dereference()
::
code::
5.value.postln;
{ 5.squared }.value.postln;
Ref.new(123).value.postln;

5.dereference.postln;
{ 5.squared }.dereference.postln;
Ref.new(123).dereference.postln;
::

section:: Play
Yet another example of polymorphism is play. Many different kinds of objects know how to play themselves.

subsection:: Function
code::
{ PinkNoise.ar(0.1) }.play;
::

subsection:: AppClock
code::
(
var w, r;
w = Window.new("trem", Rect(512, 256, 360, 130));
w.front;
r = Routine({ arg appClockTime;
    ["AppClock has been playing for secs:",appClockTime].postln;
    60.do({ arg i;
        0.05.yield;
        w.bounds = w.bounds.moveBy(10.rand2, 10.rand2);
        w.alpha = cos(i*0.1pi)*0.5+0.5;
    });
    1.yield;
    w.close;
});
AppClock.play(r);
)
::

subsection:: SynthDef
code::
(
x = SynthDef("Help-SynthDef", { arg out=0;
    Out.ar(out, PinkNoise.ar(0.1))
}).play;
)
::

subsection:: Pattern
code::
Pbind(\degree, Pseq([0, 1, 2, 3],inf)).play;
::

section:: Conclusion
Polymorphism allows you to write code that does not assume anything about the implementation of an object, but rather asks the object to "do what I mean" and have the object respond appropriately.