داستان Null در دارت(میرزا قلی کلاس آنلاین برگزار میکند)

خب بعد از اینکه Dart برای سر و سامون دادن به وضعیت خودش و خلاص شدن از دست برنامه نویس ها و مشکلات زیادی که Null درست کرده بود یه آپدیت بزرگ داد و Null رو که حالا یه بچه سر راه مونده بود رو جمع و جورش کرد, میرزا قلی(همون برنامه نویس فلاتر) تصمیم گرفت که برای بچه های دهشون یعنی قل آباد یه کلاس آموزشی آنلاین بگذاره و این چیزای جدید رو بهشون آموزش بده و کلی بین بچه های دهشون کلاس بگذاره که اره من خیلی بلدمممم.???

قبل از اینکه بریم ببینیم توی کلاس های آنلاین میرزا قلی چه اتفاقایی افتاد بهتون بگم که میتونید قسمت قبلی این داستان رو از طریق این لینک دنبال کنید و همچنین برای اینکه در جریان همه قسمت های این مجموعه قرار بگیرید هم این لینک رو ببینید.دیگه نمیگم که لایک این پست هم یادتون نره و یه سری هم به کانال فلاترمون بزنید.

خب بریم سر کلاس های میرزا قلی....

بعد از تبلیغات فراوااان سه نفر توی کلاس ها ثبت نام کردن. قل مراد, ناز قل و میرزا قلمدون.

جلسه اول شروع شد و میرزا قلی شروع کرد به تعریف کردن از کلاس های خودش که مثل این کلاس رو هیچ جا نمیتونید پیدا کنید و این اولین و تنهاترین دوره آموزشی فارسی هست که به این موضوع میپردازه و اگه توی کل قل آباد بگردید کسی رو پیدا نمیکنید که این ها رو بلد باشه و بعد از این دوره میتونید در هر شرکتی که دوست داشته باشید استخدام بشید و این حرفا ...

بعدش شروع کرد به صحبت کردن در مورد Null و گفتش که Dart یه Type جدید اضافه کرده و با اضافه کردن یه ? به Type های قبلی میتونیم یه Type جدید داشته باشیم.

Type => non nullable Type
Type? => nullable Type
String => non nullable
String? => nullable String

بعد از گفتن این ها میرزا قلی گفتش که میخوام یه سری نکته بهتون بگم که هیچکسی بهتون نمیگه...

نکته اول:

قبل از null safety هر variable ای رو که تعریف میکردی میتونستی همون موقع بهش مقدار ندی و چون که Null فرزند همه کلاس ها بود و اون variable میتونست مقدار null رو هم بگیره, اگه موقع تعریف یه variable بهش مقدار نمیدادی باعث میشد که مقدار اون variable به صورت پیش فرض برابر با null بشه.

دارت پد رو با فلگ nullSfaty = false باز کنید که این مثال رو با هم ببینیم :

https://dartpad.dev/?null_safety=false

میبینید که یه variable تعریف کردم و بهش مقدار ندادم و مقدارش به صورت پیش فرض برابر با null شده.

حالا میخوام بهتون یه نکته ای بگم که کیف کنید...

بعد از null safety قضیه بالا رو میشه به این صورت گفت :‌

  • اگه یک variable رو از نوع nullable تعریف کنیم(یعنی با ?), میتونیم همون اول کار بهش مقدار ندیم و مقدار اون به صورت پیش فرض برابر با null میشه.
  • و اگه یه variable رو از نوع معمولی یا non-nullable تعریف کنیم (یعنی بدون ?), چون که دیگه نمیتونه به هیچ وجه مقدار null رو بگیره باید همون اول اول که تعریفش کردیم بهش یه مقدار هم بدیم.

مثلن :

توی کد بالا یه variable از جنس String تعریف کردم و بهش مقدار ندادم و بهم خطا داده :

میبینید که گفته تو یه non-nullable variable تعریف کردی و باید همون اول مقدار دهیش کنی.

ولی :

