Kovaryans va qarama-qarshilik (kompyuter fanlari) - Covariance and contravariance (computer science)

Ko'pchilik dasturlash tili tipdagi tizimlar qo'llab-quvvatlash kichik tip. Masalan, agar turi Mushuk ning pastki turi Hayvon, keyin turning ifodasi Mushuk almashtirilishi kerak qayerda bo'lmasin tur ifodasi Hayvon ishlatilgan.

Varians yanada murakkab turlar orasidagi subtitrlash ularning tarkibiy qismlari orasidagi subtitr bilan qanday bog'liqligini anglatadi. Masalan, ro'yxati qanday bo'lishi kerak Mushuklar ro'yxatiga tegishli Hayvons? Yoki qaytib keladigan funktsiya qanday bo'lishi kerak Mushuk qaytadigan funktsiya bilan bog'liq Hayvon?

Ning o'zgarishiga qarab turi konstruktori, oddiy turlarning subtip aloqasi tegishli kompleks turlari uchun saqlanib qolishi, qaytarilishi yoki e'tiborsiz qoldirilishi mumkin. In OCaml dasturlash tili, masalan, "Mushuklar ro'yxati" "Hayvonlar ro'yxati" ning pastki turidir, chunki ro'yxat turi konstruktori kovariant. Bu shuni anglatadiki, oddiy turlarning subtip aloqasi murakkab turlar uchun saqlanib qoladi.

Boshqa tomondan, "funktsiya Animal-dan String-ga" bu "Cat-String-ga funktsiya" ning pastki turi, chunki funktsiya turi konstruktori qarama-qarshi parametr turida. Bu erda oddiy turlarning subtip aloqasi murakkab turlar uchun teskari.

Dasturlash tili uslubchisi massivlar, merosxo'rlik va boshqalar kabi til xususiyatlari uchun yozish qoidalarini ishlab chiqishda farqni ko'rib chiqadi umumiy ma'lumotlar turlari. Turli konstruktorlarni o'zgarmas o'rniga kovariant yoki ziddiyatli qilib, ko'proq dasturlar yaxshi yozilgan holda qabul qilinadi. Boshqa tomondan, dasturchilar ko'pincha qarama-qarshilikni noaniq deb hisoblashadi va ish vaqti turidagi xatolardan qochish uchun dispersiyani aniq kuzatib borish murakkab yozish qoidalariga olib kelishi mumkin.

Oddiy tizimni saqlash va foydali dasturlarga ruxsat berish uchun til tipik konstruktorni o'zgaruvchan deb hisoblashi mumkin bo'lsa ham, uni konvertor sifatida ko'rib chiqishi yoki uni xavfsizligini buzishi mumkin bo'lsa ham, uni kovariant sifatida ko'rib chiqishi mumkin.

Rasmiy ta'rif

Ichida tizim turi a dasturlash tili, yozish qoidasi yoki tip konstruktori:

  • kovariant agar u saqlasa turlarini buyurtma qilish (≤), turlarni aniqroqdan umumiygacha buyurtma qiluvchi;
  • qarama-qarshi agar bu buyurtmani bekor qilsa;
  • bivariant agar bu ikkalasi ham qo'llanilsa (ya'ni, ikkalasi ham) Men<A>Men<B> va Men<B>Men<A> xuddi shu paytni o'zida);[1]
  • variant agar kovariant, qarama-qarshi yoki bivariant bo'lsa;
  • o'zgarmas yoki noharbiy agar variant bo'lmasa.

Maqolada bu ba'zi bir umumiy turdagi konstruktorlarga qanday tegishli ekanligi ko'rib chiqilgan.

C # misollari

Masalan, ichida C #, agar Mushuk ning pastki turi Hayvon, keyin:

  • IEnumerable<Mushuk> ning pastki turi IEnumerable<Hayvon>. Subtip saqlanib qoladi, chunki IEnumerable<T> bu kovariant kuni T.
  • Amal<Hayvon> ning pastki turi Amal<Mushuk>. Subtip teskari, chunki Amal<T> bu qarama-qarshi kuni T.
  • Ham Ilist<Mushuk> na Ilist<Hayvon> ikkinchisining pastki turi, chunki Ilist<T> bu o'zgarmas kuni T.

C # umumiy interfeysining tafovutini joylashtirish orqali e'lon qilinadi chiqib (kovariant) yoki yilda (qarama-qarshi) atribut uning turi parametrlariga (nol yoki undan ko'p). Belgilangan har bir turdagi parametr uchun kompilyator har qanday buzilish o'limga olib kelishi bilan yakuniy ravishda bunday foydalanishni dunyo miqyosida izchilligini tasdiqlaydi. Yuqoridagi interfeyslar quyidagicha e'lon qilinadi IEnumerable<chiqib T>, Amal<yilda T>va Ilist<T>. Bir nechta turdagi parametrlarga ega bo'lgan turlari har bir parametr uchun har xil farqlarni ko'rsatishi mumkin. Masalan, vakil turi Vazifasi<yilda T, chiqib Natija> funktsiyani a bilan ifodalaydi qarama-qarshi turdagi kirish parametri T va a kovariant turdagi qiymat Natija.[2]

The interfeys dispersiyasi uchun yozish qoidalari turdagi xavfsizlikni ta'minlash. Masalan, an Amal<T> turi argumentini kutadigan birinchi darajali funktsiyani anglatadi T, va har qanday turdagi hayvonlarga ishlov bera oladigan funktsiyadan har doim faqat mushuklar bilan ishlay oladigan funktsiya o'rniga foydalanish mumkin.

Massivlar

Faqat o'qish uchun ma'lumotlar turlari (manbalar) kovariant bo'lishi mumkin; faqat yozish uchun ma'lumotlar turlari (lavabolar) qarama-qarshi bo'lishi mumkin. Ikkala manba va lavabo vazifasini bajaradigan o'zgaruvchan ma'lumotlar turlari o'zgarmas bo'lishi kerak. Ushbu umumiy hodisani tasvirlash uchun qator turi. Turi uchun Hayvon biz turini qilishimiz mumkin Hayvon[], bu "hayvonlar qatori". Ushbu misol uchun ushbu massiv o'qish va yozish elementlarini qo'llab-quvvatlaydi.

Bizda bunga quyidagicha munosabatda bo'lish imkoniyati mavjud:

  • kovariant: a Mushuk[] bu Hayvon[];
  • qarama-qarshi: an Hayvon[] a Mushuk[];
  • o'zgarmas: an Hayvon[] emas Mushuk[] va a Mushuk[] emas Hayvon[].

Agar biz xato xatolaridan qochishni istasak, faqat uchinchi tanlov xavfsizdir. Shubhasiz, har bir kishi emas Hayvon[] go'yo a kabi muomala qilish mumkin Mushuk[], chunki massivdan o'qigan mijoz kutadi Mushuk, lekin Hayvon[] masalan, o'z ichiga olishi mumkin. a It. Shunday qilib, qarama-qarshi qoidalar xavfsiz emas.

