pondělí 15. listopadu 2010

Implementace metod definovaných rozhraním

Při přípravě jiného článku jsem narazil na dost… osobité chování Axapty při implementaci rozhraní. Navzdory veškerým očekáváním Axapta nekontroluje, zda má implementující třída správné veřejné rozhraní (proto interface), ale jen že má metody shodných názvů, jaké má i rozhraní.

Ukažme si to na příkladu. Definuji následující rozhraní:
interface Rozhrani
{
    int rychlost(int _rychlost){}
}
Předpokládal bych, že každá třída implementující toto rozhraní musí obsahovat metodu rychlost() s parametrem a návratovou hodnotou typu int.

Následující třída jde nejen zkompilovat, ale kód v metodě main() i bez chyby proběhne, včetně přiřazení do proměnné.
class ImplementujiciTrida implements Rozhrani
{
    //Správný název metody, ale nesprávný typ parametru i návratové hodnoty
    void rychlost(str _slovniPopisRychlosti)
    {}

    public static void main(Args _args)
    {
        Rozhrani trida = new ImplementujiciTrida();
        //Instance nemá metodu akceptující číselný parameter a vracející hodnotu,
        //přesto toto volání proběhně.
        int i = trida.rychlost(5);
    }
}
Metoda rychlost() obdrží hodnotu překonvertovanou do řetězce a vrátí hodnotu 0 (případná hodnota v proměnné i v main() by byla přepsána), přestože má návratový typ void.
Pokud by implementace metody rychlost() obsahovala parametr, pro který neexistuje implicitní konverze (např. Object _o), dojde k chybě za běhu aplikace.

Rozhraní má poskytnout jistotu, že instance každé implementující třídy "rozumí" určitému způsobu komunikace, tedy že je možné zavolat nějakou metodu s předem danými typy parametrů. Když se třída hlásí k určitému veřejnému rozhraní (= implementuje interface), kompilátor by měl zajistit, že tomu tak skutečně je. Kompilátor Axapty to ale nedělá - a výsledkem chyby, kterou měla odhalit první kompilace, může být runtime exception nebo opravdu nepochopitelné chování aplikace.

Tímto nechci říct, že se v X++ nemají rozhraní používat. Naopak si myslím, že se používají málo (a místo nich se vytváří sporné hierarchie dědičnosti apod.). Ale nelze se spoléhat na kompilátor, že korektní implementaci rozhraní vynutí.

3 komentáře:

  1. Tak po zmene extends na implements se me to opravdu podarilo taky prekompilovat.Vypada, ze to je upravou kompilatoru v novych verzich Ax, protoze stara Ax3 to neprekompilovala. Nicmene to nic nemeni na skutecnosti, ze takhle by to fungovat nemelo. L.

    OdpovědětVymazat
  2. Aha, chybička se vloudila. Opraveno, díky za upozornění.
    Zkoušel jsem to jen AX2009, ale v brzké době to testnu na 2011 (ale nemyslím, že to bude jiné).

    OdpovědětVymazat
  3. Tak mi ta reakce trvala o poznání déle, než jsem plánoval.
    Nicméně zprávy mám dobré: V AX6 tento problém neexistuje, dokonce se implementace rozhraní kontroluje už při kompilaci.

    OdpovědětVymazat