اینجا یه variable از جنس nullable String تعریف کردم و بهش مقدار ندادم و همه چی درسته.چون که این variable میتونه مقدار null رو هم بگیره.

و وقتی که بهش هیچ مقداری ندی به صورت پیش فرض مقدار null رو میگیره.

میرزا قلی که با گفتن این نکته کلی کیف کرده بود و لپاش گل انداخته بود ناگهان با صدای قل مراد از جا پرید.

قل مراد :‌ پس چرا توی این حالت اینجوری نیست ؟؟

میرزا قلی :‌ کدوم حالت؟‌ چی داری میگی؟

قل مراد : ببین,

یه function تعریف کردم و داخلش یه variable از جنس String (بدون ? و از نوع non-nullable ) تعریف کردم ولی بهم هیچ خطایی نداده و نگفته که همون اول باید مقدار دهیش کنی.

این که با اون نکته ای که شما گفتید مطابقت نداره که.

میرزا قلی : حتمن Dart ات آپدیت نیست.

قل مراد : نه همه چی درسته.

میرزا قلی :‌ حتمن VPN ات وصل نیست.

همه شاگردا با هم :‌ عهههه آقا چه ربطی داره.

میرزا قلی :‌ ربط دارهههه. بذارید توی سیستم خودم بزنم.

میرزا قلی توی سیستم خودش زد و همون نتیجه قل مراد رو گرفت و دید که بنده خدا داره راست میگه ولی زیر بار نرفت و گفت چون Dart تازه آپدیت داده حتمن باگ داره. وگرنه نکته ای که گفتم درسته و مو لای درزش نمیره. ولی چون اعصابش خورد شده بود گفت برای امروز کافیه و جمع کنید بریییییدددد.

نکته ای که میرزا قلی گفت و سوتی ای که قل مراد ازش گرفت رو توی ذهنتون نگه دارید که بعدن ببینیم واقعن Dart باگ داشته و یا علم میرزا قلی نم کشیده بوده.

اون شب توی گروه تلگرام همه بچه ها که میرزا قلی رو خیلی قبول داشتن شروع کردن به بد گفتن در مورد Dart که به درد نمیخوره و kotlin خیلی بهتره و کاش زبون فلاتر هم kotlin بود و خاک تو سر گوگل....


بگذریم بریم ببینیم توی جلسه بعدی چی شد...

اول این جلسه نازقل از میراز قلی پرسید : استاد برای مشکلی که جلسه قبلی پیش اومد فکری نکردید؟

میرزا قلی : نه اون که باگ Dart هست. حتمن توی آپدیت بعدی درست میشه وگرنه نکته ای که من گفتم درسته.حالا میرم github و یه issue باز میکنم. نگران نباشید.(کلی هم قیافه گرفت که مثلن از github سر در میاره و ... .)

ولی این جلسه میخوام راجب آرگومان های ورودی function ها و constructor ها بگم.

توی Dart آرگومان های یک function (ورودی های یک function) به دو دسته کلی تقسیم میشن:

  • Positional

در این نوع رعایت ترتیب مهمه و باید موقع call کردن function با همون ترتیبی که ورودی ها رو تعریف کردیم بهشون مقدار بدیم.در واقع در این حالت آرگومان ها با موقعیت یا position ای که دارن شناخته میشن و رعایت تناظر بین Position تعریف و مقدار دهی این ارگومان ها مهمه.

  • Non-positional (or named arguments)

در این نوع ترتیب مهم نیست و آرگومان ها با اسمشون شناخته میشن و موقع call کردن function با ذکر نام آرگومان بهش مقدار میدیم و رعایت تناظر بین Position تعریف و مقدار دهی آرگومان ها مهم نیست.

پس نوع اول با position اشون شناخته میشن و نوع دوم با Name اشون.

میرزا قلمدون :‌ من نفهمیدم چی گفتید.

قل مراد : صبر کن با مثال متوجه میشی.

حالا نوع اول خودشون به دو دسته تقسیم میشن:

  • Required
  • Optional

که Required ها اجباری هستن و موقع call کردن function حتمن باید بهشون مقدار بدیم و Optional ها اختیاری هستن.