Aksincha, a Mushuk[] sifatida ko'rib bo'lmaydi Hayvon[]. A qo'yish har doim ham imkon bo'lishi kerak It ichiga Hayvon[]. Kovariant massivlarida bu xavfsizligini kafolatlash mumkin emas, chunki orqa do'kon mushuklarning bir qatori bo'lishi mumkin. Shuning uchun kovariant qoidasi ham xavfsiz emas - massiv konstruktori bo'lishi kerak o'zgarmas. E'tibor bering, bu faqat o'zgaruvchan massivlar uchun muammo; kovariant qoidasi o'zgarmas (faqat o'qish uchun) massivlar uchun xavfsizdir.

C # yordamida siz bu orqali o'ynashingiz mumkin dinamik kalit so'z qatori / to'plami / generics bilan o'rdak terish, intellisense shu tarzda yo'qoladi, lekin u ishlaydi.

Java va C # da kovariant massivlari

Java va C # ning dastlabki versiyalarida umumiy nomlar mavjud emas, ular ham shunday nomlangan parametrik polimorfizm. Bunday sharoitda massivlarni o'zgarmas qoidalar qilish foydali polimorfik dasturlarni istisno qiladi.

Masalan, massivni aralashtirish uchun funktsiyani yoki -dan foydalanib ikkita massivni tengligini tekshiradigan funktsiyani yozishni o'ylab ko'ring Ob'ekt.teng elementlar bo'yicha usul. Amalga oshirish massivda saqlanadigan aniq element turiga bog'liq emas, shuning uchun barcha turdagi massivlarda ishlaydigan bitta funktsiyani yozish imkoniyati bo'lishi kerak. Ushbu turdagi funktsiyalarni amalga oshirish oson:

