هموردایی و پادوردایی (علوم رایانه)
سیستم گونه سازی در بسیاری از زبانهای برنامهنویسی زیرگونه سازی را پشتیبانی میکند. برای نمونه، اگر کلاس A زیرگونهای از کلاس B باشد، عبارتی از گونه A میتواند هرجاییکه یک عبارت از گونه B وجود داشته باشد، بکار رود. هموردایی[1] به ارتباط زیرگونه سازی در گونههای پیچیده (لیستی از Aها در برابر لیستی از Bها، متودی که A را برمیگرداند در برابر متودی که B را برمیگرداند، و …) و مؤلفههای آنها گفته میشود. بسته به وردایی type constructor، رابطه زیرگونه سازی ممکن است حفظ شود، برعکس شود یا نادیده گرفته شود. برای نمونه در اکمل «لیستی از Aها» زیرگونه از «لیستی از Bها» است چراکه constructor لیست هموردا است، درحالیکه متودی با وردودی B و خروجی String زیرگونهای از متودی با ورودی A و خروجی String است چراکه Function type constructor پادوردا[1] در نوع پارامترهاست.
طراح زبان برنامهنویسی مسئله وردایی را در طراحی گونه سازی در آرایهها، وارثت، و انواع داده generic در نظر میگیرد. با بکارگیری type constructorهای هموردا و پادوردا به جای ناوردا، بیشتر برنامهها به عنوان برنامههای well-typed پذیرفته میشوند. از سویی دیگر، اکثر برنامه نویسان پادوردایی را غیرشهودی مییابند و ردیابی دقیق وردایی برای اجتناب از خطاهای زمان اجرا، منجر به قواعد گونه سازی پیچیده میشود. به منظور سادهسازی سیستم گونه سازی، یک زبان برنامهنویسی ممکن است type constructor را به صورت ناوردا در نظر بگیرد حتی اگر وردا در نظر گرفتن آن خطری نداشته باشد یا به صورت هموردا در نظر بگیرد حتی اگر type safety زیر سؤال برود.
واژه شناسی
فرهنگستان زبان فارسی، وردیدن از ریشه باستانی ورت (ورتیدن)، را بجای فعل to vary برگزیده است و از این فعل مشتقات وردایی(variance)،وردش(variation)، وردا(variant)، هموردا(covariant)، هم وردایی(covariance)، ناوردا(invariant)، ناوردایی(invariance)، پادوردا(contravariance) را برساخته است.
تعریف رسمی
در سیستم گونه سازی یک زبان برنامهنویسی روش گونه سازی یا type constructor
- همورداست اگر ترتیب زیرگونه ها(≤) از گونههای خاص تر به گونههای عام تر حفظ شود.
- پادورداست اگر ترتیب زیرگونهها برعکس شود.
- دوورداست اگر همزمان
I<A> ≤ I<B>
وI<B> ≤ I<A>
درست باشد. - ناورداست اگر هیچکدام از موارد پیش گفته نباشد.
نمونههای #C
برای نمونه در سی شارپ:
- <IEnumerable <A یک زیرگونه از <IEnumerable <B است. زیرگونهسازی حفظ شدهاست چرا که در سی شارپ
<IEnumerable<T
هموردا است. <Action<B
یک زیرگونه از<Action<A
است. زیرگونه سازی برعکس شدهاست چرا که در سی شارپ<Action<T
پادوردا است.<List<A
و هیچکدام زیرگونهٔ هم نیستند چرا که در سی شارپ<List<T
روی T ناوردا است.
ارث بری در زبانهای شی گرا
وقتی یک کلاس فرزند یک متود از یک کلاس پدر را Override میکند، کامپایلر باید درستی نوع متود را چک کند. در برخی از زبانها نوع باید دقیقاً منطبق بر نوع کلاس پدر باشد (ناوردایی). بر اساس روش زیرگونه سازی معمول برای function typeها، متود override شده میتواند نوع خاص تری را برگرداند (هم وردایی) و نوع عام تری را به عنوان آرگومان ورودی بپذیرد (پادوردایی نوع آرگومان). در نمادگان UML، حالتهای ممکن عبارتند از
- زیرگونه سازی نوع آرگومان ورودی یا مقدار بازگشتی متود.
- ناوردایی. signature متود override شده تغییر نمیکند، نوع آرگومان ورودی و نوع مقدار بازگشتی متود ثابت میماند.
- هموردا در نوع مقدار بازگشتی. رابطه زیرگونه همانند رابطه ClassA و ClassB و در همان جهت است.
- پادوردا در نوع آرگومان.رابطه زیرگونه برعکس رابطه ClassA و ClassB است.
- هموردا در نوع آرگومان.در این حالت type safe نیست.
برای داشتن نمونههای ملموس، فرض کنید کلاسی داریم برای مدل کردن یک پناهگاه جانوران. همچنین کلاس Cat زیرگونه ای از کلاس Animal است.
class AnimalShelter {
Animal getAnimalForAdoption() {
...
}
void putAnimal(Animal animal) {
...
}
}
پرسش: اگر از کلاس AnimalShelter یک زیرگونه بسازیم چه انواعی برای getAnimalForAdoption و putAnimal پذیرفته میشوند؟
هموردایی در نوع مقدار بازگشتی
در زبانی که مقدار بازگشتی هموردا را پشتیبانی میکند، کلاس مشتق شده میتواند متود getAnimalForAdoption را override کند و متود override شده نوع خاص تری را بازگرداند:
class CatShelter extends AnimalShelter {
Cat getAnimalForAdoption() {
return new Cat();
}
}
در میان زبانهای شی گرا، Java و C++ نوع مقدار بازگشتی هموردا را پشتیبانی میکنند در حالیکه C# پشتیبانی نمیکند. افزودن نوع مقدار بازگشتی هموردا یکی از نخستین اصلاحات زبان C++ بود که توسط کمیته استاندارد در سال ۱۹۹۸ تأیید شد.[2]
Scala و D نیز نوع مقدار بازگشتی هموردا را پشتیبانی میکنند.
هموردایی نوع آرگومان متود
در زبان Eiffel یک متود override شده میتواند نوع خاص تری از نوع آرگومان متود کلاس پدر خود بپذیرد (هموردایی در نوع آرگومان). بنابراین، کد زیر را ببینید:
class CatShelter extends AnimalShelter {
void putAnimal(Cat animal) {
...
}
}
این type safe نیست. چرا که با تبدیل CatShelter به AnimalShelter (به اصلاح up-casting)، میتوان هنگام نوشتن برنامه، یک سگ را در پناهگاه گربهها قرار داد که با توجه به تجاوز از محدودیتهای آرگومان CatShelter، در زمان اجرا خطا میدهد. نبود Type safety (که به عنوان "catcall problem" در جامعه Eiffel نیز شناخته میشود) به عنوان مشکل اساسی مطرح است.
منشأ اصطلاح هموردایی
این اصطلاحات از مفهوم عملگر در نظریه ردهها آمدهاست. رده را در نظر بگیرید که اشیاع آن نوعها هستند و ریختارهای آن روابط زیرگونهها را نشان میدهند ≤. برای نمونه یک function type constructor دو نوع p و r را میگیرد و نوع جدید p → r را ایجاد میکند؛ بنابراین اشیایی در را به اشیایی در میبرد. بر اساس روش زیرگونه سازی برای function typeها این عملیات ≤ را برای آرگومان نخست برعکس میکند و برای برای آرگومان دوم حفظ میکند؛ بنابراین این عملگر در آرگومان نخست پادوردا و در آرگومان دوم همورداست.
جستارهای وابسته
پانویس
- مصوب فرهنگستان زبان فارسی
- Allison, Chuck. "What's New in Standard C++?". Archived from the original on 27 May 2012. Retrieved 12 September 2017.