trzewiczek info



03.10.2010 kod:blog
Niebezpieczne dziedziczenie
Sprawa jest prosta i w gruncie rzeczy oczywista. Niemniej jednak straciłem dzisiaj czterdzieści minut szukając błędu, który okazał się błachostką. Chodzi o to, że standardowa biblioteka UGenów ChucKa zorganizowana jest w typową hierarchię klas. To dobrze! Szkoda tylko, że ta hierarchia ma luki.

Szybkie przypomnienie, jakie są konsekwencje hierarchii klas. Jeśli klasa B dziedziczy po klasie A to obiekty klasy B będą posiadały pełny interfejs klasy A. Metody klasy B mogą co prawda przeciążać (przesłaniać) interfejs klasy A, lecz, jeśli tego nie zrobi, wywołujemy metody klasy A, czyli…

No właśnie – gdzie tu problem? Problem w tym, że w dokumentacji znajdziemy dwie informacje:

– z jakiej klasy dziedziczy dana klasa
– jaki jest jej interface

co oznacza, że nie widzimy pełnego interfejsu wraz z metodami dziedziczonymi. Może się zatem zdarzyć, że pracując np. z obiektem klasy ADSR wywołamy metodę klasy Envelope (z której ADRS dziedziczy) nie powodując w ten sposób żadnego ostrzeżenia ze strony kompilatora. No bo niby czemu miałby nas ostrzegać i przed czym?! No jak dla mnie przed źle zaimplementowaną hierarchią klas, w której metody dziedziczone źle działają z obiektami klas dziedziczących.

Dokładnie tak się to ma z funkcją duration klasy ADSR. Nie jest ona przeciążona w klasie ADSR, więc wywoływana jest jej implementacja z klasy Envelope. Szkoda tylko, że z obiektami klasy ADSR ona nie działa!

SinOsc s1 => Envelope e => Gain g => dac;
SinOsc s2 => ADSR a => g;
.5 => g.gain;

// zaczynamy od ADSR, które nie działa najlepiej
1::second => a.duration;
<<< "ADSR - poczatek:", now/second >>>;

// uwaga - nie ma obwiedni - dźwięk wchodzi na ostro!
a.keyOn();
a.duration() => now;
<<< "ADSR - polowa:", now/second >>>;

// odtąd nie ma dźwięku!
a.keyOff();
a.duration() => now;
<<< "ADSR - koniec:", now/second >>>;

// zrobmy sekunde przerwy dla zlapania oddechu
second => now;

// a teraz Envelope, żeby zobaczyć, co to znaczy działa
1::second => e.duration;
<<< "Envelope - poczatek:", now/second >>>;

e.keyOn();
e.duration() => now;

<<< "Envelope - polowa:", now/second >>>;

e.keyOff();
e.duration() => now;

<<< "Envelope - koniec:", now/second >>>;

Kompilator nie ostrzega, kod się kompiluje, dźwięk się tnie, szukaj człowieku błędu ;)
N E W S