نازقل :‌ استاد نوع Named Arguments دو حالت ندارن ؟

قل مراد : نه, اون ها رو میتونیم بگیم که همیشه اختیاری هستن.

پس با این حرفا میتونیم بگیم سه حالت داریم :

  • Required positional arguments

با Position اش شناخته میشه و رعایت تناظر بین Position تعریف و مقداردهی مهمه و اجباری هست و حتمن باید مقدار بگیره.

  • Optional positional arguments

با Position اش شناخته میشه و رعایت تناظر بین Position تعریف و مقداردهی مهمه و اختیاری هست و میتونه مقدار نگیره.

  • Optional non-Positional arguments (or named arguments)

با اسمش شناخته میشه و رعایت تناظر بین Position تعریف و مقدار دهیش (موقع call کردن ) اهمیتی نداره و اختیاری هم هست و میتونه مقدار نگیره.

قل مراد که گفتی نفهمیدم مثال ها رو خوب گوش کن که بفهمی...

کد زیر رو در نظر بگیرید و فرض کنید که این کد برای قبل از null safety هست :‌

میبینید که دو تا آرگومان اول به صورت معمولی تعریف شدن ولی ارگومان سومی توی [ ] تعریف شده. حالا موقعی که میخوایم این function رو call کنیم :

باید سه تا مقدار بهش پاس بدیم و این سه مقدار به ترتیب به آرگومان ها اختصاص پیدا میکنن.

firstRequiredPositionalArg => 'first required
secondRequiredPositionalArg => 'second required'
optionalPositionalArg  => 'optional'

ترتیب اینجا خیلی مهمه و باید به همون ترتیبی که آرگومان ها تعریف شدن به همون ترتیب هم مقادیر به function پاس داده بشه. به همین دلیل به این نوع آرگومان ها میگن Positional, یعنی اینکه موقعیت قرارگیری شون مهمه و باید با همون موقعیتی که تعریف شدن هم مقدارشون به function پاس داده بشه.

ولی نکته که وجود داره میتونیم این function رو به صورت زیر هم call کنیم.

یعنی همون طور که میبینید مقدار سوم رو بهش پاس ندیم و فقط دو تا مقدار بهش پاس دادم. و میبینید طبق نتیحه و print هایی که گرفتم مقدار positionalOptionalArg برابر با null شده. اون هم به خاطر این هست که آرگومان positionalOptionalArg توی [ ] قرار گرفته و باعث میشه که این آرگومان اختیاری بشه و چون که گفتم فرض کنید قبل null safety هست, وقتی که برای این آرگومان هیچی پاس ندیم مقدارش برابر با null میشه.

به همین دلیل به این ها میگن Positional و به نوع اول که داخل [ ] قرار نمیگیره میگن required چون که حتمن باید موقع call کردن function براشون یه مقداری به function پاس بدیم و به نوع دوم که توی [ ] قرار میگیره میگن optional چون که میتونیم براشون چیزی پاس ندیم و اگ چیزی پاس ندادسم مقدارشون به صورت پیش فرض null میشه (قبل null safety)

حالا مثال زیر رو ببینید :‌

حالا میخوام function بالا رو call کنم و به firstPositionalOptionalArg مقدار ندم ولی به secondPositionalOptionalArg مقدار بدم. آیا میشه؟

جواب نه هست و چون اینجا ترتیب مهم هست نمیشه یهویی سومی رو ول کرد به امان خدا و هیچی بهش نداد و به چهارمی مقدار داد.

پس اینجوری مقدار میدم.

که اینجوری سومی null میشه (خودم صریحن گفتم که null شه چون چاره نداشتم و نمیتونستم بهش مقدار ندم ) و به چهارمی مقدار دلخواه خودم رو دادم.

یه نکته خوب اینکه میتونیم برای نوع Optional (یعنی [ ]) مقدار Default تعیین کنیم.

اینجوری موقع call کردن اگه چیزی براشون پاس ندیم به جای null شدن مقدار Default رو میگیرن.