mantiqiy tengArray(Ob'ekt[] a1, Ob'ekt[] a2);bekor shuffleArray(Ob'ekt[] a);

Ammo, agar massiv turlari o'zgarmas deb hisoblansa, bu funktsiyalarni faqat shu turdagi massivda chaqirish mumkin bo'ladi Ob'ekt[]. Masalan, qatorlar qatorini aralashtirib bo'lmaydi.

Shuning uchun ham Java, ham C # qator turlarini bir xilda ishlaydi, masalan, Java-da Ip[] ning pastki turi Ob'ekt[]va C # da mag'lubiyat[] ning pastki turi ob'ekt[].

Yuqorida muhokama qilinganidek, kovariant massivlar massivga yozish bilan bog'liq muammolarga olib keladi. Java va C # har bir massiv ob'ektini yaratishda uni turi bilan belgilash bilan shug'ullanadi. Har safar qiymat massivda saqlanganda, ijro etiladigan muhit qiymatning ish vaqti turi massivning ish vaqti turiga tengligini tekshiradi. Agar nomuvofiqlik bo'lsa, an ArrayStoreException (Java) yoki ArrayTypeMismatchException (C #) tashlandi:

// a - bu Stringning bir elementli massiviIp[] a = yangi Ip[1];// b - bu Ob'ektning massiviOb'ekt[] b = a;// b ga butun sonni tayinlang. Agar b haqiqatan ham bo'lsa, bu mumkin bo'lar edi// Ob'ektlar qatori, lekin u haqiqatan ham String qatori bo'lgani uchun,// biz java.lang.ArrayStoreException-ni olamiz.b[0] = 1;

Yuqoridagi misolda biri mumkin o'qing (b) massividan xavfsiz tarzda. Bu faqat harakat qilmoqda yozmoq muammoga olib kelishi mumkin bo'lgan qatorga.

Ushbu yondashuvning bir noqulayligi shundaki, u qattiqroq tizim tizim kompilyatsiya vaqtida qo'lga kiritishi mumkin bo'lgan ish vaqtidagi xatolikni qoldiradi. Bundan tashqari, bu ishlashga zarar etkazadi, chunki har bir massivga yozish qo'shimcha ish vaqtini tekshirishni talab qiladi.

Generika qo'shilishi bilan Java va C # endi kovaryansga tayanmasdan bunday polimorf funktsiyani yozish usullarini taklif qiladi. Massivni taqqoslash va aralashtirish funktsiyalariga parametrlangan turlari berilishi mumkin

<T> mantiqiy tengArray(T[] a1, T[] a2);<T> bekor shuffleArray(T[] a);

Shu bilan bir qatorda, C # usuli to'plamga faqat o'qish uchun kirishini ta'minlash uchun interfeysdan foydalanish mumkin IEnumerable<ob'ekt> uni bir qatorga o'tkazish o'rniga ob'ekt[].

Funktsiya turlari

Bilan tillar birinchi darajali funktsiyalar bor funktsiya turlari "mushukni kutish va hayvonni qaytarish funktsiyasi" kabi (yozilgan) Mushuk -> Hayvon yilda OCaml sintaksis yoki Vazifasi<Mushuk,Hayvon> yilda C # sintaksis).

Ushbu tillar, shuningdek, bitta funktsiya turi boshqasining kichik turi bo'lgan vaqtni, ya'ni boshqa turdagi funktsiyani kutadigan kontekstda bitta turdagi funktsiyani ishlatish xavfsizligini ko'rsatishi kerak. Funktsiyani almashtirish xavfsizdir f funktsiya uchun g agar f umumiy argument turini qabul qiladi va nisbatan aniqroq turini qaytaradi g. Masalan, turdagi funktsiyalar Hayvon -> Mushuk, Mushuk -> Mushukva Hayvon -> Hayvon har qanday joyda foydalanish mumkin a Mushuk -> Hayvon kutilgan edi. (Buni buni bilan taqqoslash mumkin mustahkamlik printsipi aloqa: "qabul qilgan narsangizda liberal va ishlab chiqargan narsangizda konservativ bo'ling.") Umumiy qoida:

agar va .

Foydalanish xulosa qoidalari yozuvi xuddi shu qoidani quyidagicha yozish mumkin:

Boshqacha qilib aytganda, → tip konstruktor kirish turidagi qarama-qarshilik va chiqish turidagi kovariant. Ushbu qoida birinchi marta rasmiy ravishda bayon qilingan Jon C. Reynolds,[3] va keyinchalik qog'ozda ommalashgan Luka Kardelli.[4]

Muomala qilishda funktsiyalarni argument sifatida qabul qiladigan funktsiyalar, bu qoidani bir necha marta qo'llash mumkin. Masalan, qoidani ikki marta qo'llash orqali, agar A'≤A bo'lsa (A '→ B) → B ≤ (A → B) → B ekanligini ko'ramiz. Boshqacha aytganda, (A → B) → B turi kovariant A holatida. Murakkab turlar uchun ma'lum bir turdagi ixtisoslashuv turi xavfli emasligi yoki yo'qligi haqida aqliy fikrni chalkashtirib yuborishi mumkin, ammo qaysi pozitsiyalar birgalikda va ziddiyatli ekanligini hisoblash oson: agar pozitsiya chap tomonida bo'lsa unga tatbiq etiladigan juft sonli o'qlar.

Ob'ektga yo'naltirilgan tillarda meros

Qachon subklass bekor qiladi superklassdagi usul, kompilyator bekor qilish usulining to'g'ri turga ega ekanligini tekshirishi kerak. Ba'zi bir tillar tipning superklassdagi turga to'liq mos kelishini talab qilsa (invariantlik), ustun usulda "yaxshiroq" turga ega bo'lishiga yo'l qo'ymaslik ham xavfsizdir. Funktsiya turlari uchun odatiy subtiping qoidasiga ko'ra, bu bekor qilish usuli aniqroq turni qaytarish kerakligini anglatadi (qaytarish turi kovaryansi) va umumiy umumiy argumentni qabul qiladi (parametr turi kontravariance). Yilda UML yozuvlari, imkoniyatlari quyidagicha:

Aniq bir misol uchun, biz an-ni modellashtirish uchun sinf yozyapmiz deylik hayvonlar uchun boshpana. Biz buni taxmin qilamiz Mushuk ning subklassidir Hayvonva bizda asosiy sinf (Java sintaksisidan foydalangan holda)

UML diagrammasi
sinf AnimalShelter {    Hayvon getAnimalForAdoption() {        // ...    }        bekor putHayvon(Hayvon hayvon) {        //...    }}

Endi savol tug'iladi: agar biz subklass qilsak AnimalShelter, qaysi turlarga berishga ruxsat berilgan getAnimalForAdoption va putHayvon?

Covariant usuli qaytish turi

Mumkin bo'lgan tilda kovariant qaytish turlari, olingan sinf getAnimalForAdoption aniqroq turni qaytarish usuli:

UML diagrammasi
sinf CatShelter uzaytiradi AnimalShelter {    Mushuk getAnimalForAdoption() {        qaytish yangi Mushuk();    }}

Asosiy OO tillari orasida, Java va C ++ kovariant qaytish turlarini qo'llab-quvvatlash, while C # emas. Kovariant qaytish turini qo'shish 1998 yilda standartlar qo'mitasi tomonidan tasdiqlangan C ++ tilining birinchi modifikatsiyalaridan biri edi.[5] Scala va D. shuningdek, kovariant qaytish turlarini qo'llab-quvvatlaydi.

Qarama-qarshi usul parametr turi

Shunga o'xshab, asosiy sinfdagi usulga qaraganda ko'proq umumiy dalillarni qabul qilish uchun ustun usulga ruxsat berish xavfsizdir:

UML diagrammasi
sinf CatShelter uzaytiradi AnimalShelter {    bekor putHayvon(Ob'ekt hayvon) {        // ...    }}

Ob'ektga yo'naltirilgan tillarning ko'pi bunga imkon bermaydi. C ++ va Java buni an bilan bog'liq bo'lmagan usul sifatida talqin qiladilar haddan tashqari yuklangan ism.

Biroq, Birlashtiruvchi ikkala kovariantlikni ham, qarama-qarshilikni ham qo'llab-quvvatladi. Bekor qilingan usullar uchun konvensiyani chaqirish kovariantdir chiqib parametrlar va qaytarish qiymatlari va normal parametrlarga zid (rejim bilan) yilda).

Kovariant usuli parametr turi

Bir nechta asosiy tillar, Eyfel va Dart[6] ustun usulning parametrlariga ega bo'lishiga imkon bering Ko'proq superklassdagi usulga nisbatan o'ziga xos tur (kovaryans parametr turi). Shunday qilib, quyidagi Dart kodida check, bilan yoziladi putHayvon asosiy sinfdagi usulni bekor qilish:

UML diagrammasi
sinf CatShelter uzaytiradi AnimalShelter {    bekor putHayvon(kovariant Mushuk hayvon) {        // ...    }}

Bu xavfsiz emas. Kasting orqali a CatShelter ga AnimalShelter, itni mushuklarning boshpanasiga joylashtirishga harakat qilish mumkin. Bu uchrashmaydi CatShelter parametr cheklovlari va ish vaqtida xatolikka olib keladi. Turlarning xavfsizligi yo'qligi (Eyfel jamoasida "mushuk" yoki "CAT" o'zgargan mavjudligi yoki turi bo'lgan "katkall muammosi" deb nomlanadi) uzoq vaqtdan beri muammo bo'lib kelgan. O'tgan yillar davomida uni tuzatish uchun global statik tahlil, mahalliy statik tahlil va yangi til xususiyatlarining turli xil kombinatsiyalari taklif qilindi,[7][8] va ular ba'zi Eyfel kompilyatorlarida qo'llanilgan.

Xavfsizlik muammosiga qaramay, Eyfel dizaynerlari kovariant parametr turlarini haqiqiy dunyo talablarini modellashtirish uchun juda muhim deb hisoblashadi.[8] Mushuklarning boshpanasi odatdagi hodisani tasvirlaydi: bu shunday bir xil hayvonlar uchun boshpana, lekin bor qo'shimcha cheklovlarva buni modellashtirish uchun meros va cheklangan parametr turlaridan foydalanish oqilona ko'rinadi. Ushbu merosdan foydalanishni taklif qilishda Eyfel dizaynerlari rad etadilar Liskovni almashtirish printsipi, subklasslarning ob'ektlari har doim ularning superklasslariga nisbatan kamroq cheklangan bo'lishi kerak.

Metod parametrlarining kovaryansiyasiga yo'l qo'yadigan asosiy tilning yana bir misoli - bu sinf konstruktorlariga nisbatan PHP. Quyidagi misolda __construct () usuli qabul qilingan, metod parametri ota-ona usuli parametriga mos kelishiga qaramay. Agar bu usul __construct () dan boshqa narsa bo'lsa, xato yuzaga keladi:

interfeys AnimalInterface {}interfeys DogInterface uzaytiradi AnimalInterface {}sinf It asboblar DogInterface {}sinf Uy hayvoni{    jamoat funktsiya __struktsiya(AnimalInterface $ hayvon) {}}sinf PetDog uzaytiradi Uy hayvoni{    jamoat funktsiya __struktsiya(DogInterface $ it)    {        ota-ona::__struktsiya($ it);    }}

Kovariant parametrlari foydali bo'lib ko'rinadigan yana bir misol, ikkilik usullar, ya'ni parametr usuli chaqirilgan ob'ekt bilan bir xil bo'lishi kutilayotgan usullar. Bunga misol taqqoslash usul: a.taqqoslash(b) yo'qligini tekshiradi a oldin yoki keyin keladi b ba'zi tartiblashda, ammo taqqoslash usuli, masalan, ikkita ratsional son ikki satrni taqqoslash usulidan farq qiladi. Ikkilik usullarning boshqa keng tarqalgan misollari qatoriga tenglik testlari, arifmetik amallar va to'plam va birlashma kabi operatsiyalar kiradi.

Java-ning eski versiyalarida taqqoslash usuli interfeys sifatida ko'rsatilgan Taqqoslash mumkin:

interfeys Taqqoslash mumkin {    int taqqoslash(Ob'ekt o);}

Buning kamchiliklari shundaki, usul turi argumentini olish uchun ko'rsatilgan Ob'ekt. Odatiy dastur birinchi navbatda ushbu dalilni bekor qiladi (agar u kutilgan turdagi bo'lmasa xatoga yo'l qo'yib):

sinf Ratsional raqam asboblar Taqqoslash mumkin {    int raqamlovchi;    int maxraj;    // ...     jamoat int taqqoslash(Ob'ekt boshqa) {        Ratsional raqam otherNum = (Ratsional raqam)boshqa;        qaytish Butun son.taqqoslash(raqamlovchi * otherNum.maxraj,                               otherNum.raqamlovchi * maxraj);    }}

Kovariant parametrlari bo'lgan tilda, argument taqqoslash to'g'ridan-to'g'ri kerakli turga berilishi mumkin Ratsional raqam, typecast-ni yashirish. (Albatta, bu hali ham ish vaqtida xatolikka yo'l qo'yishi mumkin taqqoslash keyin chaqirildi masalan. a Ip.)

Kovariant parametr turlariga ehtiyoj sezmaslik

Boshqa til xususiyatlari, kovariant parametrlarining aniq afzalliklarini ta'minlashi bilan birga Liskovning o'rnini bosishini saqlab qolishi mumkin.

Bilan tilda umumiy narsalar (a.k.a.) parametrik polimorfizm ) va cheklangan miqdoriy miqdor, oldingi misollarni yozish uchun xavfsiz usulda yozish mumkin.[9] Aniqlash o'rniga AnimalShelter, biz parametrlangan sinfni aniqlaymiz Boshpana<T>. (Buning bir noqulayligi shundaki, asosiy sinfni amalga oshiruvchisi subklasslarda qaysi turlarga ixtisoslashishi kerakligini oldindan bilishi kerak.)

sinf Boshpana<T uzaytiradi Hayvon> {    T getAnimalForAdoption() {        // ...    }    bekor putHayvon(T hayvon) {        // ...    }}    sinf CatShelter uzaytiradi Boshpana<Mushuk> {    Mushuk getAnimalForAdoption() {        // ...    }    bekor putHayvon(Mushuk hayvon) {        // ...    }}

Xuddi shunday, Java ning so'nggi versiyalarida Taqqoslash mumkin interfeysi parametrlangan bo'lib, bu pastga tushishni xavfsiz tarzda chiqarib tashlashga imkon beradi:

sinf Ratsional raqam asboblar Taqqoslash mumkin<Ratsional raqam> {    int raqamlovchi;    int maxraj;    // ...             jamoat int taqqoslash(Ratsional raqam otherNum) {        qaytish Butun son.taqqoslash(raqamlovchi * otherNum.maxraj,                                otherNum.raqamlovchi * maxraj);    }}

Yordam beradigan yana bir til xususiyati bir nechta jo'natish. Ikkilik usullarni yozish noqulay bo'lishining bir sababi, shunga o'xshash qo'ng'iroqda a.taqqoslash(b), to'g'ri bajarilishini tanlash taqqoslash haqiqatan ham ikkalasining ish vaqti turiga bog'liq a va b, lekin an'anaviy OO tilida faqat ish vaqti turi a hisobga olinadi. Bilan tilda Umumiy Lisp ob'ekti tizimi (CLOS) uslubi bir nechta jo'natish, taqqoslash usuli umumiy funktsiya sifatida yozilishi mumkin, bu erda ikkala argument ham usul tanlash uchun ishlatiladi.

Juzeppe Kastagna[10] bir nechta dispetcherlik bilan yozilgan tilda umumiy funktsiya dispetcherlikni boshqaradigan ba'zi bir parametrlarga ega bo'lishi mumkin va ba'zi bir "chap" parametrlarga ega emas. Uslublarni tanlash qoidasi amaldagi eng aniq usulni tanlaganligi sababli, agar usul boshqa usulni bekor qilsa, u holda ustun usul nazorat parametrlari uchun aniqroq turlarga ega bo'ladi. Boshqa tomondan, tipning xavfsizligini ta'minlash uchun til hali ham qolgan parametrlarni kamida umumiy bo'lishini talab qilishi kerak. Oldingi terminologiyadan foydalangan holda, ish vaqti usulini tanlash uchun ishlatiladigan turlar kovariant, usulni tanlash uchun ishlatilmaydigan usullar qarama-qarshi. Java kabi odatiy bir dispetcherlik tillari ham ushbu qoidaga bo'ysunadi: usul tanlash uchun faqat bitta argument ishlatiladi (qabul qiluvchi ob'ekti, yashirin argument sifatida usulga o'tib ketgan bu) va, albatta, turi bu superklassga qaraganda ustun usullar ichida ko'proq ixtisoslashgan.

Kastagna kovariant parametr turlari ustun bo'lgan misollar (xususan, ikkilik usullar) bir nechta dispetcherlik yordamida ko'rib chiqilishini taklif qiladi. Bu tabiiy ravishda kovariantdir, ammo aksariyat dasturlash tillari bir nechta jo'natishni qo'llab-quvvatlamaydi.

Disversiya va merosning qisqacha mazmuni

Quyidagi jadvalda yuqorida muhokama qilingan tillarda metodlarni bekor qilish qoidalari umumlashtirilgan.

Parametr turiQaytish turi
C ++ (1998 yildan beri), Java (beri J2SE 5.0 ), D.O'zgarmasKovariant
C #O'zgarmasKovariant (C # 9 dan beri - o'zgarmasgacha)
Scala, BirlashtiruvchiQarama-qarshiKovariant
EyfelKovariantKovariant

Umumiy turlari

Umumiy ma'lumotni qo'llab-quvvatlaydigan dasturlash tillarida (a. parametrik polimorfizm ), dasturchi tipdagi tizimni yangi konstruktorlar bilan kengaytirishi mumkin. Masalan, C # interfeysi Ilist<T> kabi yangi turlarini barpo etishga imkon beradi Ilist<Hayvon> yoki Ilist<Mushuk>. So'ngra ushbu turdagi konstruktorlarning xilma-xilligi qanday bo'lishi kerak degan savol tug'iladi.

Ikkita asosiy yondashuv mavjud. Bilan tillarda deklaratsiya-saytning o'zgaruvchan izohlari (masalan, C # ), dasturchi umumiy turdagi ta'rifni uning tur parametrlarining mo'ljallangan dispersiyasi bilan izohlaydi. Bilan saytdagi variatsion izohlar (masalan, Java ) o'rniga dasturchi umumiy turni yaratadigan joylarni izohlaydi.

Deklaratsiya-saytning o'zgaruvchan izohlari

Deklaratsiya saytidagi varatsion izohlarga ega bo'lgan eng mashhur tillar C # va Kotlin (kalit so'zlardan foydalangan holda chiqib va yilda) va Scala va OCaml (kalit so'zlardan foydalangan holda + va -). C # faqat interfeys turlari uchun dispersiya izohlarini beradi, Kotlin, Scala va OCaml ularni interfeys turlari uchun ham, aniq ma'lumotlar turlari uchun ham beradi.

Interfeyslar

C # da umumiy interfeysning har bir turi parametri kovariant bilan belgilanishi mumkin (chiqib), qarama-qarshi (yilda) yoki o'zgarmas (izohsiz). Masalan, biz interfeysni aniqlay olamiz IEnumerator<T> faqat o'qish uchun iteratorlar va uni parametr parametrida kovariant (tashqariga) deb e'lon qiling.

interfeys IEnumerator<chiqib T>{    T Joriy { olish; }    bool MoveNext();}

Ushbu deklaratsiya bilan, IEnumerator uning turi parametrida kovariant sifatida qaraladi, masalan. IEnumerator<Mushuk> ning pastki turi IEnumerator<Hayvon>.

Turni tekshiruvchi interfeysdagi har bir usul e'lonida faqat parametr parametrlariga mos keladigan tarzda zikr qilinishini ta'minlaydi yilda/chiqib izohlar. Ya'ni, kovariant deb e'lon qilingan parametr har qanday qarama-qarshi pozitsiyalarda bo'lmasligi kerak (agar pozitsiya qarama-qarshi turdagi konstruktorlarning g'alati sonida yuzaga kelsa, qarama-qarshi). Aniq qoida[11][12] interfeysdagi barcha usullarning qaytish turlari bo'lishi kerak covariantly amal qiladi va barcha parametr parametr turlari bo'lishi kerak qarama-qarshi ravishda amal qiladi, qayerda yaroqli S-ly quyidagicha belgilanadi:

  • Umumiy bo'lmagan turlar (sinflar, tuzilmalar, enumlar va boshqalar) birgalikda va qarama-qarshi ravishda amal qiladi.
  • Turi parametri T belgilanmagan bo'lsa, kovariant ravishda amal qiladi yildava agar u belgilanmagan bo'lsa, qarama-qarshi ravishda amal qiladi chiqib.
  • Massiv turi A[] agar S-ly amal qiladi A bu. (Buning sababi, C # ning kovariant massivlari mavjud.)
  • Umumiy turi G<A1, A2, ..., An> har bir parametr uchun S-ly amal qiladi Ai,
    • Ai haqiqiy S-ly, va menth parametr G kovariant deb e'lon qilingan yoki
    • Ai haqiqiy (S emas) -ly, va menth parametr G qarama-qarshi deb e'lon qilingan yoki
    • Ai ham o'zgaruvchan, ham qarama-qarshi ravishda amal qiladi va menth parametr G o'zgarmas deb e'lon qilinadi.

Ushbu qoidalar qanday qo'llanilishiga misol sifatida quyidagilarni ko'rib chiqing Ilist<T> interfeys.

interfeys Ilist<T>{    bekor Kiritmoq(int indeks, T element);    IEnumerator<T> GetEnumerator();}

Parametr turi T ning Kiritmoq qarama-qarshi ravishda amal qilishi kerak, ya'ni tip parametri T belgilanmasligi kerak chiqib. Xuddi shunday, natija turi IEnumerator<T> ning GetEnumerator covariantly haqiqiy bo'lishi kerak, ya'ni (beri IEnumerator kovariant interfeysi) turi T covariantly haqiqiy bo'lishi kerak, ya'ni type parametri T belgilanmasligi kerak yilda. Bu interfeys ekanligini ko'rsatadi Ilist ham, ham ziddiyatli belgilashga yo'l qo'yilmaydi.

Kabi umumiy ma'lumotlar tuzilishining umumiy holatida Ilist, bu cheklovlar degan ma'noni anglatadi chiqib parametr faqat strukturadan ma'lumotlarni olish usullari uchun ishlatilishi mumkin va an yilda parametr faqat tuzilishga ma'lumotlarni kiritish usullari uchun ishlatilishi mumkin, shu sababli kalit so'zlarni tanlash.

Ma'lumotlar

C # interfeys parametrlari bo'yicha variatsion izohlarga ruxsat beradi, lekin sinflar parametrlariga emas. C # sinflaridagi maydonlar har doim o'zgaruvchan bo'lganligi sababli, C # da parametrlangan sinflar juda foydali bo'lmaydi. Ammo o'zgarmas ma'lumotlarga urg'u beradigan tillar kovariant turlaridan yaxshi foydalanishi mumkin. Masalan, barchasida Scala, Kotlin va OCaml o'zgarmas ro'yxat turi kovariant: Ro'yxat[Mushuk] ning pastki turi Ro'yxat[Hayvon].

Scala-ning dispersiya izohlarini tekshirish qoidalari, asosan, C # bilan bir xil. Biroq, ayniqsa, o'zgarmas ma'lumotlar tuzilmalariga taalluqli ba'zi bir iboralar mavjud. Ular quyidagi ta'rifi bilan tasvirlangan (ning parchasi) Ro'yxat[A] sinf.

muhrlangan mavhum sinf Ro'yxat[+ A] uzaytiradi Xulosa[A] {    def bosh: A    def quyruq: Ro'yxat[A]    / ** Ushbu ro'yxatning boshiga element qo'shadi. * /    def ::[B >: A] (x: B): Ro'yxat[B] =        yangi skala.to'plam.o'zgarmas.::(x, bu)    /** ... */}

Birinchidan, variant turiga ega bo'lgan sinf a'zolari o'zgarmas bo'lishi kerak. Bu yerda, bosh turiga ega Akovariant deb e'lon qilingan (+) va, albatta bosh usul sifatida e'lon qilingan (def). Buni o'zgaruvchan maydon sifatida e'lon qilishga urinish (var) turi xatosi sifatida rad etilishi kerak.

Ikkinchidan, ma'lumotlar tuzilishi o'zgarmas bo'lsa ham, ko'pincha parametr turi qarama-qarshi bo'lib turadigan usullarga ega bo'ladi. Masalan, usulni ko'rib chiqing :: ro'yxatning old qismiga element qo'shadigan. (Amalga oshirish shu kabi nomlangan yangi ob'ektni yaratish orqali ishlaydi sinf ::, bo'sh bo'lmagan ro'yxatlar sinfi.) Buni berishning eng aniq turi bo'ladi

def :: (x: A): Ro'yxat[A]

Ammo, bu tipik xato bo'lishi mumkin, chunki kovariant parametri A qarama-qarshi holatda (funktsiya parametri sifatida) paydo bo'ladi. Ammo bu muammoni hal qilish uchun hiyla-nayrang bor. Biz beramiz :: har qanday turdagi elementni qo'shishga imkon beradigan yanada umumiy tur B Modomiki, hamonki; sababli, uchun B ning supertipi A. Shunga e'tibor bering Ro'yxat kovariant bo'lib, beri bu turi bor Ro'yxat[A] va biz uni turga ega deb qaraymiz Ro'yxat[B]. Bir qarashda umumlashgan tipning tovushli ekanligi aniq bo'lmasligi mumkin, ammo agar dasturchi oddiyroq tur e'lon qilish bilan boshlasa, tip xatolar umumlashtirilishi kerak bo'lgan joyni ko'rsatib beradi.

Variant haqida xulosa chiqarish

Kompilyator avtomatik ravishda barcha ma'lumotlar turi parametrlari uchun eng yaxshi dispersiya izohlarini kiritadigan tip tizimini ishlab chiqish mumkin.[13] Biroq, tahlil bir necha sabablarga ko'ra murakkablashishi mumkin. Birinchidan, tahlil lokal bo'lmagan, chunki interfeysning o'zgarishi Men barcha interfeyslarning o'zgarishiga bog'liq Men eslatib o'tadi. Ikkinchidan, noyob eng yaxshi echimlarni olish uchun tizim imkon berishi kerak bivariant parametrlari (bir vaqtning o'zida birgalikda va qarama-qarshi bo'lgan). Va nihoyat, turdagi parametrlarning o'zgarishi, shubhasiz, shunchaki sodir bo'ladigan narsa emas, balki interfeys dizaynerining qasddan tanlagan tanlovi bo'lishi kerak.

Shu sabablarga ko'ra[14] aksariyat tillar juda oz farqli xulosa chiqarishadi. C # va Scala hech qanday farqli izohlarni keltirib chiqarmaydi. OCaml parametrlangan aniq ma'lumotlar turlarining xilma-xilligini keltirib chiqarishi mumkin, ammo dasturchi abstrakt turlarning (interfeyslarning) o'zgarishini aniq ko'rsatishi kerak.

Masalan, OCaml ma'lumot turini ko'rib chiqing T funktsiyani o'raydigan

turi ('a, 'b) t = T ning ('a -> 'b)

Tuzuvchi avtomatik ravishda shunday xulosa chiqaradi T birinchi parametrda qarama-qarshi, ikkinchisida kovariant. Dasturchi shuningdek, aniq izohlarni taqdim etishi mumkin, ular kompilyator tomonidan tekshiriladi. Shunday qilib, quyidagi deklaratsiya oldingisiga teng:

turi (-'a, +'b) t = T ning ('a -> 'b)

OCaml-dagi aniq izohlar interfeyslarni ko'rsatishda foydalidir. Masalan, standart kutubxona interfeysi Xarita.S assotsiatsiya jadvallari uchun xarita turi konstruktori natija turida kovariant degan izohni o'z ichiga oladi.

modul turi S =    sig        turi kalit        turi (+'a) t        val bo'sh: 'a t        val mem: kalit -> 'a t -> bool        ...    oxiri

Bu, masalan, mushuk IntMap.t ning pastki turi hayvon IntMap.t.

Saytdagi variatsion izohlar (joker belgilar)

Saytni e'lon qilish yondashuvining bir kamchiligi shundaki, ko'pgina interfeys turlari o'zgarmas bo'lishi kerak. Masalan, biz buni yuqorida ko'rdik Ilist o'zgarmas bo'lishi kerak edi, chunki unda ikkalasi ham bor edi Kiritmoq va GetEnumerator. Ko'proq xilma-xillikni aniqlash uchun API uslubchisi mavjud bo'lgan usullarning quyi to'plamlarini ta'minlaydigan qo'shimcha interfeyslarni taqdim etishi mumkin (masalan, faqat "faqat qo'shimchalar ro'yxati" mavjud) Kiritmoq). Biroq, bu tezda beparvo bo'lib qoladi.

Sayt-variance degani, istalgan dispersiya tur ishlatiladigan kodning ma'lum bir joyida izoh bilan ko'rsatilganligini anglatadi. Bu sinf foydalanuvchilariga subtitrlar uchun ko'proq imkoniyatlar yaratadi, sinf dizayneridan turli xil dispersiyalarga ega bo'lgan bir nechta interfeyslarni belgilash talab qilinmaydi. Buning o'rniga, umumiy parametr haqiqiy parametrlangan turga o'rnatiladigan nuqtada, dasturchi uning usullaridan faqat bir qismidan foydalanilishini ko'rsatishi mumkin. Aslida, umumiy sinfning har bir ta'rifi kovariant va qarama-qarshilik uchun mavjud bo'lgan interfeyslarni yaratadi qismlar o'sha sinfning.

Java orqali saytdagi tafovutli izohlar mavjud joker belgilar, cheklangan shakli chegaralangan ekzistensial turlari. Parametrlangan turni joker belgilar o'rnatishi mumkin ? yuqori yoki pastki chegara bilan birgalikda, masalan. Ro'yxat<? uzaytiradi Hayvon> yoki Ro'yxat<? super Hayvon>. Shunga o'xshash cheksiz joker belgi Ro'yxat<?> ga teng Ro'yxat<? uzaytiradi Ob'ekt>. Bunday tur ifodalaydi Ro'yxat<X> ba'zi bir noma'lum turi uchun X bu chegarani qondiradi. Masalan, agar l turi bor Ro'yxat<? uzaytiradi Hayvon>, keyin tekshirgich qabul qiladi

Hayvon a = l.olish(3);

chunki turi X ning pastki turi ekanligi ma'lum Hayvon, lekin

l.qo'shish(yangi Hayvon());

dan beri tip xatosi sifatida rad qilinadi Hayvon shart emas X. Umuman olganda, ba'zi bir interfeyslarni hisobga olgan holda Men<T>, an havolasi Men<? uzaytiradi T> qaerda interfeysdan usullardan foydalanishni taqiqlaydi T usul turiga zid ravishda uchraydi. Aksincha, agar l turi bor edi Ro'yxat<? super Hayvon> qo'ng'iroq qilish mumkin l.qo'shish lekin emas l.olish.

Java-da joker belgi subtitrini kub shaklida tasavvur qilish mumkin.

Java-da joker belgilar bilan parametrlanmagan turlar o'zgarmas bo'lsa-da (masalan, subtip aloqasi mavjud emas) Ro'yxat<Mushuk> va Ro'yxat<Hayvon>), joker belgilar turlarini yanada qattiqroq chegarani belgilash orqali aniqroq qilish mumkin. Masalan, Ro'yxat<? uzaytiradi Mushuk> ning pastki turi Ro'yxat<? uzaytiradi Hayvon>. Bu shablon belgilar turlarining ekanligini ko'rsatadi ularning yuqori chegaralarida kovariant (va shuningdek ularning pastki chegaralarida qarama-qarshi). Hammasi bo'lib, o'xshash belgilar belgisi berilgan C<? uzaytiradi T>, pastki turni shakllantirishning uchta usuli mavjud: sinfni ixtisoslashtirish C, yanada qattiqroq chegarani belgilash orqali T, yoki belgini almashtirish orqali ? ma'lum bir turdagi (rasmga qarang).

Yuqoridagi uchta subtitrning ikkitasini qo'llash orqali, masalan, turdagi argumentlarni o'tkazish mumkin bo'ladi Ro'yxat<Mushuk> kutgan usulga Ro'yxat<? uzaytiradi Hayvon>. Bu kovariant interfeys turlaridan kelib chiqadigan aniqlik. Turi Ro'yxat<? uzaytiradi Hayvon> ning faqat kovariant usullarini o'z ichiga olgan interfeys turi sifatida ishlaydi Ro'yxat<T>, lekin amalga oshiruvchisi Ro'yxat<T> uni oldindan belgilashga majbur emas edi.

Ma'lumotlarning umumiy tuzilishining umumiy holatida Ilist, kovariant parametrlari strukturadan ma'lumotlarni olish usullari uchun, qarama-qarshi parametrlar esa strukturaga ma'lumotlarni kiritish usullari uchun ishlatiladi. Kitobdan Producer Extends, Consumer Super (PECS) uchun mnemonic Samarali Java tomonidan Joshua Bloch kovaryans va kontrvariantsdan qachon foydalanishni eslashning oson usulini beradi.

Joker belgilar moslashuvchan, ammo kamchiliklari bor. Sayt-dispersiyasi API dizaynerlari interfeyslarga parametr parametrlari turlicha bo'lishini hisobga olmasliklarini anglatsa-da, ular ko'pincha murakkab usul imzolaridan foydalanishlari kerak. Umumiy misol quyidagilarni o'z ichiga oladi Taqqoslash mumkin interfeys. Deylik, biz to'plamdagi eng katta elementni topadigan funktsiyani yozmoqchimiz. Elementlarni amalga oshirish kerak taqqoslash usuli, shuning uchun birinchi urinish bo'lishi mumkin

<T uzaytiradi Taqqoslash mumkin<T>> T maksimal(To'plam<T> koll);

Ammo, bu tur etarli darajada umumiy emas - a ning maksimal qiymatini topish mumkin To'plam<Taqvim>, lekin a To'plam<Gregorian kalendar>. Muammo shundaki Gregorian kalendar amalga oshirmaydi Taqqoslash mumkin<Gregorian kalendar>, lekin buning o'rniga (yaxshiroq) interfeys Taqqoslash mumkin<Taqvim>. Java-da, C # -dan farqli o'laroq, Taqqoslash mumkin<Taqvim> ning kichik turi hisoblanmaydi Taqqoslash mumkin<Gregorian kalendar>. Buning o'rniga maksimal o'zgartirish kerak:

<T uzaytiradi Taqqoslash mumkin<? super T>> T maksimal(To'plam<T> koll);

Chegaralangan joker belgilar ? super T haqida ma'lumot beradi maksimal dan faqat qarama-qarshi usullarni chaqiradi Taqqoslash mumkin interfeys. Ushbu alohida misol umidsizlikka uchraydi, chunki barchasi usullari Taqqoslash mumkin ziddiyatli, shuning uchun shart juda ahamiyatli emas. Saytning deklaratsiyasi tizimi ushbu ta'rifni izohlash orqali ushbu misolni kamroq tartibsizlik bilan boshqarishi mumkin Taqqoslash mumkin.

Deklaratsiya-sayt va foydalaniladigan sayt izohlarini taqqoslash

Saytdagi variatsion izohlar qo'shimcha moslashuvchanlikni ta'minlaydi, bu esa ko'proq dasturlarni tekshirishga kiritish imkonini beradi. Biroq, ular tilga qo'shadigan murakkabligi uchun tanqid qilindi, bu esa murakkab turdagi imzolar va xato xabarlariga olib keldi.

Qo'shimcha egiluvchanlik foydali yoki yo'qligini baholashning bir usuli bu mavjud dasturlarda ishlatilishini ko'rishdir. Java kutubxonalarining katta to'plamini o'rganish[13] Joker belgilar izohlarining 39% to'g'ridan-to'g'ri deklaratsiya saytlari izohlari bilan almashtirilishi mumkinligini aniqladi. Shunday qilib, qolgan 61% Java saytlarni ishlatish tizimidan foydalanishdan foyda ko'radigan joylarning ko'rsatkichidir.

Sayt deklaratsiyasida tilda kutubxonalar kamroq farqni ko'rsatishi yoki ko'proq interfeyslarni belgilashi kerak. Masalan, Scala Collections kutubxonasi kovaryansni qo'llaydigan sinflar uchun uchta alohida interfeysni belgilaydi: umumiy usullarni o'z ichiga olgan kovariant bazaviy interfeys, yon ta'sir qiluvchi usullarni qo'shadigan o'zgarmas o'zgaruvchan versiya va strukturaviy ekspluatatsiya qilish uchun meros bo'lib o'tgan dasturlarni ixtisoslashtiradigan kovariant o'zgarmas versiya. almashish.[15] Ushbu dizayn deklaratsiya saytining izohlari bilan yaxshi ishlaydi, ammo ko'plab interfeyslar kutubxona mijozlari uchun murakkablik xarajatlarini keltirib chiqaradi. Va kutubxona interfeysini o'zgartirish imkoniyati bo'lmasligi mumkin, xususan, Java-ga umumiy so'zlarni qo'shishda bitta maqsad orqaga qarab ikkilikni saqlab qolish edi.

Boshqa tomondan, Java belgilarining o'zi murakkabdir. Konferentsiya taqdimotida[16] Joshua Bloch qo'llab-quvvatlashni qo'shganda, ularni tushunish va ishlatish juda qiyin deb tanqid qildi yopilish "Biz shunchaki boshqasini sotib ololmaymiz joker belgilar". Scala-ning dastlabki versiyalarida saytdagi variatsion izohlar ishlatilgan, ammo dasturchilar ularni amalda qo'llashda qiynalishgan, deklaratsiya qilingan sayt izohlari esa darslarni loyihalashda juda foydali bo'lgan.[17] Keyinchalik Scala versiyalari Java uslubidagi ekzistensial turlar va joker belgilarni qo'shdi; ammo, ko'ra Martin Oderskiy, agar Java bilan o'zaro ishlashga ehtiyoj bo'lmasa, ehtimol ular kiritilmagan bo'lar edi.[18]

Ross Teyt bahs yuritadi[19] Java joker belgilarining murakkabligining bir qismi ekzistensial turlarning bir shaklidan foydalangan holda saytning o'zgarishini kodlash to'g'risidagi qarorga bog'liq. Asl takliflar[20][21] dispersiya izohlari, yozish uchun maxsus sintaksisdan foydalanilgan Ro'yxat<+Hayvon> Java-ning yanada aniqroq o'rniga Ro'yxat<? uzaytiradi Hayvon>.

Joker belgilar ekzistensial turlarning bir shakli bo'lganligi sababli, ular dispersiyadan tashqari ko'proq narsalar uchun ishlatilishi mumkin. Shunga o'xshash tur Ro'yxat<?> ("noma'lum turdagi ro'yxat"[22]) moslamalarni usullariga o'tkazishga yoki ularning tur parametrlarini aniq ko'rsatmasdan maydonlarda saqlashga imkon beradi. Kabi sinflar uchun bu juda muhimdir Sinf bu erda usullarning aksariyati tip parametrlarini eslatib o'tmaydi.

Biroq, xulosa chiqarish chunki ekzistensial turlar qiyin muammo. Tuzuvchini amalga oshiruvchi uchun Java-ning joker belgilarini tekshiruvchini tugatish, turdagi argumentlarni chiqarish va noaniq dasturlar bilan bog'liq muammolar tug'diradi.[23] Umuman olganda hal qilib bo'lmaydigan umumiy dasturlardan foydalanadigan Java dasturi yaxshi yozilganmi yoki yo'qmi,[24] shuning uchun har qanday tekshirgich ba'zi dasturlar uchun cheksiz ko'chadan yoki vaqt tugashidan o'tishi kerak. Dasturchi uchun bu murakkab turdagi xato xabarlariga olib keladi. Java turi, joker belgilarni yangi turdagi o'zgaruvchilar bilan almashtirish orqali belgilash belgilarini tekshiradi konvertatsiya qilish). Bu xato xabarlarini o'qishni qiyinlashtirishi mumkin, chunki ular dasturchi to'g'ridan-to'g'ri yozmagan o'zgaruvchilar turiga ishora qiladi. Masalan, qo'shishga harakat qilish Mushuk a Ro'yxat<? uzaytiradi Hayvon> kabi xatolarni keltirib chiqaradi

usuli List.add (ta'qib qilish # 1) qo'llanilmaydi (mushukning haqiqiy argumentini # chaqiruv usulini chaqirishga aylantirish mumkin emas), bu erda # 1 ta'qib qilish yangi turdagi o'zgaruvchidir: # 1 ta'qib qilish Hayvonni ushlashdan uzaytiradimi? Hayvonni uzaytiradi

Sayt deklaratsiyalari va saytlarning ikkala izohlari ham foydali bo'lishi mumkinligi sababli, ba'zi bir tizimlar ikkalasini ham taqdim etadi.[13][19]

Terminning kelib chiqishi kovaryans

Ushbu atamalar tushunchasidan kelib chiqadi kovariant va qarama-qarshi funktsiyalar yilda toifalar nazariyasi. Kategoriyani ko'rib chiqing ob'ektlari turlar va morfizmlari pastki tipdagi munosabatlarni ifodalaydigan ≤. (Bu qisman tartiblangan har qanday to'plamni toifa sifatida ko'rib chiqishga misoldir.) Keyin, masalan, funktsiya turi konstruktori ikki turni oladi p va r va yangi turini yaratadi pr; shuning uchun u ob'ektlarni oladi ob'ektlarga . Ushbu funktsiya funktsiya turlari uchun kichik tip qoidalariga ko'ra birinchi parametr uchun ≤ ni o'zgartiradi va ikkinchisida saqlaydi, shuning uchun u birinchi parametrda qarama-qarshi funktsiyadir va ikkinchisida kovariant funktsiyadir.

Shuningdek qarang

Adabiyotlar

  1. ^ Bu faqat patologik holatda bo'ladi. Masalan, 'a t = int ni kiriting: har qanday turini qo'yish mumkin 'a va natija hali ham int
  2. ^ Func delegat - MSDN hujjatlari
  3. ^ Jon C. Reynolds (1981). Algol mohiyati. Algoritmik tillar bo'yicha simpozium. Shimoliy-Gollandiya.
  4. ^ Luka Kardelli (1984). Ko'p merosning semantikasi (PDF). Ma'lumotlar turlari semantikasi (Xalqaro simpozium Sofiya-Antipolis, Frantsiya, 1984 yil 27 - 29 iyun). Kompyuter fanidan ma'ruza matnlari. 173. Springer. doi:10.1007/3-540-13346-1_2.(Axborot va hisoblashdagi uzunroq versiya, 76 (2/3): 138-164, 1988 yil fevral).
  5. ^ Ellison, Chak. "Standard C ++ da qanday yangiliklar bor?".
  6. ^ "Fixing Common Type Problems". Dart Programming Language.
  7. ^ Bertrand Meyer (October 1995). "Static Typing" (PDF). OOPSLA 95 (Object-Oriented Programming, Systems, Languages and Applications), Atlanta, 1995.
  8. ^ a b Howard, Mark; Bezault, Eric; Meyer, Bertrand; Colnet, Dominique; Stapf, Emmanuel; Arnout, Karine; Keller, Markus (April 2003). "Type-safe covariance: Competent compilers can catch all catcalls" (PDF). Olingan 23 may 2013.
  9. ^ Franz Weber (1992). "Getting Class Correctness and System Correctness Equivalent - How to Get Covariance Right". TOOLS 8 (8th conference on Technology of Object-Oriented Languages and Systems), Dortmund, 1992. CiteSeerX  10.1.1.52.7872.
  10. ^ Giuseppe Castagna, Covariance and contravariance: conflict without a cause, ACM Transactions on Programming Languages and Systems, Volume 17, Issue 3, May 1995, pages 431-447.
  11. ^ Eric Lippert (3 December 2009). "Exact rules for variance validity". Olingan 16 avgust 2016.
  12. ^ Section II.9.7 in ECMA International Standard ECMA-335 Common Language Infrastructure (CLI) 6th edition (June 2012); onlayn mavjud
  13. ^ a b v John Altidor; Huang Shan Shan; Yannis Smaragdakis (2011). "Taming the wildcards: combining definition- and use-site variance" (PDF). Proceedings of the 32nd ACM SIGPLAN conference on Programming language design and implementation (PLDI'11). Arxivlandi asl nusxasi (PDF) 2012-01-06 da.
  14. ^ Eric Lippert (October 29, 2007). "Covariance and Contravariance in C# Part Seven: Why Do We Need A Syntax At All?". Olingan 16 avgust 2016.
  15. ^ Marin Odersky; Lex Spoon (September 7, 2010). "The Scala 2.8 Collections API". Olingan 16 avgust 2016.
  16. ^ Joshua Bloch (November 2007). "The Closures Controversy [video]". Presentation at Javapolis'07. Arxivlandi asl nusxasi 2014-02-02 da. 2013 yil may oyida olingan. Sana qiymatlarini tekshiring: | kirish tarixi = (Yordam bering)CS1 tarmog'i: joylashuvi (havola)
  17. ^ Martin Odersky; Matthias Zenger (2005). "Scalable component abstractions" (PDF). Proceedings of the 20th annual ACM SIGPLAN conference on Object-oriented programming, systems, languages, and applications (OOPSLA '05).
  18. ^ Bill Venners and Frank Sommers (May 18, 2009). "The Purpose of Scala's Type System: A Conversation with Martin Odersky, Part III". Olingan 16 avgust 2016.
  19. ^ a b Ross Tate (2013). "Mixed-Site Variance". FOOL '13: Informal Proceedings of the 20th International Workshop on Foundations of Object-Oriented Languages.
  20. ^ Atsushi Igarashi; Mirko Viroli (2002). "On Variance-Based Subtyping for Parametric Types" (PDF). Proceedings of the 16th European Conference on Object-Oriented Programming (ECOOP '02). Arxivlandi asl nusxasi (PDF) 2006-06-22.
  21. ^ Kresten Krab Thorup; Mads Torgersen (1999). "Unifying Genericity: Combining the Benefits of Virtual Types and Parameterized Classes" (PDF). Object-Oriented Programming (ECOOP '99). Arxivlandi asl nusxasi (PDF) 2015-09-23. Olingan 2013-10-06.
  22. ^ "The Java™ Tutorials, Generics (Updated), Unbounded Wildcards". Olingan 17 iyul, 2020.
  23. ^ Tate, Ross; Leung, Alan; Lerner, Sorin (2011). "Taming wildcards in Java's type system". Proceedings of the 32nd ACM SIGPLAN conference on Programming language design and implementation (PLDI '11).
  24. ^ Radu Grigore (2017). "Java generics are turing complete". Proceedings of the 44th ACM SIGPLAN Symposium on Principles of Programming Languages (POPL'17). arXiv:1605.05274. Bibcode:2016arXiv160505274G.

Tashqi havolalar