تابع خطی
از توابع خطی برای بهبود کیفیت برنامه و یا تعریف پارامتر های جنریک نوع reified استفاده میشه.
فرایند اجرای کد های کاتلین در jvm
هنگام کامپایل کد های کاتلین ابتدا تبدیل به کد های جاوا شده و سپس با کامپایلر جاوا به کد های خوانا توسط jvm تبدیل میشن.

تعریف تابع خطی
هنگامی که یک تابع مرتبه بالا تعریف میکنیم لامبدا هایی که به عنوان پارامتر تابع تعریف کردیم هرکدوم یک Object هستند که میتونن فضای حافظه رو اشغال کنن.
برای بهبود کیفیت برنامه میتونیم از توابع خطی (inline) در کاتلین استفاده کنیم تا از دست ابجکت هایی که حافظه رو اشغال کردن خلاص بشیم.
به کد زیر دقت کنید
در بالا یک تابع مرتبه بالا داریم و یک عبارت لامبدا رو به عنوان پارامتر براش تعریف کردیم. اگه کد رو بخوایم کامپایل کنیم قبلش تو جاوا یه چیزی شبیه زیر میشه:
وقتی بخوایم تابعو صدا بزنیم:
به چیزی شبیه زیر تو جاوا تبدیل میشه:
همینطور که ملاحظه کردید اگه بخوایم تابع foo رو به صورت معمولی ایجاد کنیم یک آبجکت از Function ایجاد میشه که حافظه رو اشغال میکنه.
حالا تابع foo رو با استفاده از کلید واژه ی inline تعریف میکنیم:
وقتی تابعو مثل قبل صدا کنیم کامپایلر کد ها رو مثل زیر از تابع میندازه بیرون:
دیگه خبری از Function نیست و عبارت block به صورت تابع ایجاد شد؛ همین در بهبود کیفیت مخصوصا زمانی که حافظه رو با آبجکت های زیادی اشغال کرده باشیم میتونه کمک کنه.
نکات قابل توجه هنگام تعریف تابع خطی
۱- از تعریف توابع بزرگ (به لحاظ زیاد بودن کد های داخل تابع) باید خودداری کرد.
۲- اگه عبارت لامبدا رو به صورت inline تعریف کنیم فقط میتونیم در توابع خطی صداش بزنیم یا به صورت پارامتر به توابع خطی پاس بدیم.
۳- توابع خطی نمیتونن به توابع و متغیر های private دسترسی داشته باشن، در مورد internal ها باید با @PublishedApi علامتگذاری بشن.
کلیدواژه ی noinline
هنگامی که یک تابع مرتبه ی بالا رو به صورت خطی تعریف میکنیم، تمام پارمتر ها خطی میشن، اگه بخوایم بعضی از پارامتر ها خطی نباشن از کلیدواژه ی noinline استفاده میکنیم.
مثال:
در بالا bar خطی و baz غیر خطی است.
استفاده از return غیر محلی
هنگام تعریف عبارت لامبدا به طور اشکار از return نمیشه استفاده کرد مگه با تعریف برچسب برای عبارت اما اگه لامبدا خطی باشه میتونیم داخل لامبدا مستقیم از return (فقط برای متوقف کردن تابع) استفاده کنیم.
به این return غیر محلی گفته میشه چون تابع بیرون لامبدا هم متوقف میکنه.
مثال:
در زیر از return یک بار به صورت غیر محلی استفاده کردیم و یک بار به صورت محلی با تعریف برچسب op برای operator.
کلیدواژه ی crossinline
بعضی از پارامتر های لامبدایی که برای تابع خطی تعریف میکنیم، ممکنه به صورت مستقیم داخل تابع صدا زده نشن و در یک تابع یا ابجکت داخل تابع خطی صداشون کنیم؛ اما اجازه نداریم از خطی داخل غیر خطی استفاه کنیم چون نمیشه داخل تابع غیر خطی از return غیر محلی استفاده کرد. در اینجا باید پارامتر تابعو با کلیدواژه ی crossinline تعریف کنیم.
مثال:
فرض کنید تابع foo غیر خطی و تابع bar خطی باشه، میخوایم foo رو داخل bar صدا بزنیم و از پارامتر bar داخل foo استفاده کنیم.
مثال:
در مثال بالا یک object از نوع Runnable داخل foo تعریف کردیم و body رو داخل آبجکت صدا زدیم.
پارامتر های Reified Type
توابعی که پارامتر های نوع جنریکشون reified است باید خطی باشن.
داخل بدنه ی تابع جنریک نمیشه به پارامتر های جنریک (مثلا T) دسترسی داشت چون فقط T هنگام کامپایل وجود داره و زمان اجرا پاک میشه. اما اگه نوع T با reified تعریف شده باشه میتونیم بهش زمان اجرا دسترسی داشته باشیم.
با بیان یک مثال میخوایم بررسی کنیم یک آبجکت نمونه ای از یک کلاس هست یا خیر؟
اگه یک تابع جنریک برای این کار تعریف کنیم، برنامه دچار خطا میشه:
برای حل این موضوع یا باید از reflection در تابع جنریک استفاده کنیم یا یک تابع خطی جنریک تعریف کنیم که پارامتر نوع جنریکش reified باشه.
مثال:
در بالا یک پارامتر جنریک نوع T با reified تعریف کردیم.
پراپرتی (property) های خطی
کلیدواژه ی inline میتونه برای getter و setter های property که backing field ندارن استفاده بشه.
مثال:
همچنین میتونیم کل property رو خطی کنیم:
به پراپرتی که در مثال دیدید property های خطی در کاتلین میگیم.
خلاصه
- از توابع خطی برای بهبود کیفیت برنامه و تعریف پارامتر reified استفاده میشه.
- هنگام استفاده از کلیدواژه ی inline تابع و پارامتر هاش خطی میشه.
- پارامتر توابع خطی با استفاده از کلیدواژه ی noinline میتونن غیر خطی بشن.
- در لامبدا های خطی میتونیم از return غیر محلی برای متوقف کردن تابع استفاده کنیم
- با استفاده از کلیدواژه ی crossinline میتونیم پارامتر های خطی رو در غیر خطی های داخل تابع صدا بزنیم.
- میتونیم برای تابع خطی جنریک های reified تعریف کنیم.
- میتونیم getter و setter های پراپرتی ها رو به صورت خطی تعریف کنیم یا کل پراپرتی رو خطی کنیم.