و نکته دیگه اینکه حتمن اون هایی که required هستن یعنی داخل [ ] قرار نمیگیرن باید قبل از اون هایی بیان که optional هستن.یعنی اینجوری تعریف کردن غلطهههه:

حتمن Optional ها باید برن آخر آخر.... اول همه Required ها و اخر کار Optional ها .

دلیلش رو هم خودتون فکر کنید ببینید واسه چیه.

نازقل :‌ عه استاد بگید واس چیه؟

میرزا قلی :‌ همینه که هست, یکم فک کن.

حالا بریم سر اون یکی دسته یعنی :

Optional non-Positional arguments (or named arguments)

توی مثال بالا میبییند که دو تای اولی مثل قبل تعریف شدن ولی سومی و چهارمی یه تفاوتی دارن و اون هم این هستش که داخل { } تعریف شدن. و این باعث میشه که موقع call کردن function بتونیم بدون رعایت کردن ترتیب و با استفاده از اسمشون به اونا مقدار بدیم.

میبینید که برای دو تای اولی ترتیب مهم هست چون که از نوع positional هستن و برای سومی و چهارمی ترتیب مهم نیست و اون ها رو با اسمشون مقدار دادم. یعنی حالت زیر هم درسته :

میبینید که اینجا ترتیب مقدار دادن سومی و چهارمی رو عوض کردم و باز هم درسته چون که این ها رو با استفاده از اسمشون میشناسیم و بهشون میگیم Non-positional args یا Named args ولی دسته قبلی رو با استفاده از موقعیت یا Position اشون میشناختیم و بهشون میگفتیم Positional args.

حالا اگه فرض کنیم قبل null safety هستیم و به named args هامون مقدار ندیم چی میشه ؟

میبینید که اگه مقداری پاس ندم مقدارشون برابر با null میشه.پس قبل از null safety اینطوری بوده که Named arg ها اختیاری بودن و اگه چیزی واسشون پاس نمیدادیم مقدارشون برابر null میشد.

ولی اینجا هم میتونستیم مثل Optional positional arg بهشون مقدار Default بدیم.

و نکته آخر اینکه توی یک function نمیتونیم هم زمان Named args و Positional Optional args رو داشته باشیم.

و نکته آخرتر این که Named arg ها هم باید آخر کار و بعد از همه Positional Required arg ها تعریف بشن.

پس :

  • نوع اول آرگومان ها Positional arg ها هستن که با موقعیتشون شناخته میشن و باید به همون ترتیبی که تعریف شدن بهشون موقع call کردن function مقدار بدیم.(تناظر بین Position تعریف و مقداردهی)
  • این نوع یعنی Positional arg ها به دو دسته تقسیم میشن :‌ Required , Optional . دسته اول یعنی Required ها به صورت معمولی تعریف میشن و دسته دوم یعنی Optional ها داخل [ ] .
  • دسته دوم رو میتونیم موقع call کردن function بهشون مقدار ندیم و در صورت مقدار ندادن مقدارشون null میشه و همچنین میتونیم براشون موقع تعریف مقدار Default مشخص کنیم.
  • نوع Optional همیشه باشد آخر کار و بعد از Required ها تعریف بشن.
  • نوع دوم آرگومان ها Named arg ها یا Non-positional arg ها هستن که با اسمشون شناخته میشن و موقع call کردن function باید با اسمشون بهشون مقدار بدیم و ترتیب اون ها مهم نیست.
  • نوع دوم یعنی Named arg ها باید همیشه بعد از Positional ها تعریف بشن (یعنی آخر کار)
  • همزمان توی یک function نمیشه هم Named arg داشت و هم Optional positional arg arg.
  • قبل از null safety اگه به Optional positional arg یا Named arg ها مقدار نمیدادیم مقدارشون null میشد.مگر اینکه براشون مقدار Default مشخص میکردیم.


تا اینجا همه چی داشت خوب پیش میرفت که ناگهان...

نازقل : استاد اینایی که گفتی که همه رو گفتی فرض کیند قبل null safety هست پس بعدش چی ؟

قل مراد :‌ قضیه خیلی سادس.

بعد از null safety ما دو نوع Type داریم.

Type => Non-nullable Type
Type? => Nullable Type

حالا

  • برای نوع اول آرگومان ها یعنی Required positional arguments :

برای این ها همیشه باید مقدار بدیم و ترتیب هم مهمه. حالا اگه آرگومانی که تعریف کردیم از نوع Type بود موقع call کردن نمیتونیم بهش مقدار null بدیم ولی اگه از نوع ?Type بود میتونیم بهش مقدار null هم بدیم.

میبینید که در کد بالا یه function با دو تا آرگومان دارم که هر دو Required positional arguments هستند ولی اولی non-nullable و دومی nullable هست و همون طور که میبینید موقع call کردن به اولی نمیتونم null بدم ولی به دومی میتونم.


  • برای نوع دوم یعنی Optional positional arguments:

برای این ها بعد از null safety اگه آرگومان رو از نوع ?ُType تعریف کردیم میتونیم موقع call کردن بهش مقدار ندیم و به صورت پیش فرض مقدار null میگیره (مگر اینکه براش Default تعریف کرده باشیم که در این صورت اگه بهش مقدار ندیم مقدار Default رو میگیره) و اگه آرگومان رو از نوع Type تعریف کردیم چون که دیگه نمیتونه مقدار null رو بگیره و احتمال داره که موقع call شدن چیزی براش پاس داده نشه در نتیجه موقع تعریف ارگومان باید حتمن واسش مقدار Default تعریف کنیم.

کد بالا رو بببیند. یه function داریم با دوتا آرگومان که هر دو از نوع Optional positional arguments هستند ولی اولی non-nullable و دومی nullable هست. همون طوری که میبینید برای دومی که nullable هست هیچ مشکلی نداریم چون که اگه بهش مقداری پاس ندیم میتونه مقدار null بگیره ولی برای اولی که non-nullable هست خطا گرفته. چرا که این آرگومان یه آرگومان اختیاری هست و میتونیم بهش مقداری پاس ندیم ولی چون که نمیتونه مقدار null رو بگیره وقتی که بهش هیچی پاس ندیم سرگردون و حیروون میمونه و نمیدونه باید چکار کنه و چه مقداری بگیره.

راه حل چیه ؟

را حل اینه که یا بهش یه مقدار Default بدیم که در این صورت اگه موقع call کردن چیزی بهش پاس ندادیم مقدار Default رو بگیره :‌

یا اینکه اون رو از حالت Optional بودن در بیاریم و Required کنیم.


  • اما برای نوع سوم یعنی Optional non-Positional arguments (or named arguments):

این حالت هم شبیه حالت دوم میشه. یعنی اگه آرگومان رو از نوع ?Type یا nullable تعریف کردیم میتونیم موقع call کردن بهش مقداری ندیم و مقدارش در این صورت برابر با null میشه(البته اگه براش مقدار Default تعیین کرده باشیم در این حالت مقدار Default رو میگیره) و اگه آرگومان از نوع Type یا non-nullable باشه چون که دیگه نمیتونه مقدار null رو بگیره و موقع call شدن ممکنه چیزی واسش پاس داده نشه در نتیجه حتمن باید براش مقدار Default تعیین بشه.

میبینید که الان اولی خطا داره و دومی اوکیه.و‌:


خب مثل اینکه توی این جلسه همه چیز داشت خوب پیش میرفت ولی...

میرزا قلمدون :‌ آقا توی فلاتر یه چیزی بود (@required) که وقتی میزاشتی قبل یه Named arg, باعث میشد که اجباری بشه.

میرزا قلی :‌خب ؟

میرزا قلمدون :‌ Dart همیچین چیزی نداره؟ آخه من میخوام هم Named arg داشته باشم و هم اینکه non-nullable باشه هم اینکه مقدار Default بهش ندم ولی اجباریش کنم. مثل Required positional arguments اجباری باشه ولی اسم دار هم باشه.

قل مراد : نه دیگه چنین چیزی نداریم. همیناس که گفتم.

ناز قل :‌ خاک تو سر دارت و گوگل هر دو باهم.

میرزا قلی :‌ دیگه همینه که هست نمیخوای کار نکن.

ناز قل: واااااااا.

خب این جلسه مث اینکه به خوبی و خوشی تموم شد ولی سوالی که میرزا قلمدون مطرح کرد میتونست یه سوال چالشی و مهم باشه.

به سوال میرزا قلمدون خوب فک کنید... خوب خوب... عمیق....

میرزا قلمدون میخواست یه آرگومانی داشته باشه که این سه تا شرط رو هم زمان داشته باشه:

  • Named arg
  • Non-nullable (Type)
  • Required

ولی طبق چیزایی که میرزا قلی گفت انگار چنین چیزی توی Dart وجود نداره.

یا Dart یه چیزی کم داره و یا اینکه میرزا قلی یه چیزی رو از قلم انداخت.به نظر شما کدومش؟

بریم ادامه داستان رو بخونیم ببینیم چه اتفاقی میوفته....

ادامه داستان توی گروه تلگرامی <<فلاتر و بچه های قل آباد>> اتفاق میوفته. جایی که بچها سوالاشون رو میپرسیدن و میرزا قلی یا بقیه جواب میدادن....

بریم چنتا از این سوال و جواب ها رو با هم ببینیم...

سوال اول :

ناز قل : بچها من یه کلاس دارم که اینطوریه:

حالا بهم خطا داده نمیدونم چرا.

میرزا قلی : چون اون فیلدی که تعریف کردی(name) از نوع non-nullable هست و باید اینجوری بهش مقدار بدی :‌

ناز قل : آخه چرا؟؟؟ من میخوام تو بدنه constructor بهش مقدار بدم.

میرزا قلی : نمیشه... همین جوری که گفتم بده.

ناز قل :‌ یعنی چی آخه ؟ این چه وضعشه ؟ من دیگه از فردا فلاتر کار نمیکنم.


مث اینکه قضیه داره خیلی خطرناک میشه...ناز قل که فلاتر رو گذاشت کنار.حالا فلاتر بدون نازقل چکار کنه ???

سوال دوم :‌

قل مراد :‌ دوستان این چرا خطا داره؟

خب مث اینکه هیچکسی به این سوال جواب نداد و قل مراد سوالش رو توی 20 تا گروه دیگه هم فوروارد کرد در حالیکه اعضای همه گروه ها مثل همن و در واقع انگار یه گروه رو 20 تا کپی ازش بگیری.ولی هر چه قدر منتظر موند جوابی به سوالش داده نشد.

سوال سوم :

اکبرقلی : دوستان من یه variable از جنس nullable تعریف کردم و حالا میخوام روش یه متد صدا بزنم ولی بهم ارور میده چکار کنم؟

میرزا قلی : اگه تو کلاس های من شرکت کرده بودی به مشکل نمیخوردی...

نازقل : مثلن ما که شرکت کردیم الان بلدیم؟؟

خب با این مشکلات به وجود اومده برنامه نویس ها ساکت نموندن و اعتراض ها هر روز و هر روز بیشتر شد و برنامه نویس ها دست به یه شورش علیه گوگل و Dart زدن .

گوگل گوگل حیا کن این دارتو رها کن...

ما فلاتر رو با کاتلین میخوایم...

سرانجام این اعتراضات Dart توسط پلیس USA بازداشت شد و یه دادگاه برای رسیدگی به شکایات برنامه نویس ها تشکیل شد. میرزا قلی هم به عنوان نماینده برنامه نویس ها خودشو از قل آباد به نیویورک رسوند که در این دادگاه شرکت کنه.

توی قسمت بعدی با هم داستان دادگاه Dart رو میخونیم و میبینیم که آیا Dart میتونه از خودش دفاع کنه و یا اینکه برنامه نویس ها درست میگفتن.???

شما چی فکر میکنین؟؟؟