<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های Mohammad Taheri</title>
        <link>https://virgool.io/feed/@mohammadtaherri</link>
        <description>.</description>
        <language>fa</language>
        <pubDate>2026-06-17 02:55:28</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/1024284/avatar/o1W3iF.jpeg?height=120&amp;width=120</url>
            <title>Mohammad Taheri</title>
            <link>https://virgool.io/@mohammadtaherri</link>
        </image>

                    <item>
                <title>داستان Null در دارت(دادگاه رسیدگی به اتهامات دارت-2)</title>
                <link>https://virgool.io/flutter-challenge/dart-null-story-court-2-fybaowhhzpf1</link>
                <description>خب همون طور که توی قسمت قبلی دیدیم Dart از جلسه اول دادگاه سربلند بیرون اومد و تونست به خوبی از خودش دفاع کنه و چیزای زیادی در مورد Scope ها مختلفی که variable ها میتونن داخلش تعریف و استفاده بشن و همچنین نحوه ی تعامل با nullable variable ها و non-nullable variable ها و final variable ها در Scope های مختلف و کاربرد دقیق کلمه کلیدی late بهمون یاد داد.اگه داستان قبلی رو نخوندی حتمن از این لینک بخونش و بعد بیا سراغ داستان جلسه دوم دادگاه.برای اطلاع از کل قسمت های مجموعه داستان Null در دارت هم این لینک رو ببین.بریم سراغ جلسه دوم دادگاه...توی این جلسه Dart باید به دومین اتهام خودش پاسخ میداد و اون هم اتهامی بود که در مورد انواع مختلف ارگومان های ورودی یه function یا constructor بهش زده بودن.اگه داستان این قسمت رو بخونی که میرزا قلی کلاس آنلاین برگزار کرد و انواع مختلف آرگومان های ورودی رو معرفی کرد میبینی که میرزا قلی سه نوع مختلف برای اون ها ذکر کرد ولی انگار یه جای کار میلنگید. و مثل همیشه انگشت اشاره به سمت Dart بدبخت نشونه رفت و برنامه نویس ها هیچ عیب و نقصی نداشتن.خب دیگه وقتشه که دفاعیات Dart رو بشنویم.شما رو با قاضی دادگاه و جناب Dart تنها میگذارم و آخر داستان برای خدافظی برمیگردم.???قاضی دادگاه : لطفن جناب Dart به جایگاه تشریف بیارن و پاسخگوی دومین بند از اتهامات وارده باشن.جناب Dart : بنده کمی کسالت دارم و سرما خورده ام اگه امکانش هست در این جلسه وکیلم صحبت میکنن.قاضی دادگاه : مشکلی نیست, از وکیل جناب Dart درخواست میشود به جایگاه تشریف بیارن.وکیل :‌ با سلام خدمت همه. بدون مقدمه بحث اصلی رو شروع میکنم.قبل از null safety آرگومان های ورودی یک function یا constructor میتونستن سه حالت مختلف داشته باشن : Required positional argumentsOptional positional argumentsOptional non-Positional arguments (or named arguments)ولی بنظر میرسید که این حالت ها یک جای خالی دارن. تصویر بالا رو نگاه کنید.نوع  Positional args دو حالت اختیاری(Optional) یا اجباری (Required) رو شامل میشن.ولی نوع Named args فقط حالت اختیاری(Optional) رو پشتیبانی میکنن.بنابراین موکل بنده یک کلمه کلیدی جدید رو به خودش اضافه کرد که این کلمه required نام داره و برای پر کردن این جای خالی هست.بنابراین در حال حاضر انواع محتلف آرگومان های ورودی یه function به چهار حالت تقسیم میشن.Required positional argumentsOptional positional argumentsOptional named argumentsRequired named argumentsیا به عبارت دیگه :‌نوع Positional : این نوع با Position اشون شناخته میشن و رعایت تناظر بین Position تعریف و مقداردهیشون مهمه.یعنی با همون ترتیبی که موقع تعریف function تعریف شدن موقع call کردن function هم باید بهشون مقدار بدیم.این نوع به دو دسته ی Required و Optional تقسیم میشن که برای تعریف نوع Optional باید اون ها رو داخل [ ] قرار بدیم .اما نکاتی که برای این نوع از آرگومان ها باید بدونیم :‌ نوع Required رو همیشه باید ابتدای لیست آرگومان های function بگذاریم و آخر لیست Optional ها رو قرار بدیم (داخل [ ]). پس اول همه Required ها و بعد Optional ها .موقع call کردن function باید به همون ترتیبی که آرگومان ها رو تعریف کردیم بهشون مقدار بدیم و میتونیم برای Optional ها که داخل [ ] هیچ مقداری ارسال نکنیم.هر سه حالت بالا برای call کردن این function صحیح هست.برای آرگومان اول و دوم چون که Required هستن حتمن باید مقدار ارسال بشه ولی برای سومی و چهارمی چون که Optional هستن میتونیم مقداری ارسال نکنیم.نوع Required هم میتونن به صورت nullable باشن و هم non-nullable و اگه از نوع nullable باشن موقع call کردن function میتونیم مقدار null رو هم بهشون بدیم.توی کد بالا اولی nullable و دومی non-nullable هست.نوع Optional چون که احتمال داره براشون مقداری ارسال نشه یا باید nullable باشن که در صورت ارسال نشدن مقدار, null رو بگیرن و یا اینکه باید یه مقدار Default براشون تنظیم بشه که در صورت ارسال نشدن مقدار, اون مقدار Default رو بگیرن.توی کد بالا اولی non-nullable هست ولی مقدار پیش فرض داره و درصورتی که هیچی براش ارسال نشه مقدار پیش فرض رو میگیره ولی دومی nullable هست و در صورت ارسال نشدن هیچ مقداری , null رو میگیره.ولی حالت زیر غلطه: پس Optional ها یا باید nullable باشن یا مقدار Default داشته باشن یا هر دو باهم.نوع Named : این نوع از آرگومان ها با اسمشون شناخته میشن و موقع call کردن function باید با اسمشون بهشون مقدار بدیم و ترتیب اون ها مهم نیست.و اما نکات این نوع :این آرگومان ها رو داخل { } قرار میدیم.موقع call کردن function باید با اسمشون بهشون مقدار بدیم و ترتیب مهم نیست.اگه همزمان توی function نوع Positional هم داشتیم حتمن باید اول اون ها رو بیاریم و بعد از همه Positional ها این ها رو قرار بدیم.به صورت زیر غلطه :‌همزمان نمیتونیم توی یه function نوع Named و نوع Optional positional رو با هم داشته باشیم.این نوع خودشون به دو دسته Optional و Required تقسیم میشن.حالت معمولی اون ها حالت Optional هست و در این حالت موقع call کردن function میتونیم هیچ مقداری واسشون ارسال نکنیم.چون در این حالت احتمال داره که هیچ مقداری براشون ارسال نشه پس یا باید nullable باشن که در صورت ارسال نشدن هیچ مقداری, null رو بگیرن و یا باید براشون مقدار پیش فرض تعریف کنیم.کد بالا دو تا  Named arg رو نشون میده که هر دو اختیاری هستن و اولی nullable هست و در صورتی که هیچ مقداری براش ارسال نشده null رو میگیره و دومی non-nullable هست ولی مقدار Default داره و درصورتی که هیچ مقداری براش ارسال نشه مقدار Default رو میگیره.مثال زیر هم حالات مختلف call کردن این function رو نشون میده که همگی درست هستن.ولی حالت زیر غلطه :‌یعنی وقتی که آرگومان non-nullable هست نمیتونه همزمان Optional هم باشه و براش هیچ مقدار پیش فرضی تعریف نشده باشه.چون که ممکنه موقع call شدن هرچ مقداری براش ارسال نشه.پس Named arg هایی که از نوع Optional هستن یا باید nullable باشن  و یا واسشون مقدار Default تعریف بشه.حالت دیگه Named arg ها حالت Required یا اجباری هست که در این حالت موقع call کردن function باید حتمن حتمن براشون مقدار تعیین کنیم.برای این مورد قبل از اسم و نوع آرگومان از کلمه کلیدی required که به تازگی به موکلم اضافه شده استفاده میکنیم.در این حالت همون طور که میبینید آرگومان هم میتونه از نوع nullable باشه و هم از نوع non-nullable.توی این حالت موقع call کردن function حتمن حتمن باید برای آرگومان مقدار تعیین کنیم.حتا اگه آرگومان nullable هم باشه چون که required شده باید براش مقدار تعیین بشه.توی کد بالا برای اولی که nullable هست مقدار ندادیم ولی خطا داریم.پس تنها حالت صحیح call کردن این function این هست که برای هر دو مقدار تعیین کنیم.ولی چون اولی nullable هست میتونیم مقدار null رو هم بهش پاس بدیم.همچنین توی این حالت نمیتونیم برای ارگومان مورد نظر مقدار پیش فرض تعریف کنیم.وکیل : عرایض بنده تمام شد اگر سوالی دارید در خدمتم.قاضی دادگاه :‌ متشکرم.برای مشورت و صدور رای نهایی 45 دقیقه تنفس اعلام میکنیم.45 دقیقه بعد ...قاضی دادگاه :‌ طبق اتهامات مطرح شده علیه Dart و دفاعیات ایشان و وکیل محترم در دو جلسه دادگاه نتیجه این دادگاه به این شرح اعلام میگردد:همه اتهامات نام برده از جناب Dart رد شده و به این صورت ایشان از حصر آزاد میشوند و همچنین به دلیل اتهامات بی موردی که میرزا قلی نسبت به جناب Dart روا داشتن و باعث شورش برنامه نویس ها و آشوب و نا امنی و خسارت به اموال عمومی شد, میرزا قلی به مدت 10 سال به جزیره گامبولوها تبعید میشوند و باید در این مدت Dart را به طور کامل و از زیر صفر تا بالای 100 به مردم این جزیره تدریس نماید.من برگشتم???خب Dart که بی گناهیش اثبات شد. میرزا قلی هم به جزیره گامبولوها تبعید شد.وای به حال میرزا قلی و وای به حال تره گامبولوها.???قسمت های بعدی رو از دست ندین که قراره کلی چیز جذاب تر یاد بگیرم.فعلن...</description>
                <category>Mohammad Taheri</category>
                <author>Mohammad Taheri</author>
                <pubDate>Wed, 22 Dec 2021 21:33:46 +0330</pubDate>
            </item>
                    <item>
                <title>داستان Null در دارت(دادگاه رسیدگی به اتهامات دارت-1)</title>
                <link>https://virgool.io/flutter-challenge/dart-null-story-court-1-dltvimbcuosn</link>
                <description>توی قسمت قبلی دیدیم که برنامه نویس ها یه شورش علیه Dart به راه انداختن و سرانجام جناب Dart دستگیر شد و قرار شد که یه دادگاه برای رسیدگی به اتهاماتش تشکیل بشه.از اون جایی که اتهامات خیلی زیاد بود چند جلسه دادگاه برای رسیدگی به این اتهامات لازم بود و توی این قسمت داستان جلسه اول دادگاه رو با هم میخونیم.قاضی دادگاه :‌ از جناب Dart تقاضا میشود که به جایگاه تشریف بیاورن و پاسخگوی اتهامات مطرح شده باشند...اما اولین اتهام چی بود؟داستان قسمت قبلی یادته؟ که میرزا قلی کلاس آنلاین برگزار کرد و توی جلسه اول یه اتفاقاتی افتاد...نتیجه ای که میرزا قلی گرفته بود و به بچها گفت این بود:اگه یک variable رو از نوع nullable تعریف کنیم(یعنی با ?), میتونیم همون اول کار بهش مقدار ندیم و مقدار اون به صورت پیش فرض برابر با null میشه.و اگه یه variable رو از نوع معمولی یا non-nullable تعریف کنیم (یعنی بدون ?), چون که دیگه نمیتونه به هیچ وجه مقدار null رو بگیره باید همون اول اول که تعریفش کردیم بهش یه مقدار هم بدیم.ولی قل مراد گفتش که من یه کد اینجوری زدم :‌و این کد داره دومین نتیجه ای که تو گرفتی رو نقض میکنه.آخرش به این نتیجه رسیدن که حتمن Dart مشکل داره و باگ داره...حالا Dart باید به این اتهام پاسخ میداد؟از اینجا به بعد داستان رو از زبان Dart بشنویم. قبلش بگم که آقای Dart کتابی صحبت میکنه و دیگه این موضوع دست من نیست...در ابتدا به عنوان مقدمه باید عرض کنم که در من (منظورش از من همون Dart هست) هر موقع از { } استفاده می کنید یک Scope جدید ایجاد می شود. برای مثال وقتی که یک class جدید مینویسید :‌ با قرار دادن { } یک Scope جدید ایجاد می شود.یا مثلن وقتی که یک function جدید تعریف میکنید :‌ همین طور وقتی که یک شرط if مینویسید یا یک حلقه for ایجاد میکنید :‌همه این ها به دلیل استفاده از { } یک Scope جدید ایجاد میکنن.میرزا قلمدون که همراه میرزا قلی از قل آباد به نیویورک رفته بود که در دادگاه شرکت کنه یهو بلند شد و گفت :‌ حالا اینایی که گفتین چه ربطی به موضوع داره؟قاضی دادگاه :‌ تق تق تق ... نظم جلسه را رعایت کنید. جناب Dart ادامه دهید.جناب Dart : حال در هر Scope به variable های تعریف شده در Scope های بالاتر از خودش (یا به عبارتی به Scope های پدر) دسترسی داریم ولی به Variable های تعریف شده در Scope های فرزند دسترسی نداریم.همین طور باید اضافه کنم میتوانیم variable ها را براساس Scope ای که در آن تعریف می شوند به سه دسته کلی تقسیم کنیم:Global variablesدسته اول variable هایی  هستن که خارج از هر Scope یعنی خارج از هر class یا function یا ... تعریف می شوند و در واقع در بدنه اصلی برنامه تعریف می شوند.Class Instance fieldsدسته دوم instance field های مربوط به class ها هستن.میرزا قلمدون باز پرید وسط  و گفت :‌ instance field چیه ؟‌ قاضی دادگاه :‌ تق تق تق ... نظم جلسه را حفظ کنید...میرزا قلمدون رو بخاطر به هم ریختن نظم جلسه از اتاق بیرون کردن...Local variablesدسته سوم variable هایی هستند که داخل بدنه یک function یا داخل Scope های مربوط به if یا ... تعریف می شوند و به آن ها Local می گوییم.برای مثال :‌ در کد بالا  نوع Global و Local  را مشاهده میکنید.نوع Global در بدنه اصلی برنامه و نوع Local داخل function(function Scope) تعریف شده اند.نوع اول یعنی Global ها داخل function قابل دسترسی و استفاده هستن ولی نوع دوم یعنی Local ها فقط و فقط داخل همون scope ای که تعریف شده اند قابل دسترسی هستن و خارج از آن قابل دسترسی نیستن.دلیل این امر هم این هست که function Scope در واقع فرزند Global Scope محسوب میشود و میتواند به variable های آن دسترسی داشته باشد ولی Global Scope نمی تواند به variable های فرزند خودش یعنی function Scope دسترسی داشته باشد.مثالی دیگر :‌خروجی کد بالا به صورت زیر هست :میبینید که در کد بالا یک تابع با نام myFunction تعریف کرده ام که برای خودش یک scope ایجاد میکند و داخل این scope به همه variable هایی که در scope خودش و همچنین scope بالاتر (global) تعریف شده اند دسترسی داریم.همچنین داخل تابع myFunction یک تابع دیگر با نام myInnerFunction تعریف کرده ام که این تابع هم برای خودش یک scope ایجاد میکند({ }) و داخل این scope به همه variable های scope بالاتر (یعنی global و myFunction scope) دسترسی داریم.ولی داخل globla scope نمیتوانیم به varibale هایی که داخل این دو function تعریف شده اند دسترسی داشته باشیم.همچنین از داخل myFunction نمیتوانیم به variable هایی که داخل myInnerFunction تعریف شده اند دسترسی داشته باشیم.و یک مثال دیگر :داخل Instance method های  یک کلاس به همه local variable ها (که داخل همان method یا همان scope تعریف شده اند ) و همه instance filed های کلاس به علاوه همه global variable ها ( که خارج از کلاس تعریف شده اند) دسترسی داریم.و به عنوان مثال آخر :‌در کد بالا یک function داریم و داخل آن از یک if استفاده کرده ایم که استفاده از if باعث ایجاد یک Scope جدید می شود ( { } ) و داخل Scope مربوط به myFunction به variable هایی که در if Scope تعریف شده اند دسترسی نداریم ولی داخل Scope مربوط به if به همه ی variable های تعریف شده در Scope های بالاتر  دسترسی داریم. در واقع در اینجا if Scope فرزند function Scope محسوب میشود و به variable های آن دسترسی دارد ولی function Scope به variable های فرزند خودش دسترسی ندارد.پس :‌هر { } یک Scope جدید ایجاد می کند. و بدنه اصلی برنامه که شامل هیچ { } نیست را می توانیم Global Scope بنامیم.هر Scope به variable های تعریف شده در Scope های اجداد خود دسترسی دارد ولی به variable های تعریف شده در Scope های نوادگان خود دسترسی ندارد.براساس Scope های مختلف می تواینم variable ها را به سه دسته کلی Global و Local و Class instance field تقسیم کنیم.بعد از این مقدمه باید عرض کنم که :‌وقتی که یک non-nullable variable را به صورت Local تعریف میکنید نیازی نیست که همان ابتدا آن را مقدار دهی کنید. چون که آنالایزر من (منظورش آنالایزر دارت هست چون خودش دارته) هوشمند هست و میتواند کل بدنه مربوط به آن Scope(مثلن کل بدنه function) را بررسی کند.در این حالت اگر از variable تعریف شده در هیچ کجا استفاده نکنید کار بدون مشکل پیش می رود ولی به محض این که برای اولین بار می خواهید از آن استفاده کنید آنالایزر من کل بدنه مربوط به ان Scope را بررسی و تحلیل می کند و اگر ببینید که شما آن variable را قبل از استفاده مقدار دهی نکرده اید به شما خطا می دهد.برای مثال :‌در کد بالا یک variable از نوع non-nullable تعریف کرده ایم و آن را مقدار دهی نکرده ایم ولی چون که از آن استفاده نکرده ایم هیچ مشکلی رخ نمی دهد.حالا کد زیر را ببینید :‌نوع بازگشتی function رو String کردم و بدون مقداردهی variable آن را return کردم. و یک خطا گرفتم :همان طور که میبینید این خطا می گوید که  که یک non-nullable variable باید قبل از استفاده حتمن مقدار دهی بشود.به عنوان مثالی دیگر : میبینید که یک non nullable String با نام StringStatus تعریف کرده ام در موقع return خطا گرفته ام.چون آنالایزر  مطمین نیست که در هر شرایطی این variable قبل از استفاده (یعنی قبل از return )مقدار میگیرد.که با افزودن یک else به آنالایزر  اطمینان میدهم که در هرصورت این variable قبل از استفاده مقدار دهی میشود و خطا برطرف میشود.ولی این نکته فقط و فقط برای Local variables صادق است و برای Global variables و Class instance fields نمی توانیم از این نکته استفاده کنیم.چرا که آنالایزر  من نمی تواند کل برنامه یا کل یک کلاس را بررسی و تحلیل کند و تشخیص دهد که آیا یک variable که در این Scope ها تعریف شده است قبل از استفاده مقدار دهی شده است یا خیر پس variable هایی از این دو نوع که از نوع non-nullable هستند باید همان ابتدا مقدار دهی شوند.برای مثال :‌در کد بالا یک Global variable داریم که از نوع non-nullable است و باید در همان لحظه تعریف مقداردهی شود, در غیر این صورت با خطا مواجه خواهید شد.این قضیه برای Field های یک کلاس هم صادق هست :‌پس  :اگر یک variable از جنس nullable باشد میتواند موقع تعریف مقدارهی نشود و مقدار آن برابر با null خواهد شد.اگر یک varibale از جنس non-nullable باشد و به صورت Local تعریف شود, می تواند موقع تعریف مقدار نگیرد و خود آنالایزر  هشدارهای لازم برای مقدار دهی را در صورت لزوم میدهد.(موقع اولین استفاده آنالایزر  چک می کند که ایا آن variable مقدار دهی شده است یا نه)اگر یک variable از جنس non-nullable باشد و داخل global scope تعریف شده باشد و یا داخل class scope (class field) باید همان موقع تعریف مقدار دهی شود.ولی اگر یک non-nullable variable از نوع class instance field باشد در شرایط خاصی میتوانیم آن را همان موقع تعریف مقدار دهی نکنیم.معمولن class instance field ها را می خواهیم در constructor مقدار دهی کنیم ولی آنالایزر باید این امکان را داشته باشد که بفهمد که آیا non-nullable variable تعریف شده, مقدار دهی شد یا خیر؟در واقع وقتی که یک Local variable تعریف میکینم چون که آنالایزر باید یک سطح کوچک از کد (مثلن بدنه یک function) را بررسی کند و اطمینان حاصل کند که non-nullable variable تعریف شده قبل از اولین استفاده مقدار دهی شده است یا خیر. بررسی و آنالیز این سطح کوچک برای آنالایزر کار دشواری نیست و به همین دلیل به ما اجازه می دهد که در همان ابتدای تعریف non-nullable variable آن را مقدار دهی نکنیم.ولی در مورد Global variable ها یا class instance field ها چون که آنالایزر باید یک سطح بزرگ از کد را بررسی کند, این عمل راحت نیست و به همین دلیل وقتی non-nullable variable هایی داخل این Scope ها تعریف میکنید شما را اجبار میکند که در همان ابتدا آن رو مقدار دهی کنید.ولی در مورد class instance field ها میتوانیم دو حالت استثنا را در نظر بگیریم و در آن موارد اجازه داریم که non-nullable variable را همان اول مقدار دهی نکنیم.قبل از گفتن این دو مورد استثنا باید بگوییم که سه روش برای initialize کردن یک instance field داخل constructor وجود دارد.روش اول: استفاده از this در آرگومان ها ورودی سازنده.?این قسمت توسط آنالایزر قابل رصد شدن هست و آنالایزر میتواند آرگومان های ورودی سازنده های کلاس ها را چک کند.روش دوم : استفاده از لیست مقدار دهی(initialize list).?این قسمت هم توسط آنالایزر قابل رصد هست.روش سوم : استفاده از constructor body.?این قسمت یعنی constructor body توسط آنالایزر قابل رصد نیست.پس با توجه به موارد بالا میتوان گفت که میتوانیم یک instance field از نوع non-nullable تعریف کنیم و آن را همان ابتدا مقداردهی نکنیم به شرط اینکه از روش های اول یا دوم برای مقدار دهی آن استفاده کنیم.روش اول :‌ روش دوم :‌ولی در صورت استفاده از روش سوم آنالایزر خطا میدهد:ولی در صورتی که خواستید :  یک non-nullable variable را داخل Global Scope تعریف کنید و آن را همان ابتدای تعریف مقدار دهی نکنید.یا یک non-nullable class instance field تعریف کنید و آن را همان ابتدا یا با استفاده از یکی از دو روش بالا مقداردهی نکنید.می توانید از کلمه کلیدی late استفاده کنید.مثال :‌یک non-nullable variable در Global Scope که همان ابتدا مقدار دهی نشده است و آنالایزر هم هیچ خطایی اعلام نکرده است.یک non-nullable instance field داخل یک class که همان ابتدا مقدار دهی نشده است و آنالایزر هم هیچ خطایی اعلام نکرده است.و اما کلمه کلیدی late چه کار میکند؟تا این جا دیدیم که بعد از اضافه شدن قابلیت null safety به Dart یک سری از خطاهایی که قبلن در زمان اجرای کد(runtime) دریافت میکردیم به زمان compile منتقل شدند و همان موقعی که در حال کدنویسی هستیم آنالایزر به ما هشدار میدهد.ولی کلمه کلیدی late به compiler میگوید که دیگر با این variable در زمان compile کد کاری نداشته باش و در واقع برنامه نویس به compiler اعلام میکند که من خودم مدیریت این variable و مقداردهی آن را به عهده میگیرم و لازم نیست که تو در این مورد دخالت کنی.پس با استفاده کردن از late دیگر compiler کاری به مقداردهی یا عدم مقداردهی این non-nullable variable ندارد و مدیریت آن را به عهده برنامه نویس میگذارد.حال با این تفاصیر دو اتفاق میوفتد : دیگر آنالایزر در مورد این variable و عدم مقدار دهی آن به ما اعلام خطا نمیکند.چون مدیریت مقداردهی این variable به عهده برنامه نویس هست اگر برنامه نویس آن را مقدار دهی نکند و از آن در جایی استفاده کند, موقع اجرای کد (runtime) خطا رخ میدهد.مثال :‌میبینید که یک non-nullable global variable با استفاده از late تعریف کردم و بدون مقدار دهی از آن استفاده کردم ولی آنالایزر هیچ خطایی مبنی بر اینکه این variable را مقداردهی نکرده ای اعلام نکرد (به دلیل استفاده از late).پس در زمان نوشتن کد و compile هیچ خطایی نداریم.ولی اگر کد را اجرا کنیم :‌همان طور که میبینید یک خطای زمان اجرا یا runtime error دریافت میکنیم.مثال :‌در یک class یک non-nullable field را با late تعریف کردم و بدون مقدار از آن استفاده کردم ولی به دلیل استفاده از late هیچ خطایی در زمان compile نداریم.ولی با اجرای کد : ولی اگر همین variable را در بدنه constructor مقدار دهی کنم مشکل برطرف میشود :‌نکته خیلی مهم :‌نیازی نیست برای Local variable از late استفاده کنید.همچنین نیازی نیست برای nullable variable ها از late استفاده کنید چون در صورت عدم مقداردهی, مقدار پیش فرض یعنی null را میگیرند.استفاده از late فقط برای non-nullable global variable که میخواهید همان ابتدای تعریف آن را مقدار دهی نکنید یا non-nullable class field که می خواهید ان را همان ابتدای تعریف یا با یکی از دو روش گفته شده برای مقدار دهی در constructor مقداردهی نکنید, مناسب است.این نکته را هم باید اضافه کنم که نکاتی که در مورد class instance field ها گفتیم در مورد static field های یک class هم صادق است برای تعریف یک non-nullable static field داخل یک class میتوان از late استفاده کرده و مقدار دهی را به بعدن موکول کرد.و اما نکته پایانی در مورد final variable ها است.تا قبل از null safety اگر یک final variable تعریف میکردیم باید آن را همان ابتدا مقدار دهی میکردیم یا در مورد class instance field باید آن را به یکی از دو روش گفته شده که توسط آنالایزر قابل تحلیل است مقداردهی میکردیم.مثال :‌در مثال بالا یک global variable داریم که از نوع nullable است پس تا اینجا نیازی نیست که آن را همان ابتدا مقدار دهی کنیم چون که میتواند مقدار پیش فرض null را بگیرد. همچنین نیازی به استفاده از کلمه late نیست.اما به دلیل اینکه این variable از نوع final است باید همان ابتدای تعریف مقدار دهی شود و به همین دلیل آنالایزر خطا میدهد.ولی میتوان با استفاده از late این مشکل را حل کرد :پس از کلمه کلیدی late  را علاوه بر کاربرد های قبلی میتوان : برای final variable هایی که در Global Scope تعریف می شوند و نمیخواهیم آن ها را همان ابتدا مقدار دهی کنیم استفاده کرد.برای class instance field هایی که به صورت final تعریف میشوند و نمیخواهیم آن ها را همان ابتدا یا با استفاده از دو روش مقدار دهی در constructor که توسط آنالایزر قابل تحلیل است مقدار دهی کنیم.استفاده کرد.عرایض بنده تمام شد و از دادگاه محترم و حاضرین در جلسه تقاضا دارم در صورتی که سوال یا ابهامی دارند مطرج کنند.با توجه به توضیحات کامل Dart کسی از حاضرین سوالی نبپرسی و همه قانع شدن و دادگاه هم اولین اتهام رو از Dart رد کرد.خب جلسه اول دادگاه به این صورت به پایان رسید و مثل اینکه Dart خیلی خوب تونست اتهامات وارد شده را از خودش رد کنه. ولی هنوز جلسات دیگه ای برای بررسی سایر اتهامات باقی مونده که داستان اون ها رو توی قسمت های بعدی با هم میخونیم.ولی حالا من خلاصه مواردی که Dart گفت رو یه بار دیگه براتون میگم :‌خلاصه Scope : با استفاده از هر { } یک Scope جدید ایجاد میشه مثل تعریف یه class یا یه function یا یه if و ... .اون variable هایی که داخل بدنه اصلی برنامه هستن رو بهشون میگیم Global .اون هایی که داخل function یا if و ... تعریف میشن رو میگیم Local.اون هایی که داخل class ها هستن رو میگیم class fields.هر Scope فقط و فقط به variable هایی که داخل خودش و Scope های اجدادش تعریف شدن دسترسی داره و به variable های Scope های نوادگانش دسترسی نداره.خلاصه nullable variables: این ها چون که میتونن مقدار null رو بگیرن.توی هر Scope ای که تعریف بشن میتونن همون اول مقدار دهی نشن و در این صورت مقدار پیش فرض null رو میگیرن.این مورد یک استثنا داره و اون هم این که این variable خودش final باشه که توی بخش final میگم.خلاصه non-nullable variables:این ها نمیتونن مقدار null رو بگیرن.حالا اگه به صورت Local تعریف شدن میتونی همون اول مقدارشون ندی و خود کامپایلر یا آنالایزر در صورت لزروم بهت هشدار میده(توی اولین استفاده بررسی میکنه که آیا مقدار دارن یا نه و اگه نداشتن بهت خطا میده (compile time error))اگه به صورت Global تعریف کردی مجبوری همون اول مقدارشون بدی.اگه یه class field بودن باید یا همون اول مقدارشون بدی یا با استفاده از دو روش مقدار دهی توی constructor که compiler میتونه رویتش کنه.یعنی با استفاده از this یا initialize list.خلاصه final variables : این ها چه nullable باشن و چه non-nullable اگه :‌ به صورت Local تعریف شدن میتونی همون اول مقدارشون ندی و خود کامپایلر یا آنالایزر در صورت لزروم بهت هشدار میده(توی اولین استفاده بررسی میکنه که ایا مقدار دارن یا نه و اگه نداشتن بهت خطا میده (compile time error))اگه به صورت Global تعریف کردی مجبوری همون اول مقدارشون بدی.اگه یه class field بودن باید یا همون اول مقدارشون بدی یا با استفاده از دو روش مقدار دهی توی constructor که compiler میتونه رویتش کنه.یعنی با استفاده از this یا initialize list.خلاصه late : از این کلمه کلیدی فقط برای Global variable ها یا class field ها استفاده کن.برای Local variable ها نیازی نیست که ازش استفاده کنی.شرط استفاده ازش هم اینه که : یه Global variable ای داشته باشی که مجبور باشی همون ابتدای تعریف مقدارش بدی یعنی یا non-nullable باشه و یا اینکه final باشه.یه class field داشته باشی که مجبور باشی همون اول یا با استفاده از دو روش مقدار دهی در constructor مقدارش بدی یعنی یا non-nullable باشه یا final.و به هر دلیلی نخوای که توی این شرایط بهش مقدار بدی.در این صورت از late استفاده کن و با این کار به compiler میگی که برو وایسا کنار و دخالت نکن و compiler هم گوش میکنه و میگه من میرم کنار و کاری به کارت ندارم ولی مسیولیتش با خودت و اگه اینو مقدار ندادی و ازش استفاده کردی موقع اجرای برنامه خطا میگیری و آبروت جلوی کاربر میره.پس اگه از late استفاده کردی مراقب باش که آبرو ریزی نشه.درواقع با استفاده از late قابلیت compile time error رو از دست میدیم و موقع کدنویسی هیچ error ای دریافت نمیکنیم و در صورت بی دقتی موقع اجرا خطا میگیریم(runtime)حالا در پایان این قسمت یه چالش مطرح میکنم و ازت میخوام که با دلیل و منطق و تحلیل درست و حسابی اون رو حلش کنی و جوابش رو بدی...کد بالا چرا خطا داره و چکار کنیم که درست شه؟امیدوارم که لذت برده باشی و کلی نکته جدید یاد گرفته باشی.لایک یادت نره.... تا قسمت بعدی و ادامه ماجرای های null در Dart خدافظ.</description>
                <category>Mohammad Taheri</category>
                <author>Mohammad Taheri</author>
                <pubDate>Thu, 09 Dec 2021 18:11:45 +0330</pubDate>
            </item>
                    <item>
                <title>داستان Null در دارت(میرزا قلی کلاس آنلاین برگزار میکند)</title>
                <link>https://virgool.io/flutter-challenge/dart-null-story-mirza-gholii-online-class-yeq5mkdlvyiw</link>
                <description>خب بعد از اینکه Dart برای سر و سامون دادن به وضعیت خودش و خلاص شدن از دست برنامه نویس ها و مشکلات زیادی که Null درست کرده بود یه آپدیت بزرگ داد و Null رو که حالا یه بچه سر راه مونده بود رو جمع و جورش کرد, میرزا قلی(همون برنامه نویس فلاتر) تصمیم گرفت که برای بچه های دهشون یعنی قل آباد یه کلاس آموزشی آنلاین بگذاره و این چیزای جدید رو بهشون آموزش بده و کلی بین بچه های دهشون کلاس بگذاره که اره من خیلی بلدمممم.???قبل از اینکه بریم ببینیم توی کلاس های آنلاین میرزا قلی چه اتفاقایی افتاد بهتون بگم که میتونید قسمت قبلی این داستان رو از طریق این لینک دنبال کنید و همچنین برای اینکه در جریان همه قسمت های این مجموعه قرار بگیرید هم این لینک رو ببینید.دیگه نمیگم که لایک این پست هم یادتون نره و یه سری هم به کانال فلاترمون بزنید.خب بریم سر کلاس های میرزا قلی....بعد از تبلیغات فراوااان سه نفر توی کلاس ها ثبت نام کردن. قل مراد, ناز قل و میرزا قلمدون.جلسه اول شروع شد و میرزا قلی شروع کرد به تعریف کردن از کلاس های خودش که مثل این کلاس رو هیچ جا نمیتونید پیدا کنید و این اولین و تنهاترین دوره آموزشی فارسی هست که به این موضوع میپردازه و اگه توی کل قل آباد بگردید کسی رو پیدا نمیکنید که این ها رو بلد باشه و بعد از این دوره میتونید در هر شرکتی که دوست داشته باشید استخدام بشید و این حرفا ...بعدش شروع کرد به صحبت کردن در مورد Null و گفتش که Dart یه Type جدید اضافه کرده و با اضافه کردن یه ? به Type های قبلی میتونیم یه Type جدید داشته باشیم.Type =&gt; non nullable Type
Type? =&gt; nullable Type
String =&gt; non nullable
String? =&gt; 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 اشون.میرزا قلمدون :‌ من نفهمیدم چی گفتید.قل مراد : صبر کن با مثال متوجه میشی.حالا نوع اول خودشون به دو دسته تقسیم میشن:RequiredOptionalکه 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 =&gt; &#039;first required
secondRequiredPositionalArg =&gt; &#039;second required&#039;
optionalPositionalArg  =&gt; &#039;optional&#039;ترتیب اینجا خیلی مهمه و باید به همون ترتیبی که آرگومان ها تعریف شدن به همون ترتیب هم مقادیر به 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 =&gt; Non-nullable Type
Type? =&gt; 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 argNon-nullable (Type)Requiredولی طبق چیزایی که میرزا قلی گفت انگار چنین چیزی توی Dart وجود نداره.یا Dart یه چیزی کم داره و یا اینکه میرزا قلی یه چیزی رو از قلم انداخت.به نظر شما کدومش؟ بریم ادامه داستان رو بخونیم ببینیم چه اتفاقی میوفته....ادامه داستان توی گروه تلگرامی &lt;&lt;فلاتر و بچه های قل آباد&gt;&gt; اتفاق میوفته. جایی که بچها سوالاشون رو میپرسیدن و میرزا قلی یا بقیه جواب میدادن....بریم چنتا از این سوال و جواب ها رو با هم ببینیم...سوال اول :ناز قل : بچها من یه کلاس دارم که اینطوریه:حالا بهم خطا داده نمیدونم چرا.میرزا قلی : چون اون فیلدی که تعریف کردی(name) از نوع non-nullable هست و باید اینجوری بهش مقدار بدی :‌ناز قل : آخه چرا؟؟؟ من میخوام تو بدنه constructor بهش مقدار بدم.میرزا قلی : نمیشه... همین جوری که گفتم بده.ناز قل :‌ یعنی چی آخه ؟ این چه وضعشه ؟ من دیگه از فردا فلاتر کار نمیکنم.مث اینکه قضیه داره خیلی خطرناک میشه...ناز قل که فلاتر رو گذاشت کنار.حالا فلاتر بدون نازقل چکار کنه ???سوال دوم :‌قل مراد :‌ دوستان این چرا خطا داره؟خب مث اینکه هیچکسی به این سوال جواب نداد و قل مراد سوالش رو توی 20 تا گروه دیگه هم فوروارد کرد در حالیکه اعضای همه گروه ها مثل همن و در واقع انگار یه گروه رو 20 تا کپی ازش بگیری.ولی هر چه قدر منتظر موند جوابی به سوالش داده نشد.سوال سوم : اکبرقلی : دوستان من یه variable از جنس nullable تعریف کردم و حالا میخوام روش یه متد صدا بزنم ولی بهم ارور میده چکار کنم؟میرزا قلی : اگه تو کلاس های من شرکت کرده بودی به مشکل نمیخوردی...نازقل : مثلن ما که شرکت کردیم الان بلدیم؟؟خب با این مشکلات به وجود اومده برنامه نویس ها ساکت نموندن و اعتراض ها هر روز و هر روز بیشتر شد و برنامه نویس ها دست به یه شورش علیه گوگل و Dart زدن . گوگل گوگل حیا کن این دارتو رها کن...ما فلاتر رو با کاتلین میخوایم...سرانجام این اعتراضات Dart توسط پلیس USA بازداشت شد و یه دادگاه برای رسیدگی به شکایات برنامه نویس ها تشکیل شد. میرزا قلی هم به عنوان نماینده برنامه نویس ها خودشو از قل آباد به نیویورک رسوند که در این دادگاه شرکت کنه.توی قسمت بعدی با هم داستان دادگاه Dart رو میخونیم و میبینیم که آیا Dart میتونه از خودش دفاع کنه و یا اینکه برنامه نویس ها درست میگفتن.???شما چی فکر میکنین؟؟؟</description>
                <category>Mohammad Taheri</category>
                <author>Mohammad Taheri</author>
                <pubDate>Sat, 04 Dec 2021 23:34:29 +0330</pubDate>
            </item>
                    <item>
                <title>فانکشن بدون پرانتز در دارت</title>
                <link>https://virgool.io/flutter-challenge/dart-function-without-parentheses-hscdfgcxdoro</link>
                <description>سلام به فلاتری های عزیر و همراهان Flutter Challenge.اگه وقتی که داری یه function رو بدون پرانتز به جایی پاس میدی گیج و سردرگم میشی و نمیدونی که داره چه اتفاقی میوفته تا آخر این مقاله رو با دقت بخون و بعدش با اعتماد به نفس از این تکنیک استفاده کن و به بقیه هم یاد بده.توی این مقاله ی کوتاه میخوایم در مورد function ها در Dart صحبت کنیم ولی نه در مورد همه نکاتش بلکه فقط میخوایم ببینیم چرا بعضی جاها یه function رو بدون پرانتز به کار میبریم و اصلن چه اتفاقی پشت پرده میوفته وقتی که یه function رو بدون پرانتز استفاده میکنیم و یا وقتی پرانتز براش میذاریم اون پشت مشتا چه اتفاقی میوفته.خلاصه میخوایم بریم و ته و توی این قضیه رو دربیاریم. پس با این مقاله جذاب تا آخر همراه باش....قبل از پرداختن به اصل موضوع چندتا نکته بهتون بگم.توی Dart همه class ها از کلاس Object ارث بری میکنن : شاید بپرسی class چه ربطی به function داره؟ همراهم باش تا آخر مقاله که بفهمی.خب اینجوری بگم که توی Dart یه class داریم به اسم Object که پایه و اساس همه class های دیگه هست و همه class ها (به جز Null) از این class ارث بری میکنن.بریم یه مثال بزنیم که متوجه بشی...کد بالا رو ببین, یه variable از جنس int تعریف کردم و بعدش دو تا print گذاشتم و با استفاده از دستور is گفتیم که ایا این variable از جنس int و Object هست؟خروجی رو ببین:میبینی جواب هر دو شده Yes. چون که همون طور که گفتم توی Dart همه کلاس ها از جمله int از Object ارث بری میکنن.یا مثال زیر رو ببین :پس فهمیدیم که توی Dart همه class ها به جز Null از Object ارث بری میکنن.Callable class : میدونیم که هر class تشکیل شده از یک سری field و method.Instance FieldsStatic FieldsInstance methodsStatic methodsحالا یه method خاص داریم با یه اسم خاص. اگه توی یه class یه method ای بسازیم که اسمش call باشه یه اتفاقات خاصی میوفته.کلاس بالا رو ببین که یه method به اسم call داره.در مورد این method بگم که: نوع مقدار بازگشتیش مهم نیست, یعنی میتونه void باشه یا هر چیز دیگه...(هر چی دوست داشتی)آرگومان های ورودیش هم مهم نیست و میتونه هیچ آرگومانی نگیره و یا هر چی دلت خواست براش قرار بدی.فقط اسمش مهمه که حتمن call باشه.حالا چه اتفاقی میوفته ؟‌توی کد بالا خیلی ساده یه نمونه از کلاسم ساختم و بعدش هم متد call رو صدا زدم.همه چی واضحه...نه؟حالا کد زیر رو ببین:توی کد بالا یه اتفاق جالب افتاد. خیلی جالب.دو تا پرانتز گذاشتم ته myService و متد call اجرا شد!!!دیدی؟وقتی که توی یه class یه متدی داشته باشیم که اسمش call باشه میتونیم با گذاشتن پرانتز ته variable ساخته شده از اون class اون method رو اجرا کنیم. به این class ها میگن Callable class.اینم یه مثال دیگه:توی Dart حتا Function هم یک class هست : این جمله خیلی سنگین بود ولی الان تحلیلش میکنیم.توی کد بالا یه function تعریف کردم.چه اتفاقی داره میوفته؟کد زیر رو ببین‌:اینجا یه دونه String تعریف کردم. وقتی اینو تعریف میکنیم چی داره میشه ؟‌در واقع یه نمونه از کلاس String ساخته میشه و توی حافظه قرار میگیره(توی یکی از خونه های حافظه یا رم) و بعد این variable که اینجا اسمش رو گذاشتیم str رفرنس اون خونه از حافظه رو توی خودش نگه میداره درواقع str اشاره میکنه به یه خونه از حافظه که داخلش یه نمونه از کلاس String ذخیره شده.حالا کد بالا رو دوباره ببین : اینجا وقتی که یه function تعریف میکنم هم باید یه چیزی توی حافظه ذخیره بشه دیگه...نه؟ همین جوری الکی که نمیشه؟ باید یه چیزی ذخیره بشه؟ نباید بشه؟ باید بشه.ولی چی ذخیره میشه و چه جوری ؟‌توی Dart یه کلاسی داریم به اسم Function.وقتی که یه function تعریف میکنم مثل کد زیر :خود Dart میاد و اون پشت یه کارایی میکنه.یه کاری شبیه به این انجام میده. نه دقیقن مثل این ها. ولی برای اینکه متوجه بشید کد بالا رو در نظر بگیرید.جناب Dart میاد و یه class درست میکنه و میگه که Function رو  implements کن. و بعد یه method با اسم call توش میذاره و بدنه ی این method دقیقن کپی همون function هست که ما نوشتیم.حالا Dart میاد و میگه : پس ما یه Function نوشتیم :‌ولی پشت پرده یه اتفاق های دیگه افتاد :‌پشت پرده کدی که ما نوشتیم به صورت بالا تفسیر میشه.در واقع یه class نوشته میشه که از جنس Function class هست و براش یه method به اسم call قرار داده میشه و بعدش یه نمونه از اون class ساخته میشه و اون نمونه رو میریزه توی .... توی چی میریزه؟توی یه variable با اسمی که ما برای function گذاشتیم.پس وقتی که یه function به صورت زیر تعریف میکنیم :‌یه callable class از جنس Function class ساخته میشه و ازش یه نمونه ساخته میشه و اون نمونه میره توی حافظه ذخیره میشه حالا ما یه variable داریم به اسم myFunction که داره اشاره میکنه به اون خونه از حافظه.پس وقتی که داریم یه function تعریف میکنیم انگار هیچ فرقی با وقتی نداره که داریم یه variable معمولی مثل String تعریف میکنیم.پس ما الان یه variable داریم به اسم myFunction که داره رفرنس یه خونه از حافظه رو داخل خودش نگه میداره که اون خونه از حافظه داخلش یه نمونه از یه callabe class ذخیره شده.پس با توجه به مفهوم callable class ها میتونیم با گذاشتن دو تا پرانتز ته این variable یعنی myFunction باعث اجرا شدن متد call اون class بشیم که همون بدنه ی function ای هست که ما تعریف کردیم.پس همون طور که یه variable از جنس String یا یه variable از هر جنس دیگه ای رو میتونیم به جاهای مختلف پاس بدیم این جا هم myFunction که در واقع یه variable هست رو میتونیم  به جاهای  مختلف پاس بدیم و این میشه که میگن داری function رو بدون پرانتز پاس میدی و هر موقع که ته اون variable پرانتز بذاری اون call اجرا میشه.حالا مثال زیر رو هم ببین:میبینی که یه function تعریف کردم و بعدش برای اجرا کردنش به جای اینکه ته variable مورد نظر یعنی myFunction پرانتز بذارم روش call رو صدا زدم وباز هم function اجرا شد که این هم از همه حرفایی که تا الان زدیم به خوبی میشه نتیجه گرفت.و به عنوان نکته آخر همون طور که گفتیم همه class ها توی Dart از Object ارث بری میکنن از جمله Function class.پس : امیدوارم که از این مقاله لذت برده باشی.</description>
                <category>Mohammad Taheri</category>
                <author>Mohammad Taheri</author>
                <pubDate>Sun, 28 Nov 2021 21:41:34 +0330</pubDate>
            </item>
                    <item>
                <title>داستان Null در دارت(نال فرزند سر راهی)</title>
                <link>https://virgool.io/flutter-challenge/%D8%AF%D9%86%DB%8C%D8%A7%DB%8C-%D8%AF%D8%A7%D8%B1%D8%AA-%D8%A8%D8%B9%D8%AF-%D8%A7%D8%B2-null-safety%D9%86%D8%A7%D9%84-%D9%81%D8%B1%D8%B2%D9%86%D8%AF-%D8%B3%D8%B1-%D8%B1%D8%A7%D9%87%DB%8C-rvvatw9odxqi</link>
                <description>توی قسمت های قبلی دیدیم که Null که یه فرزند ناخلف برای کلاس های Dart بود دردسر های زیادی رو براشون درست میکرد. از یه طرف میگفت من فرزند همه شما ها هستم و یه نمونه از کلاس من (null) میتونه به یه variable از type شما ها اختصاص پیدا کنه و از یه طرف دیگه هیچ کدوم از متد های شما رو پشتیبانی نمیکنم و باعث یه سری از خطاهای ناجور و run time میشم.(میتونی از اینجا داستان قسمت های قبلی رو دنبال کنی)سرانجام کلاس های Dart یه جلسه بین خودشون تشکیل دادن و نتیجه این جلسه مهم که ساعت ها به طول انجامید این شد که دیگه Null رو به عنوان فرزند قبول نداشته باشن و تصمیم گرفتن خیلی بی سر و صدا اون رو بذارنش سر راه.و این شد که شکل و شمایل Dart به صورت بالا دراومد.همه کلاس ها مثل روال سابق از Object ارث بری میکردن ولی دیگه Null اون پایین نبود.حالا با این شرایط وقتی که یه variable ای با یه type ای تعریف میکردیم دیگه نمیتونستیم بهش مقدار null رو بدیم چون که دیگه کلاس Null فرزند کلاس های دیگه نبود.مثلن کد ساده زیر رو ببینید: میبینید که اومدم و به یه variable که از نوع String هست مقدار null رو دادم ولی زیرش خط قرمز کشیده و خطا داده و خطا هم به صورت زیر هست :خطا رو بخونید....گفته که نمیتونی یه مقدار از نوع Null(حرف بزرگ / کلاس Null) رو بدی به یه variable از نوع String.خب اینجا یه اتفاق خوب افتاد و دیگه امکان دادن مقدار null به variable ها نیست و اگه چنین کاری رو انجام بدیم همون موقع کد نویسی بهمون خطا میده و نمیذاره کار به موقع اجرا بکشه.ولی باز هم سر و صدای برنامه نویس ها دراومد.برنامه نویس ها میگفتن که آقااااا ما نمیخوایم که کلن یه کاری کنی که ما نتونیم از Null استفاده کنیم که.حرفمون این بود که یه کاری کنید که در عین این که یه جاهایی یه variable ای امکان گرفتن null رو داره و به قولی nullable هست ولی روند کد نویسی هوشمندتر بشه و همون موقع کد نویسی بهمون یه سری خطاها و هشدارها رو بده نه اینکه بیای کلن Null رو نابود کنی و بذاریش کنار.ولی این دفعه دیگه کلاس ها زیر بار نرفتن و گفتن ما دیگه نمیتونیم تغییری توی خودمون بدیم و دستمون برای تغییر بسته هست و برید پیش اقای Dart که مشکل رو براتون حل کنه.پس این شد که اقای Dart موند و یه بچه بدون سرپرست (Null) و برنامه نویس هایی که هم این بچه رو لازمش داشتن و هم از دستش عاصی بودن.دیگه این بار خود Dart دست به کار شد و یه سری چیزای جدید اختراع کرد که هم از Null بدون استفاده نمونه و هم برنامه نویس ها راضی باشن...بریم ببینیم چه اتفاقی افتاد...گفتیم که با کنار گذاشتن Null حالا دیگه وقتی که یه variable ای تعریف میکردیم دیگه نمیتونستیم بهش مقدار null رو بدیم چون که دیگه کلاس Null فرزند کلاس های دیگه نبود. ولی بعضی از مواقع نیاز داشتیم که یه variable بتونه مقدار null رو هم بگیره. مثلن همون برنامه میزرا قلی رو در نظر بگیرید که یه کاربری داشت با یه سری فیلد ها.خب توی این برنامه ساده مثلن فیلد id و firstname و lastname هیچ موقع null نمیشن(این رو غضنفر به میرزا قلی گفته و بهش اطمینان داده که من هیچ موقع از سمت سرور برای این فیلد ها null نمیفرستم) ولی فیلد friends ممکنه بعضی مواقع null بشه و بعضی مواقع هم نشه. پس وقتی که میرزا قلی داره کلاس user رو میسازه باید بتونه یه جوری این فیلدها رو تعریف کنه که اون سه تا فیلد اول هیچ اجازه ای برای null شدن نداشته باشن ولی فیلد آخر این اجازه رو داشته باشه.برای variable هایی که میخوایم هیچ اجازه ای برای null شدن نداشته باشن قضیه ساده هست. مثلن وقتی که میگیم : String myStrاین variable دیگه نمیتونه مقدار null بگیره.ولی برای جاهایی که نیاز هست یه variable همزمان بتونه مقدار null رو هم بگیره Dart یه type جدید رو معرفی کرد.Type? myVariableدارت گفتش که برای variable هایی که نیاز دارن null رو هم بگیرن بعد از نوع متغیر یه علامت ? بگذارید.String? myStrمثلن توی کد بالا با گذاشتن یه علامت ? بعد از String باعث میشیم که variable هم بتونه یه مقدار از جنس String بگیره و هم بتونه یه مقدار از جنس Null بگیره(که همون null هست, تنها نمونه ای که میتونیم از کلاس Null بسازیم.)ولی ببینیم با اضافه کردن این ? چه اتفاقی داره میوفته...در واقع با اضافه کردن این علامت ? یه Type جدید تولید میشه. مثلن با یه Type از نوع String داریم که با اضافه کردن ? و تبدیلش به  ?String یه Type جدید تولید میشه.این Type جدید به صورت زیر تفسیر میشه : String? =&gt; String | Nullیعنی ?String یه Type جدید هست و variable ای که از این جنس هست میتونه مقادیری از جنس String و یا Null داشته باشه.(علامت | به معنای یا هست.) توی دنیای برنامه نویسی به این نوع type ها میگن Union Types. یعنی Type هایی که به variable اجاره میده همزمان مقادیری از type های مختلف رو بگیره. پس نتیجه میگیریم که ?String هم یک Union Type هست چون که وقتی که یه variable با این نوع تعریف بشه همزمان میتونه مقادیر از جنس String یا مقادیری از جنس Null (null) رو بگیره.به صورت کلی تر میتونیم بگیم که :Type? =&gt; Type | Null
اگه بخوام با شکل بهتون نشون بدم اینجوری میشه :میبینید که نوع ?String یه نوع جدید هست و به و صورت String | Null تفسیر میشه.یا به عبارت دیگه نوع جدید ?String دو تا فرزند داره که یکی از فرزند هاش String هست و اون یکی هم Null.پس طبق قواعد شی گرایی وقتی که یه variable از جنس ?String تعریف میکنیم میتونیم بهش مقادیری از جنس فرزند هاش یعنی String و یا Null رو بدیم.حالا یه چیز بهتون بگم بین خودمون بمونه...یه برنامه نویس حرفه ای باید ادبیاتش هم حرفه ای باشه یعنی وقتی که حرف میزنه هم مشخص باشه که با بقیه فرق داره وکلن دارن حرفه ای صحبت میکنه.پس از این به بعد اگه یه variable از جنس ?String تعریف کردید دیگه نگید که من یه variable از جنس String دارم چون که این دیگه یه String  نیست باید بگید یه variable از جنس String | Null (استرینگ یا نال) یا به عبارت ساده تر یه variable از جنس nullable String دارم. پس :String =&gt;  String (or non nullable String)String? =&gt; nullable Stringپس تا اینجا فهمیدیم که توی ورژن جدید Dart ما Non nullable Type ها یا همون Type های معمولی رو داریم و همچنین Nullable Type ها که با اضافه کردن یه ? به Type های معمولی تولید میشن.توی قسمت بعدی قراره میرزا قلی برای بچهای قل آباد کلاس آنلاین برگزار کنه و بهشون null safety رو یاد بده...بریم ببینیم چی میشه ....</description>
                <category>Mohammad Taheri</category>
                <author>Mohammad Taheri</author>
                <pubDate>Sun, 21 Nov 2021 13:52:56 +0330</pubDate>
            </item>
                    <item>
                <title>داستان Null در دارت (نال فرزند ناخلف)</title>
                <link>https://virgool.io/flutter-challenge/%D8%AF%D9%86%DB%8C%D8%A7%DB%8C-%D9%82%D8%A8%D9%84-%D8%A7%D8%B2-null-safety-%D8%AF%D8%B1-%D8%AF%D8%A7%D8%B1%D8%AA-%D9%86%D8%A7%D9%84-%D9%81%D8%B1%D8%B2%D9%86%D8%AF-%D9%86%D8%A7%D8%AE%D9%84%D9%81-mriok0gq0jkl</link>
                <description>توی قسمت قبلی دیدیم که قبل از null safety همه کلاس های Dart فرزند کلاس Object بودن (که البته این موضوع به قبل و بعد null safety ربطی نداره و همچنان صادقه) همچنین دیدیم که یه کلاس به اسم Null داریم که این کلاس فرزند همه کلاس های دیگه هست و تنها نمونه ای هم که از این کلاس میتونیم داشته باشیم کلمه کلیدی و رزرو شده ی null هستش و به خاطر همین موضوع که کلاس Null فرزند همه کلاس های دیگه محسوب میشد میتونستیم مقدار null رو به هر variable ای با هر type ای بدیم.ولی داستان به همین خوبی پیش نمیرفت و این آقا یا خانم Null مشکلات زیادی رو درست میکرد. هر روز دعوا ها و مشاجره های زیادی به خاطر این آقا بین برنامه نویس ها و Dart و کلاس ها شکل میگرفت.بیاین داستان یکی از این مشاجره ها رو با هم بخونیم....از قرار معلوم میرزا قلی یه برنامه نویس فلاتر بود که قرار بود یه اپ ساده بزنه. این اپ یه User داشت و هر user یه سری friend داشت و میرزا قلی باید مشخصات کاربر به همراه تعداد دوستاشو توی یه صفحه ساده نمایش میداد.میرزا قلی برای مدل سازی کاربر هاش توی اپش کلاس ساده زیر رو در نظر گرفت :از اونجایی که میرزا قلی قرار بود که اطلاعات کاربر رو از سرور دریافت کنه با دوستش غضنفر که برنامه نویس بک اند بود همکاری میکرد و غضنفر گفت که من بهت یه API میدم که اطلاعات کاربر رو بهت میده. خروجی اون API یه JSON به شکل زیر بود :میرزا قلی هم اومد و باتوجه به این JSON یه json serialization برای کلاسش نوشت:میبینید که میرزا قلی یه factory به اسم fromJson به کلاسش اضافه کرد که JSON دریافتی از غضنفر رو به کلاس Dart تبدیل کنه و یه متد toJson هم برای تبدیل کلاسش به JSON نوشت.تا این جای داستان همه چیز به خوبی و خوشی پیش میرفت و همه خوشحال بودن تا اینکه یهو سر و کله ی حاجی نصرت پیدا شد (حاجی نصرت صاب کار این دو تا بود) , حاجی خیلی عصبانی بود و میگفت چنتا کاربرا وقتی اپ رو باز میکنن اپ میپره بیرون و شما دو تا بی عرضه نتونستین یه اپ درست بدین دست من.میرزا قلی تقصیر رو مینداخت گردن غضنفر و میگفت این چیزا به من ربطی نداره و مربوط به سرور میشه و غضنفر هم میگفت به من چه آقاااااااا اپ داره سوتی میده و میپره بیرون , تو میگی مربوط به سروره ؟؟؟!!!خلاصه آخرش میرزا قلی قبول کرد که بشینه و بررسی کنه و بعد از بررسی های شبانه روزی به این نتیجه رسید که غضنفر بعضی مواقع به جای لیست دوستان واسش null میفرسته. یعنی به جای اینکه اطلاعات رو این شکلی بفرسته : این شکلی میفرسته :میرزا قلی هم که میخواست روی این لیست عملیات انجام بده و نمیدونست که این لیست بعضی مواقع null ارسال میشه, هیچ چکی انجام نداده بود و یه همچین خطایی رخ میداد : حالا قضیه این خطا چی بود ؟همون طور که گفتیم Null فرزند همه بود و میشد null رو که یه نمونه از این کلاس بود رو به همه type ها داد ولی وقتی که میخواستیم یه متد رو روی type مورد نظرمون صدا بزنیم این اقای null میگفت که من همچین متدی ندارم , درسته که من یه فرزند ضمنی از همه کلاس ها به حساب میام ولی از هیچ متدی پشتیبانی نمیکنم و این میشد که این خطا رخ میداد.(واقعن فرزند ناخلف که میگن همینه, فرزند همه بود ولی از هیچی هم پشتیبانی نمیکرد.)مثلن کد ساده زیر رو در نظر بگیرید :‌حالا مقدار name رو عمدن null میدم (مربوط به قبل null safety ایه ها)میبینید که یه خطا رخ داده و گفته که این متد یعنی length رو روی شی مورد نظر وجود نداره.توجه داشته باشید که این خطاها از نوع Runtime Exception ها هستن و موقع اجرای برنامه خودشون رو نشون میدن.حالا توی این مورد ساده میشه با یه if قضیه رو حل کرد : ولی خب همیشه قضیه به این سادگی ها نیست.برگردیم به داستانمون ...میرزا قلی که خطا پیدا کرده بود و فهمیده بود که این لیست بعضی وقتا null ارسال میشه انگشت اشارشو گرفت به سمت غضنفر و خوشحاااال گفت که دیدید گفتم مشکل از سروره .... این آقا داره null میفرسته. غضنفر هم زیر بار نمیرفت که نمیرفت و میگفت بابا جان این تو دیتابیس اینجوری ثبت شده, من که نمیتونم کاریش کنم که, همون چیزی که توی دیتابیس هست رو میگیرم میدم به تو. میرزا قلی هم میگفت تو برنامه نویس نیستی وگرنه میتونستی درست بفرستی. غضنفر هم میگفت اگه تو برنامه نویسی درستش کن.خلاصه این مشکل فقط برای این ها پیش نیومد و خیلی از برنامه نویس ها درگیرش بودن تا اینکه تصمیم گرفتن برن توی گیت هاب Dart و یه issue باز کنن.برنامه نویس های بیچاره حرفشون این بود که یه کاری کن که به جای اینکه این چیزا رو موقع runtime خطا بگیره و ابرومون رو جلوی کاربرا ببره موقع کدنویسی بهمون بگه.Dart هم اول زیر بار نمیرفت و میگفت که این موضوع مربوط به من نیست و مربوط به کلاس ها میشه و Null بچه اوناست و من دخالت نمیکنم.خلاصه پس از کش و قوص های فراوان کلاس های Dart یه جلسه تشکیل دادن و یه تصمیم خیلی مهم در مورد Null گرفتن که توی قسمت بعدی این تصمیم مهم رو با هم میبینیم.</description>
                <category>Mohammad Taheri</category>
                <author>Mohammad Taheri</author>
                <pubDate>Fri, 19 Nov 2021 17:51:15 +0330</pubDate>
            </item>
                    <item>
                <title>داستان Null در دارت (نال فرزند همه)</title>
                <link>https://virgool.io/flutter-challenge/dart-null-safety-null-safety-%D8%AF%D9%86%DB%8C%D8%A7%DB%8C-%D8%AF%D8%A7%D8%B1%D8%AA-%D9%82%D8%A8%D9%84-%D8%A7%D8%B2-utjddlfzyiyd</link>
                <description>به اولین قسمت از مجموعه null safety در Dart خوش اومدی. برای اطلاع از همه قسمت های این مجموعه و زمان انتشار و آپدیتشون این لینک رو دنبال کن.همچنین اگه تا حالا عضو کانال فلاتری Flutter Challenge نشدی حتمن با این لینک عضو کانال شو که آموزش ها و چالش های بعدی رو از دست ندی.بریم ببینیم چه خبره....تصویر زیر رو ببین...این تصویر مربوط به دنیای Dart قبل از null safety هست.❓مفهومش رو فهمیدی؟اگه مفهومش رو خوب نفهمیدی نگران نباش , من واست توضیح میدم.زبان برنامه نویسی Dart یه زبان برنامه نویسی شی گرا هست یا اگه بخوایم خارجیش رو بگیم OOP که مخفف Object Oriented Programming.مثل همه زبان های برنامه نویسی شی گرای دیگه توی این زبان هم ما با class ها سر کار داریم.توی Dart هر چیزی که استفاده میکنیم تهش میخوره به یه class.فرض کن یه variable با نوع int تعریف کردی :‌int myNum = 2;این int خودش یه class هست.تصویر بالا یه اسکرین از source code کلاس int توی Dart هست. میبینید که int ای که بالا برای تعریف variable خودمون استفاده کردیم خودش یه class هست. در واقع ما داریم میگیم که یه variable میخوایم که جنسش از جنس کلاس int باشه یا اینکه من دارم یه variable ای میسازم که قراره یه نمونه یا object از کلاس int رو توی خودش نگه داره.پس وقتی که یه String یا ... رو هم تعریف میکنیم همین داستان بالا رو داریم :String myStr = &#039;......&#039;;یا وقتی که خودمون یه class میسازیم :‌ ?پس نتیجه گرفتیم که توی Dart همه چیز به class ختم میشه.?یه نکته پاورقی هم بگم که توی Dart حتا function ها هم به یه class ختم میشن. اگه میخوای در مورد این نکته بیشتر بدونی میتونی این پست از کانال فلاترمون رو ببینی.?حالا قضیه از اینجا شرو میشه که همه کلاس ها توی Dart از یه کلاس به اسم Object ارث بری میکنن.هر کلاسی که توی Dart داریم از این کلاس ارث بری میکنه و این ارث بری به صورت ضمنی هست. پس این کلاس یه super type برای همه کلاس های Dart به حساب میاد.مثال زیر رو ببین :میبینیم که یه variable از جنس int دارم و بعدش گفتم که ایا a یه Object هست ؟a is Object و جواب true هست چون که کلاس int از کلاس Object ارث بری میکنه و هر variable ای که از جنس int باشه از جنس Object هم هست.حالا این وسط یه استثنا وجود داره و اون هم کلاس Null هست .درست شنیدی کلاس Null , این با null فرق داره .(به حرف بزرگ دقت کن)توی Dart یه کلاسی داریم به اسم Null .برای این کلاس فقط و فقط  و فقط یه نمونه یا object وجود داره که اون هم کلمه کلیدی null هست .پس کلمه کلیدی null (با حرف کوچیک) یه نمونه یا یه شی یا یه object(حرف کوچیک) از کلاس Null(حرف بزرگ) هست و تنها نمونه یا شی ای که میتونیم از این کلاس داشته باشیم هم همین هست.The reserved word &#x60;null&#x60; denotes an object that is the sole instance of this class.حالا بریم به دنیای قبل از null safety و ببینیم که چه خبر بوده ...تصویر بالا رو با دقت نگاه کن.قبل از null safety همه کلاس ها از کلاس Object ارث بری میکردن و یه فرزند از اون به حساب میومدن و کلاس Null هم خودش یه فرزند از همه کلاس های دیگه به حساب میومد.کلاس Null به صورت مستقیم از Object ارث بری نمیکرد بلکه یه فرزند (فرزند ضمنی) همه کلاس های دیگه به حساب میومد.به خاطر همین توی دنیای قبل null safety وقتی که مثلن یه variable از جنس int تعریف میکردیم میتونستیم بهش مقدار null هم بدیم.اینجا یه variable از جنس int تعریف کردم. پس مقداری که بهش میدیم باید یه عدد صحیح باشه ولی چون که کلاس Null خودش یه فرزند از هر کلاسی (از جمله int )به حساب میاد میتونم بهش مقدار null (که یه شی از کلاس Null هست) رو هم بدم.تاکید میکنم که این داستان برای قبل از null safety هست.خب این قسمت رو همین جا به پایان میرسونیم.امیدوارم که لذت برده باشید.توی قسمت بعدی میبینیم که جناب Null یه فرزند ناخلف و دردسر ساز بوده پس بدون از دست دادن زمان قسمت بعدی رو بخون.</description>
                <category>Mohammad Taheri</category>
                <author>Mohammad Taheri</author>
                <pubDate>Thu, 18 Nov 2021 14:44:51 +0330</pubDate>
            </item>
                    <item>
                <title>داستان Null در دارت</title>
                <link>https://virgool.io/flutter-challenge/dart-null-safety-introduction-qelr6jcpsj1c</link>
                <description>سلام رفقا , دخترا و پسرای خوب فلاتر توی این مجموعه داستان جذاب سرگذشت Null توی Dart رو با هم مرور میکنیم و null safety رو خیلی خوب و دقیق یاد میگیریم.بعد از خوندن این مجموعه مقاله مثل یه استاد ماهر و بدون نگرانی از این ویژگی خوب Dart استفاده میکنی.قبل از شروع به خوندن اگه هنوز توی کانال فلاترمون عوض نشدی سریعتر از اینجا عضو شو که مقاله ها و چالش های جذاب بعدی رو از دست ندی.پس بزن بریم...شخصیت های اول این داستان : دارتکلاس های دارتنالمیرزا قلی برنامه نویس فلاترشخصیت های دیگه ای هم در آینده اضافه میشن...دیگر شخصیت های داستان هم قاضی دادگاه و دوستای میرزا قلی (مثل غضنفر برنامه نویس بک اند و ...) هستن.توی قسمت اول داستان میریم به گذشته ها و یکم خاطرات گذشته رو مرور میکنیم , میریم  به دنیای قبل از null safety و میبینیم که قبل از اضافه شدن این ویژگی به Dart دنیا دست کی بود , توی این قسمت میبینیم که قبل از null safety همه کلاس ها توی Dart یه فرزند از کلاس Object بودن و کلاس Null هم خودش فرزند همه کلاس های دیگه بوده.(برای جزییات بیشتر این قسمت رو از اینجا مطالعه کن).بعدش توی قسمت دوم داستانمون میبینیم که این جناب Null که فرزند همه کلاس های دیگه بوده همچین فرزند خوب و سر به راهی نبوده و دردسرها و مشکلات زیادی درست میکرده , به عبارتی فرزند ناخلف بوده. این بچه ناخلف همیشه سر و صدای برنامه نویس ها رو در میورده و برنامه نویس ها هم همیشه سر دارت نق میزدن.(این قسمت رو هم از اینجا میتونی مطالعه کنی)توی قسمت سوم که رفته رفته وارد دنیای بعد از null safety میشیم, کلاس های Dart پس از رنج های فراوونی که از دست این فرزند ناخلفشون میکشن یه تصمیم خیلی مهم میگیرن و اون رو میزارنش سر راه و Null میشه یه فرزند سر راهی ???  و پس از بحث و جدل های فراوان خود Dart سرپرستی اون رو به عهده میگیره و Null بیچاره میشه یه بچه ای که نه پدر داره نه مادر , خودش بچه هم که نداشت , میشه تک و تنها.حالا Dart یه سری ویژگی های جدید به برنامه نویس ها ارایه میده که بتونن از این بچه سرراهی هم استفاده کنن.(این قسمت رو هم میتونی از اینجا مطالعه کنی.)توی قسمت چهارم میرزا قلی همون برنامه نویس فلاتر یه کلاس آنلاین برای بچه های قل آباد برگزار میکنه تا null safety رو بهشون آموزش بده ولی با این وجود تبلیغات فراوان و خوب شروع شدن کلاس مثل اینکه اتفاقات دیگه ای میوفته...با هم ببینیم توی این قسمت چه اتفاقاتی میوفته...ولی آخرای این قسمت برنامه نویس ها که از Dart حسابی به ستوه اومدن دست به یه شورش سراسری علیه Dart میزنن و سرانجام Dart دستگیر میشه...توی قسمت پنجم یه دادگاه برای رسیدگی به شکایات برنامه نویس ها از Dart تشکیل میشه. و حالا Dart باید توی این دادگاه از خودش دفاع کنه.این قسمت رو که اولین جلسه رسیدگی به اتهامات Dart هست رو با دقت بخون...ببینیم آیا Dart میتونه از خودش دفاع کنه یا  باید برای همیشه Dart رو بذاریم کنار؟توی این قسمت نکات جذابی در مورد Scope های مختلف که یک variable تعریف و استفاده میشه و ارتباط اون Scope ها با هم و همچنین نحوه ی تعامل با nullable variables و non-nullable variables و final variables توی Scope های مختلف و کاربرد کمله کلیدی late یاد میگیریم.قسمت قبلی رو خوندی حالا این قسمت رو که دومین جلسه دادگاه هست رو بخون...توی این قسمت هم نکات زیادی در مورد انواع آرگومان های ورودی function ها و constructor ها یاد میگیریم.همراه این مجموعه مقاله باش که کلی اتفاقات جذاب قراره بیوفته.قسمت های جدید به زودی منتشر میشه...</description>
                <category>Mohammad Taheri</category>
                <author>Mohammad Taheri</author>
                <pubDate>Thu, 18 Nov 2021 13:56:42 +0330</pubDate>
            </item>
                    <item>
                <title>Dart Const (استفاده در فلاتر)</title>
                <link>https://virgool.io/flutter-challenge/dart-const-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%AF%D8%B1-%D9%81%D9%84%D8%A7%D8%AA%D8%B1-shuxeh14ngkr</link>
                <description>Flutter Challenge(چالش فلاتر)رسیدیم به بخش جذاب کار یعنی استفاده از const در Flutter. اگه مقاله مربوط به const constructor رو نخوندی میتونی از اینجا اون رو بخونی و برای بررسی همه مقالات مربوط به const هم این لینک رو ببین.توی مقاله قبلی یه نکته در مورد Widget ها در Flutter گفتیم.گفتیم که Widget ها Immutable هستن و اون ها رو به const constructor مجهزشون کنید و هرجایی که امکانش بود ازشون object (نمونه) های const بسازید.اگه source code فلاتر رو نگاه کنید میبینید که بالا سر کلاس ویجت @immutable قرار داره.حالا دلیل اینکه چرا توسعه دهندگان فلاتر ویجت ها رو Immutable در نظر گرفتن خارج از بحث این مقاله هست و در آینده و مقاله های تخصصی تر بهش میپردازیم. الان هدفمون استفاده کاربردی از این ویژگی هست.?پس طبق عکس بالا و تعریف داکیومنت از Widget باید بگیم که کلن Widget داخل فلاتر immutable هست, بعضی جاها دیدم که میگن Stateless ها Immutable هستن و Stateful ها mutable. نه اصلن این حرف رو قبول نکنید, کلن ویجت ها از هر نوعی که میخوان باشن Immutable هستن و Stateful ها یه State دارن که اون mutable هست.?توی ورژن های قبلی فلاتر اگه یه ویجت میساختیم و داخلش فیلد هایی استفاده میکیردیم که final نبودن(یعنی قاعده ی Immutable رو رعایت نمکیردیم) بهمون Warning میداد و میگفت که ویجتی که ساختی Immutable نیست.حالا توی ورژن جدید فلاتر یعنی 2.5 به یه چیز دیگه هم گیر میده و اگه ویجتی که میسازی const constructor نداشته باشه به این هم Warning میده.???پس یکبار دیگه تکرار میکنم که همه ویجت ها رو (همه همه همه) Immutable بسازید و واسشون const constructor بگذارید و هرجایی که امکانش بود ازشون object های const بسازید.هر جایی هم که امکانش نبود و یا نیاز داشتیم که یه object جدید بسازیم که new میکنیم.خب بعد از این مقدمه بریم سر اصل بحثمون...قبل از این گفتیم که دو شرط اصلی و اساسی که یک کلاس لازم داره که بتونه const constructor داشته باشه این هست که :همه instance field هاش final باشن یا به عبارتی immutable باشه.و constructor مورد نظر body نداشته باشه.حالا یه تبصره به این شروط اضافه میکنیم. ?اگه یه کلاسی داشته باشیم که داره از یه کلاس دیگه ارث بری میکنه , شرط اینکه کلاس فرزند بتونه const constructor داشته باشه این هست که کلاس پدر همه شروط بالا رو داشته باشه و علاوه بر اون constructor  کلاس پدر const باشه.خب همون طور که طبق عکس بالا میبینید Base Class ویجت ها در فلاتر هم immutable هست و هم از const constructor بهره میبیره در نتیجه این امکان رو به کلاس های فرزند میده که بتونن const constructor داشته باشن.?پ.ن: اکثر abstract class ها (base classها) که داخل فلاتر میبینیم اگه دقت کنید میبینید که یه const constructor که معمولن هیچ پارامتری هم نگرفته و خالی هست دارن(مثل همین بیس کلاس ویجت). علتش هم این هست که به کلاس های فرزند این امکان رو بده که بتونن const constructor داشته باشن.یه مثال از چیزایی که تا الان گفتیم بزنیم:همون طور که میبییند یه ویجت ساده ساختم و داخلش یه فیلد با نام title تعریف کردم که final نیست. و در نتیجه بهم تذکر داده که کلاست immutable نیست.متنش هم به این شکل هست:This class (or a class that this class inherits from) is marked as &#x27;@immutable&#x27; , but one or more of its instance fields aren&#x27;t final.خب حالا کلاسم رو immutable میکنم (یعنی title رو final میکنم) ولی قبل از constructor از const استفاده نمکینم.اینجا باز هم بهم Warning میده و میگه که از const constructor استفاده نکردی و این همون هشداری هست که گفتم توی ورژن جدید فلاتر بهمون میده.Prefer declaring const constructor on @immutable classes.اگه روی لینک مربوط به این Warning هم بزنیم توضیحات زیر رو میتونیم ببینیم.حالا یه دونه Stateful میسازم و فیلد title رو از حالت final درمیارم:اینجا باز هم اون Warning که  میگه کلاست immutable نیست رو میبینیم.This class (or a class that this class inherits from) is marked as &#x27;@immutable&#x27; , but one or more of its instance fields aren&#x27;t final.و اگه title رو final کنم و از const استفاده نکنم.باز هم Warning مربوط به const constructor رو خواهیم دید.Prefer declaring const constructor on @immutable classes.پس به صورت عملی هم دیدیم که از این نظر یعنی immutable بودن و const constructor هیچ تفاوتی بین Sateless و Stateful نیست.حالا ممکنه سوالاتی پیش بیاد:❓وقتی که یه ویجت رو به const constructor مجهز کردیم , ایا همه جا موقع ساخت object ازش باید از const استفاده کنیم؟نه... نه امکان چنین کاری هست و نه بعضی جاها منطقی. ❓چرا امکانش نیست که همه جا برای ساخت object از ویجت هامون از const استفاده کنیم؟یه دلیل اینکه همون طور که توی مقاله های قبلی گفتیم وقتی که یه const constructor داریم و میخوایم با استفاده از اون یه object بسازیم باید تمام وروردی هایی که بهش پاس میدیم compile-time constant باشن که در عمل این امکان پذیر نیست , یعنی در عمل بعضی مواقع نمیتونیم ورودی های const برای یک constructor تامین کنیم.مثال : مثلن شما ویجت Text رو در نظر بگیرید که قراره یه متنی رو نمایش بده و این متن قراره از سرور بیاد (مثلن عنوان کالا در یه اپ فروشگاهی یا متن پیام در یه اپ چت یا ... هست).عملیات دریافت متن از سرور توی run-time انجام میشه در نتیجه متن مورد نظر نمیتونه یه compile-time constant باشه پس در نتیجه اینجا نمیتونیم از ویجت مورد نظرمون یه const object بسازیم.(چرا که برای ساختن یه const object باید تمام ورودی هایی که به constructor پاس میدیم compile-time constant باشن.)علاوه بر این وقتی که موقع ساخت object از یه ویجت توی widget tree از const استفاده میکنیم موقع rebuild شدن اون قسمت از درخت, اون ویجتی که با const ساختیمش دیگه rebuild نمیشه. یعنی بار اول که ساخته شد و build شد دیگه تا آخر سرجاش هست و rebuild نمیشه.خب بعضی جاها نمیخوایم این اتفاق بیوفته و میخوایم ویجتمون rebuild شه.حالا بریم با مثال هایی ببینیم که کجاها توی فلاتر از const استفاده کنیم و نتیجه عملی این استفاده چی هست.مثال1)توی کدهاتون حتمن خیلی جاها نیاز دارین که از padding یا margin استفاده کنین و برای این کار از EdgeInset استفاده میکنین.تا اینجا مشکلی نیست و خیلیم عالی.حالا فرض کنید که یه اپ داریم که از 10 تا صفحه تشکیل شده و توی هر صفحه قراره از دو تا padding با مقدار مشخص استفاده کنیم:EdgeInsets.symmetric(horizontal: 16 , vertical: 32);
EdgeInsets.only(top: 48);فرض کنید از این دو مقدار توی 10 صفحه اپ و هر صفحه هم یکبار قراره استفاده بشه.حالا دو حالت در نظر میگیریم:حالت اول توی همه جاهایی که میخوایم از اینها استفاده کنیم قبلش new میگذاریم (یا هیچی نمیگذاریم)حالت دوم قبلشون const میگذاریم.قبل از اینکه این دو حالت رو با هم بررسی کنیم یه سری به کلاس EdgeInset بزنیم و ببینیم که چی داخلش داره.این کلاس یه کلاس immutable هست که 4 تا instance field داره (left , top , right , bottom) , همه constructor هاش هم const هستن و همه constructor ها در نهایت این 4 فیلد رو مقدار دهی میکنن.خب حالا حالت اول رو بررسی کنیم:توی این حالت هر جایی که به یه EdgeInsets.symmetric(horizontal: 16 , vertical: 32); نیاز داریم برامون یه دونه object جدید از EdgeInset با مقادیر (left = 16 , right = 16 , top = 32 , bottom = 32) میسازه .هر بار هم که به (EdgeInsets.only(top: 48 یه object جدید با مقادیر (left= right=bottom=0 , top=48)میسازه.پس اگه توی 10 تا صفحه و هر صفحه یک بار بهشون نیاز داشته باشیم در مجموع 20 تا object از کلاس EdgeInset میسازه و توی رم قرار میده.داستان به اینجا ختم نمیشه و اگه شما یک صفحه رو ببینید و دوباره باز کنید (pop , push) دوباره یه object جدید ساخته میشه و از قبلیا استفاده نمیکنه.(البته اینجا زباله جمع کن دارت میاد و object های بلااستفاده رو جمع میکنه ولی خب باز هم همین طوری الکی داره object جدید ساخته میشه.)حالا ببینیم توی حالت دوم چی میشه:اینجا چون از const استفاده کردیم.آقای کامپایلر میاد وسط میدون.وقتی میبینه که ما توی کدمون const EdgeInsets.only(top: 48) رو درخواست دادیم میره و یه object از این کلاس با مقادیر (left=right=bottom= 0 , top=48)میسازه و توی حافظه ذخیره میکنه و بعد از اون توی برنامه هر جایی که نیاز به  یه object از این کلاس با این مقادیر بود(که قبلش هم const اومده بود) از همین چیزی که قبلن ساخته استفاده میکنه.پس در نتیجه از ساخته شدن object های بیشمار و مصرف بیهوده فضای رم جلوگیری میشه.مثال2)توی کدهاتون خیلی جاها نیاز دارین که از ویجت SizedBox استفاده کنید, مثلن خیلی جاها توی یه column یا row نیازه که بین دو تا ویجت یه فاصله مشخص ایجاد کنیم. خب SizedBox هم که یه ویجته و مثل همه ویجت های دیگه const constructor داره. پس اینجور مواقع هم از const استفاده کنید.توی کد بالا چون که برای Text هام از String literal استفاده کردم که خودشون compile-time constant هستن میتونم Text ها رو هم const کنم.حالا چون همه ویجت هایی که توی این لیست (لیست چیلدرن) قرار دارن const هستن میتونیم پشت لیست یه const بذاریم و همه const ها رو از پشت ویجت ها برداریم.و در این حالت هم همه ویجت هایی که توی لیست هستن از حالت const استفاده میکنن.مثلن کد زیر رو ببینید:وقتی که قبل از Center از const استفاده کردیم دیگه نیاز نیست که برای Text و TextStyle هم از const استفاده کنیم و خودش این کار رو میکنه (یعنی الان Text و TextStyle هم const میشن)یعنی کد بالا با کد زیر فرقی نداره.میدونید چرا این اتفاق میوفته؟گفتیم که وقتی میخایم از یه کلاس یه const object بسازیم باید تمام ورودی هایی که به constructor پاس میدیم compile-time constant باشه. خب اینجا قبل Center از const استفاده کردیم. ورودی Constructorاش هم که Text هست که باید const باشه (که بدون اینکه ما بگذاریم خودش اینکار رو میکنه) و ورودی Text هم که یه متن و همین طور TextStyle هستن, پس اگه قبل TextStyle هم const نذاریم خودش اینکار رو میکنه.حالا فرض کنید قبل Center از const استفاده کردیم ولی  Text قابلیت const بودن نداره مثل کد زیر:میبینید که در این حالت بهمون ارور میده. چون که Text دیگه نمیتونه const باشه(متن Text داره از widget گرفته میشه که توی run-time مشخص میشه و دیگه compile-time constant نیست) و در نتیجه Center هم نمیتونه const باشه (چون که ورودیش const نیست), در این حالت فقط همون TextStyle رو const میکنیم.مثال3)کد زیر یه فرم لاگین خیلی خیلی ساده هست که یه عنوان داره و یه تکست فیلد برای ورود شماره تلفن و یه دکمه ی تایید.همین طور که میبینید این فرم داخل یه State قرار گرفته و به دلایل مختلف ممکنه که rebuild بشه و با هر بار rebuild شدن تمام ویجت هایی که داخل متد build قرار گرفتن یه بار دیگه از اول ساخته میشن و rebuild میشن.حواستون باشه با هر بار rebuild شدن متد build تمام ویجت ها دوباره ساخته میشن و متد build اشون صدا زده میشه.خب اینجا یه سری از ویجت ها مثل ویجت Text که داره عنوان رو نشون میده نیاز نیست هر بار که State مورد نظر rebuild میشه دوباره از اول ساخته بشه. پس میشه با قرار دادن یه const قبل ویجت Text که داره متن Sign In رو نشون میده از این مورد جلوگیری کرد.ولی نه صبر کنید!!!قبل Text یه const گذاشتم ولی داره بهم ارور میده.❓میبینید؟ چرا اینطوری شد؟مربوط به style هست , style ای که بهش دادیم یه compile-time constant نیست.❓خب پس چکار کنیم؟ از یه طرف نمیخوایم با هر بار rebuild شدن این State ویجت Text یه بار از اول ساخته بشه(چون که یه عنوان هست و قرار نیست تغییر کنه) و از طرفی هم نمیتونیم قبلش const بگذاریم.❓نظر شما چیه؟من میگم میتونیم این ویجت رو کلن اکسترکت کنیم و ی ویجت جدید با نام SignInFormTitle بسازیم و اون رو const کنیم.الان یه ویجت ساختیم که وظیفش اینه که عنوان فرم رو نشون بده (SignInFormTitle) و قبلش هم از const استفاده کردیم در نتیجه هر بار که State مورد نظر rebuild بشه این ویجت دوباره از اول ساخته نمیشه و در نتیجه rebuild هم نمیشه.❓دقیقن چه اتفاقی میوفته؟یه ویجت به اسم SignInFormTitle داریم که برای استفاده ازش از const استفاده کردیم.پس کامپایلر یه object ازش میساره و هر جا که خواستیم بهمون میده. حالا بار اول اول که این کد ها اجرا میشن متد build این ویجت اجرا میشه و اون Text که const هم نیست ساخته میشه. ولی دفعه های بعدی که درخت rebuild میشه دیگ این ویجت rebuild نمیشه و متد build اش صدا زده نمیشه.(این موضوع که بار اول اول که کدها اجرا میشن متد build ویجت SigninFormTitle اجرا میشه و بعد از rebuild شدن درخت دیگه اجرا نمیشه به دلیل کاری هست که فریمورک فلاتر با ویجت های const میکنه که توضیحش از بحث این مقاله خارج هست.)??سعی میکنیم در آینده با مثال های بیشتر این مقاله رو تکمیل تر کنیم.????امیدوارم از مجموعه مقاله Dart Const لذت برده باشید و بتونید توی پروژه هاتون به خوبی و با درک عمیق ازش استفاده کنید.??</description>
                <category>Mohammad Taheri</category>
                <author>Mohammad Taheri</author>
                <pubDate>Thu, 23 Sep 2021 01:05:36 +0330</pubDate>
            </item>
                    <item>
                <title>Dart Const (Introduction)</title>
                <link>https://virgool.io/flutter-challenge/dart-const-introduction-knezoduxwgqv</link>
                <description>با یک مجموعه مقاله جذاب از Flutter Challenge در خدمت شما هستیم. توی این مجموعه کلید واژه const در زبان برنامه نویسی Dart رو به طور دقیق بررسی میکنیم.ابتدا توضیحات داکیومنت دارت در مورد const و final رو میبینیم.توی این لینک (dart/language-tour) اینجوری در مورد const و final گفته:If you never intend to change a variable, use final or const, either instead of var or in addition to a type. A final variable can be set only once; a const variable is a compile-time constant. (Const variables are implicitly final.) A final top-level or class variable is initialized the first time it’s used.اگر هرگز قصد ندارید که یک متغیر رو تغییر بدید به جای استفاده از کلمه کلیدی var از final یا const برای تعریف اون استفاده کنید(یا علاوه بر مشخص کردن نوع متغیر از این کلید واژه ها استفاده کنید).متغیر هایی که به صورت final تعریف شده اند فقط یک بار میتوانند تنظیم شوند(مقدار بگیرند) و قابل تغییر نیستند. متغیرهایی که به صورت const تعریف شده اند ثابت های زمان کامپایل هستند.(توی پرانتز هم میگه که متغیرهای const به صورت ضمنی final هستند.)بعد از این تعریف چندتا مثال میاره...final name = &#039;Bob&#039;; // Without a type annotation
final String nickname = &#039;Bobby&#039;;
name = &#039;Alice&#039;; // Error: a final variable can only be set once.یک متغیر رو final گرفته و بعد خواسته مقدارش رو تغییر بده که به ارور خورده.در ادامه توضیحاتش این رو اضافه میکنه:Use const for variables that you want to be compile-time constants. If the const variable is at the class level, mark it static const. Where you declare the variable, set the value to a compile-time constant such as a number or string literal, a const variable, or the result of an arithmetic operation on constant numbers:از const برای متغیرهایی استفاده کنید که می خواهید ثابت زمان کامپایل باشند.اگر میخواهید یک متغیر const در سطح کلاس داشته باشید اون رو static کنید (static const ).وقتی یک متغیر const تعریف میکنید و میخواهید به اون مقدار بدید مقدارش رو برابر با یک ثابت زمان کامپایل (compile-time constant) قرار بدید مانند یک رشته یا عدد (string or number literal) یا ....بعدش هم این مثال ها رو اورده :const bar = 1000000; // Unit of pressure (dynes/cm2)
const double atm = 1.01325 * bar; // Standard atmosphereو در ادامه توضیحات دیگه ای رو میده:The const keyword isn’t just for declaring constant variables. You can also use it to create constant values, as well as to declare constructors that create constant values. Any variable can have a constant value.کلید واژه const فقط برای تعریف متغیر های ثابت نیست.شما میتونید از این کلید واژه برای ایجاد مقادیر ثابت (values) و همچنین سازنده هایی که مقادیر ثابت رو ایجاد میکنند استفاده کنید.(منظورش اینه فقط قبل اسم متغیر نمیاد بلکه میتونه قبل اسم سازنده یا قبل مقدار هم بیاد.)var foo = const [];
final bar = const [];
const baz = []; // Equivalent to `const []`You can change the value of a non-final, non-const variable, even if it used to have a const value:foo = [1, 2, 3]; // Was const []You can’t change the value of a const variable:baz = [42]; // Error: Constant variables can&#039;t be assigned a value.? این جملات و توضیحاتی که به صورت کلمه به کلمه از سایت دارت کپی کردم(و واستون ترجمه کردم) انقد دقیق و مهم هست که باید اون ها رو با آب طلا بنویسیم.ولی همون قدر که مهم و نقطه زن هست برای مخاطبی که برای اولین باره که اون رو میخونه (یا حتا چندمین بار) گیج کننده هست.اینجوری بهتون بگم که کلمه به کلمه این توضیحات باید تفسیر بشن و بعد از تفسیرش تازه میفهمید که چه مفهوم عمیقی پشت این تعاریف سایت دارت بوده.???من اینجام برای یه تفسیر خوب و عمیق. ???پس بزن بریم...قسمت اول : بررسی مفاهیم اولیه و معرفی const variables.قسمت دوم : بررسی مفهوم const در کلاس (static const).قسمت سوم : const values .قسمت چهارم :‌ بررسی مفهوم const در کلاس (const constructor).قسمت پنجم : استفاده از const در Flutter.توی هر کدوم از این قسمت ها یه بخشی از داکیومنت رو تحلیل میکنیم و به صورت دقیق و مفهومی تفسیر میکنیم و در نهایت هم به صورت کاملن کاربردی توی فلاتر ازش استفاده میکنیم.??</description>
                <category>Mohammad Taheri</category>
                <author>Mohammad Taheri</author>
                <pubDate>Mon, 20 Sep 2021 23:27:30 +0430</pubDate>
            </item>
                    <item>
                <title>Dart Const (const constructor)</title>
                <link>https://virgool.io/flutter-challenge/dart-const-const-constructor-sbynlmrrq8nc</link>
                <description>Flutter Challenge(چالش فلاتر) قسمت قبلی: Const values.در ادامه میرسیم به بحث شیرین const constructor ها.?جلسه قبلی در مورد const values صحبت کردیم که مقدمه ای بود برای درک مفهوم const constructor ها.?قبلن در مورد اجزای تشکیل دهنده یه کلاس توضیح دادیم و گفتیم که هر کلاس از یک سری فیلد تشکیل میشه (instance fields) و همچنین یک سری تابع که روی این فیلد ها عمل میکنن (methods ). فیلدهایی با عنوان static هم داشتیم که به طور مفصل راجبشون صحبت کردیم و گفتیم که توی یه کلاس فقط فیلد های static قابلیت const شدن دارن و instance field ها نمیتونن const باشن چون که موقع run-time و بعد از ساخته شدم نمونه از کلاس مقداردهی میشن و قابل دسترسی هستن.?از طرف دیگه گفتیم وقتی که از کلید const قبل یه variable یا value استفاده میکنیم اون قسمت در زمان کامپایل تحلیل و مقدارش ثبت میشه. پس برای صحبت کردن در مورد const constructor ها ابتدا باید constructor رو بشناسیم و ببینیم چه قسمت هایی از یک constructor قابلیت این رو داره که در زمان کامپایل توسط کامپایلر عزیز آنالیز بشه.سازنده یا Constructor چیه؟یه متدی داخل کلاس هست که موقع ساخت نمونه از کلاس صدا زده میشه.عملیات ساخت نمونه از یه کلاس هم که همیشه توی run-time انجام میشه , پس کدهایی که داخل constructor زده میشه موقع run-time اجرا میشن.ولی همون طور که میدونید وظیفه ی اصلی constructor ها این هستش که instance field های یک کلاس رو مقدار دهی اولیه کنن(initialize).خب حالا ببینیم این initialize کردن داخل دارت چند روش میتونه داشته باشه:روش اول: استفاده از this در ارگومان ها ورودی سازنده.?این قسمت توسط کامپایلر قابل رصد شدن هست و کامپایلر میتونه ارگومان های ورودی سازنده های کلاس ها رو چک کنه.روش دوم : استفاده از لیست مقدار دهی(initialize list).?این قسمت هم توسط کامپایلر قابل رصد هست.روش سوم : استفاده از constructor body.?این قسمت یعنی constructor body توسط کامپایلر قابل رصد نیست و زمانی که از کلاس مورد نظر نمونه ساخته میشه (run-time) اجرا میشه و از اسرار اون پرده برداشته میشه.???پس روش های اول و دوم توسط کامپایلر قابل رصد شدن و آنالیز هستن و روش سوم نه.❓چرا؟چون که توی روش های اول و دوم فقط instance field ها دارن مقدار دهی میشن و کامپایلر میتونه این رو به راحتی آنالیز کنه ولی توی روش سوم علاوه بر مقدار دهی instance field ها , کد های دیگه هم ممکنه داخل constructor body قرار بگیره که این کد ها فقط و فقط توی run-time و موقع ساخت نمونه باید اجرا بشن.❓پس با توجه به مفهومی که از const میدونیم برای داشتن یک const constructor کدوم یک از روش های بالا قابل استفاده هستن؟???افرین... فقط روش اول  و دوم. چون که اگه بخوایم یه const constructor داشته باشیم باید قابلیت این رو داشته باشه که زمان کامپایل همه بخش های اون آنالیز بشن.خب این از نکته اول در ساخت const constructor ها.اما یه نکته دیگه هم برای ساخت const constructor وجود داره ...???این که همه instance field های کلاس مورد نظر final باشن. در واقع کلاسمون immutable باشه(یعنی غیر قابل تغییر باشه).از این نظر کلاس ها به دو دسته تقسیم میشن.Immutableکلاسی که همه instance field های اون final هست و در واقع اون کلاس قابلیت ویرایش نداره و اگه خواستید یکی از فیلد های اون کلاس رو تغییر بدید باید یه نمونه جدید بسازید.کلاس بالا رو در نظر بگیرید که از این نوع هست . یه نمونه به اسم p ازش ساختیم. حالا اگه بخوایم مقدار x رو توی این نمونه تغییر بدیم :میبینید که امکانش نیست و مجبوریم یه نمونه جدید با مقدار x جدید بسازیم.mutableکلاسی که حداقل یه دونه از instance field های اون final نباشه و قابلیت ویرایش رو داشته باشه.???پس گفتیم که شرط دوم برای داشتن یه const constructor این هست که کلاسمون immutable باشه.❓ولی چرا؟چون که با توجه به مفهوم const قراره که توی زمان کامپایل یه نمونه از اون کلاس ساخته بشه و توی حافظه قرار بگیره و بعد از اون توی run-time هر موقع که یه نمونه با مقادیر مورد نظر از اون کلاس خواستیم دقیقن همون نمونه ساخته شده زمان کامپایل رو بهمون بده. خب حالا اگه نمونه های ساخته شده قابل ویرایش باشن ما نمیتونیم جاهای مختلف که به اون نمونه نیاز داریم از یه نمونه واحد ساخته شده توی compile-time استفاده کنیم.(این رو وقتی مثال بزنیم بهتر متوجه میشید , بعدن دوباره برگردید به این جمله و دوباره بخونید.)پس یه بار دیگه چیزایی که تا اینجا گفتیم رو مرور میکنیم:دو تا شرط برای داشتن یه const constructor داریم:کلاس مورد نظر immutable باشه (همه فیلد های اون final باشن.)سازنده مورد نظر body نداشته باشه (از روش اول یا دوم برای مقدار دهی اولیه فیلد ها استفاده کنه.)خب بریم مثال بزنیم:توی کد بالا کلاسمون immutable هست و constructor هم از روش اول برای مقداردهی فیلد ها استفاده کرده.دو نمونه با مقادیر کاملن یکسان ساختیم و اون ها رو با هم مقایسه کردیم و نتیجه false شد.❓چرا؟چون که هر بار که درخواست میدیم برای ساخت نمونه , یه نمونه جدید و توی یه مکان جدید از حافظه ساخته میشه و چون که اپراتور == فقط بررسی میکنه که ایا دو نمونه مورد نظر به یک مکان از حافظه اختصاص دارن یا نه نتیجه false میشه.مثال بعدی:دو تا تغییر توی کد دادم:اول توی کلاس و قبل constructor از کلید const استفاده کردم.دوم موقع ساخت نمونه از const قبل value ها استفاده کردم.با تغییر اول constructor مورد نظر قابلیت این رو پیدا میکنه که در زمان کامپایل آنالیز بشه.(اون دو شرط اصلی هم که رعایت شده.)❓خب حالا چه اتفاقی میوفته؟کامپایلر وقتی که میرسه به const Point(2 , 4) میره و یه نمونه با این مقادیر ایجاد میکنه و توی حافظه ثبت میکنه و از اون بع بعد توی run-time هر موقع به این عبارت یعنی const Point(2 , 4) رسید میبینه که قبلن یه نمونه با همین مقادیر ثبت کرده و دقیقن همون نمونه رو میریزه توی متغیر. پس هر دو متغیر دقیقن به یک مکان از حافظه اشاره میکنن و نتیجه true میشه.مثال بعدی :میبینید که اولین نمونه رو با const ساختم و دومی رو بدون const .(وقتی هیچی نمیذاریم خود دارت به صورت پیش فرض new قرار میده).شما بگید...❓چرا نتیجه false شد؟مثال بعدی :‌ میبینید که طبق این مثال یه کلاس میتونه شامل چنتا constructor باشه که بعضی هاشون const هستن و بعضی هاشون نه.یه مثال ساده :الان دو تا نمونه ی ثابت ولی با مقادیر مختلف درخواست شدن پس دو تا نمونه مجزا توی دو تا مکان مجزا از حافظه ساخته میشن...حالا مثال بعدی رو با توجه به نکاتی که توی همه این جلسات گفتیم تحلیل کن.❓چرا ارور گرفتیم؟ (زیر x و y خط قرمز داریم.)چون که داریم از const استفاده میکنیم و موقع کامپایل وقتی const Point(x , y); این رو میبینه میخاد یه نمونه با این مقادیر ایجاد کنه. ولی در کمال ناباوری میبینه که x و y دو تا متغیر final هستن و final ها هم که تازه موقع run-time مقدار میگیرن پس مقدارشون موقع کامپایل مشخص نیست که بخواد با استفاده از اونها نمونه بسازه.پس نتیجه خیلی مهم این هست که برای ساخت نمونه های const تمام مقادیری که به constructor پاس داده میشن باید compile-time constant باشن.(نکته ای که میدونم توی فلاتر خیلی وقتا خیلی هاتون رو اذیت کرده و به دلیلش فکر نکردید... اگرم دلیلش رو میدونستید که ایولللل.)این سناریو رو اینجوری در نظر بگیرید که مثلن x و y دو تا مقداری هستن که موقع run-time مشخص میشن , مثلن مقادیری هستن که از سرور گرفته میشن یا از TextField خونده میشن.پس با وجود اینکه کلاسمون قابلیت این رو داره که از const constructor استفاده کنه ولی بعضی از مواقع نمیتونیم از این قابلیت استفاده کنیم و ناچاریم که از کلاسمون نمونه جدید (new) بسازیم.پس یه جمع بندی داشته باشیم:برای اینکه یه کلاس const constructor داشته باشه باید immutable باشه(همه instance field هاش final باشن.)همچنین مقدار  دهی اولیه به instance field ها یا باید با استفاده از کلمه کلیدی this انجام بشه و یا داخل initialize list.سازنده ای که قراره const بشه نباید body داشته باشه.(چون که body شامل کدها و عملیات مختلف هست و در زمان کامپایل قابل آنالیز نیست و کامپایلر دارت قابلیت آنالیز اون رو نداره.)برای ساخت یه نمونه const از یه کلاس که const constructor داره ,  باید تمام مقادیری که به constructor پاس داده میشن خودشون compile-time constant باشن.یک کلاس میتونه همزمان شامل constructor های const و غیر const باشه. ولی اگه حداقل یه constructor از نوع const داخل کلاس داشتیم , کلاس باید immutable باشه.??? مفهوم Widget داخل فلاتر یه مفهوم immutable هست پس همه ویجت هاتون رو immutable بسازید و به const constructor مجهزشون کنید و جاهایی که امکان داره (نه همه جا) نمونه های const ازشون بسازید.(این نکته مقدمه ای هست برای بحث های آینده)قسمت بعدی: استفاده در فلاتر.برای دریافت آموزش های بیشتر و شرکت در چالش های فلاتری, کانال فلاتری Flutter Challenge(چالش فلاتر) رو دنبال کن.</description>
                <category>Mohammad Taheri</category>
                <author>Mohammad Taheri</author>
                <pubDate>Sun, 19 Sep 2021 15:26:18 +0430</pubDate>
            </item>
                    <item>
                <title>Dart Const (const values)</title>
                <link>https://virgool.io/flutter-challenge/dart-const-const-values-lbxb84udqs3f</link>
                <description>Flutter Challenge(چالش فلاتر)قسمت قبلی : بررسی مفهوم const در کلاس (static const).?قبل از پرداختن به مفهوم const constructor ها , یکم در مورد const values  صحبت میکنیم تا درک const constructor ها هم واسمون راحتر بشه.باز هم میریم سراغ داکیومنت و چنتا جمله ای که جلسه اول با هم خوندیم رو مجددن مرور میکنیم.The const keyword isn’t just for declaring constant variables. You can also use it to create constant values, as well as to declare constructors that create constant values. Any variable can have a constant valueکلید واژه const فقط برای تعریف متغیر های ثابت نیست.شما میتونید از این کلید واژه برای ایجاد مقادیر ثابت (values) و همچنین سازنده هایی که مقادیر ثابت رو ایجاد میکنند استفاده کنید.(منظورش اینه فقط قبل اسم متغیر نمیاد بلکه میتونه قبل اسم سازنده یا قبل مقدار هم بیاد.)var foo = const [];
final bar = const [];
const baz = []; // Equivalent to `const []`You can’t change the value of a const variable:baz = [42]; // Error: Constant variables can&#039;t be assigned a value.You can change the value of a non-final, non-const variable, even if it used to have a const value:foo = [1, 2, 3]; // Was const []تا اینجا هر چی با const کار کرده بودیم این کلید رو قبل اسم متغیر میوردیم ولی توی این مثال ها میبینیم که بعضی جاها قبل مقدار (value) اومده یا حتا قبل اسم متغیر final اومده و قبل مقدارش const.خب پس ببینیم چنتا حالت مختلف داریم و هر کدوم رو تحلیل کنیم.کلید final فقط میتونه قبل اسم متغیر بیاد و قبل مقدارش نمیتونه بیاد.کلید const هم میتونه قبل اسم متغیر بیاد و هم قبل مقدارش.پس :حالت اول : نه قبل اسم متغیر  و نه قبل مقدارش هیچی نیاد.var names = [&#039;Mohammad&#039; , &#039;Arash&#039;];حالت دوم : قبل اسم متغیر final بیاد و قبل مقدارش هیچی نیاد.final names = [&#039;Mohammad&#039; , &#039;Arash&#039;];حالت سوم : قبل اسم متغیر final بیاد و قبل مقدارش const بیاد .final names = const  [&#039;Mohammad&#039; , &#039;Arash&#039;];حالت چهارم: قبل اسم متغیر const بیاد و قبل مقدارش هیچی نیاد یا قبل هر دو const بیاد (این دو حالت معادل هم هستن , یعنی وقتی قبل اسم متغیر const میاد به صورت ضمنی انگار که قبل مقدارش هم const گذاشتی)const names = const  [&#039;Mohammad&#039; , &#039;Arash&#039;];
//or
const names =  [&#039;Mohammad&#039; , &#039;Arash&#039;];حالت پنجم: قبل اسم متغیر هیچی نیاد ولی قبل مقدارش const بیاد.var names = const  [&#039;Mohammad&#039; , &#039;Arash&#039;];حالا به جای اینکه بهتون بگم دونه دونه توی این حالات چه بلایی سر کدمون میاد تحلیل کردن رو یادتون میدم و بعدش که خودتون فکر کردید و تحلیل کردید با هم همه حالتها رو تحلیل میکنیم.???✅قبل از این گفتیم که اگه یه متغیر رو final کنیم اون متغیر فقط و فقط یکبار میتونه مقدار بگیره و ثابت هست ولی این مقدار گرفتن توی run-time و وقتی که اجرای کد به اون نقطه رسید انجام میشه.✅همچنین گفتیم که اگه یه متغیری رو const کنیم اون هم فقط و فقط یکبار میتونه مقدار بگیره و ثابت هست با این تفاوت که اینبار مفدار گرفتن توی compile-time انجام میشه و این متغیر ها یا بهتره بگیم ثابتها قبل رسیدن کد به مرحله اجرا مقدارشون رو گرفتن و حاضر و اماده هستن.✅الان هم که گفتیم کلید const علاوه بر قبل اسم متغیر قبل مقدار یا value هم میتونه بیاد.✅قبلن هم گفتیم که اگه قبل یه چیزی const بیاد اون تکه از کد توی زمان کامپایل تجزیه و تحلیل میشه و مقدارش ثبت میشه.✅همچنین گفته بودیم که وقتی که قبل اسم یه متغیر const میاد کل عبارت یعنی طرف چپ و راست توی زمان کامپایل رصد میشن و الان هم توی حالت چهارم گفتیم که وقتی قبل اسم متغیر const میاد انگار قبل مقدارش هم const گذاشتی , پس به همین علته که وقتی قبل اسم متغیر const میاد کل عبارت توی زمان کامپایل رصد میشه.❓گفتیم اگه قبل اسم متغیر const بیاد اون متغیر توی زمان کامپایل مقدارشو میگیره. خب حالا اگه قبل مقدار بیاد چی میشه؟??در این حالت توی زمان کامپایل اون مقدار به عنوان یک مقدار یا value ثابت ثبت میشه و دیگه هر جایی از کد که از اون مقدار با پیشوند const استفاده کردی همون مقدار ثبت شده رو بهت میده.مثال میزنیم:دو تا آرایه دقیقن مثل هم تعریف کردیم و قبل اسم متعیر ها و مقادیر هیچی نیومده. و بعد اونها رو با هم مقایسه کردیم (==). میبینیم که نتیجه false شده.❓چرا ؟‌??چون که هر بار که از [&#x27;mohammad&#x27; , &#x27;Arash&#x27;] استفاده میکنم . یعنی مینویسم : var namesN = [&#039;mohammad&#039; , &#039;Arash&#039;];یه ارایه جدید توی حافظه برام ایجاد میکنه و وقتی که با == دو تا آرایه رو مقایسه میکنم بررسی میکنه که آیا این آرایه ها توی یک مکان از حافظه قرار دارن یا نه . و چون که توی مکان های مختلف از حافظه ایجاد شدن نتیجه رو false برمیگردونه.حالا یه مثال دیگه :‌ اینبار قبل مقدار ها const گذاشتم و همون طور که میبینید نتیجه true بشد.❓چرا؟??چون که وقتی کامپایلر برای بار اول میرسه به const [&#x27;mohammad&#x27; , &#x27;Arash&#x27;] این مقدار رو به عنوان یک مقدار ثابت ثبت میکنه و بعد از اون هر بار و هر کجا که به یک چنین عبارتی رسید دقیقن همون مقدار قبلی رو که واسش ثبت کرده دوباره استفاده میکنه.یعنی وقتی کامپایلر رسید به   var names = const [&#039;mohammad&#039; , &#039;Arash&#039;];یه مقدار ثابت برای ارایه مورد نظر ثبت میکنه.حالا اینجا خود متغیر const نیست و قراره که توی run-time مقدار بگیره. توی run-time وقتی رسید به این خط از کد میگه من قبلن و زمان کامپایل برای این ارایه یه مقدار ثابت ثبت کردم و همون مقدار رو میریزم توی متغیر names . و بعدش هم وقتی میرسه به خط بعدی همین تحلیل رو میکنه و دوباره همون آرایه ثابت ثبت شده توی زمان کامپایل رو توی متغیر names2 هم میریزه و این میشه که هر دو متغیر دقیقن به یک مکان از حافظه اشاره میکنن و نتیجه مقایسه == برابر با true میشه.مثال بعدی :دو تا متغیر از نوع String تعریف کردم و هیچکدوم هم const نیستن ولی نتیجه مقایسه true شد!!!❓این رو چطور تحلیل میکنید؟قبلن و توی قسمت اول گفتیم که همه string literal ها , .... compile-time constants هستن.❓یعنی چی ؟یعنی وقتی میرسه به خط اول میبینه یه String تعریف شده و چون که String ها به صورت ضمنی const هستن یه مقدار (value) ثابت (&#x27;Mohammad&#x27;) توی حافظه ایجاد میکنه و بعد از اون هر جای کد که نیاز به این مقدار باشه از همون مقدار اولیه ثبت شده توی حافظه استفاده میکنه.پس وقتی که توی run-time به این کد ها رسید و خواست که به متغیر های name و name2 مقدار بده همون مقدار ثابت &#x27;Mohammad&#x27; که زمان کامپایل ثبت شده بود رو میریزه داخلشون. پس این دو هم با هم برابر میشن.اطلاعات عمومی: توی زبان های برنامه نویسی دیگه مثل JAVA به دیتا تایپ هایی مثل int , double , boolean , ... میگن Primitive Data Types.در واقع اونجا دو نوع type داریم.Primitive Data Type.Reference Data Type.که بلایی که سر Primitive ها میاد شبیه همین بلایی هست که اینجا سر String اومد که از توضیح بیشتر میگذریم. (البته توی JAVA تایپ String از نوع Primitive نیست ولی بلایی شبیه Primitive ها سرش میاد...بگذریم.)این هم یه مثال دیگه:که الان میفهمیم با توجه به مفهوم compile-time constants چرا این مقایسه مقدار true رو میده.خب حالا وقتشه که بریم سر تحلیل حالات مختلفی که با هم مرور کردیم. (فقط قبلش یادتون نره خودتون فکر کنید...)حالت اول : نه قبل اسم متغیر  و نه قبل مقدارش هیچی نیاد.var names = [&#039;Mohammad&#039; , &#039;Arash&#039;];خب توی این حالت که هیچ اتفاق خاصی نمیوفته. توی زمان کامپایل هیچ مقداری ثبت نمیشه و توی run-time یه ارایه جدید ایجاد میشه و ریخته میشه توی متغیر names .میبینید که هر بلایی که بخوایم میتونیم سر names بیاریم.چرا هر چی من میگم گیر نمیدید!!! من گفتم که توی این حالت در زمان کامپایل هیچی ثبت نمیشه!!! نباید هیچی بگید؟؟؟???❓پس این &#x27;Mohammad&#x27; و &#x27;Arash&#x27;  چی هستن؟??درسته که خود آرایه یا متغیر از نوع const نیستن و زمان کامپایل ثبت نمیشن ولی این مقادیری String ای که باید ثبت بشن.???خب دیگه خودتون استاد شدین و تحلیل این رو میسپارم به خودتون...???حالت دوم : قبل اسم متغیر final بیاد و قبل مقدارش هیچی نیاد.final names = [&#039;Mohammad&#039; , &#039;Arash&#039;];❓توی این حالت چه اتفاقی میوفته؟ خب واضحه که چون متغیر final هست فقط یکبار میتونه مقدار بگیره و دیگه نمیتونیم تغییرش بدیم و این ثبت مقدار هم توی run-time انجام میشه.میبینید که اگه بخوایم دوباره بهش مقدار بدیم ارور میده.سوال...❓آیا در این حالت میتونیم خود لیست رو ویرایش کنیم ؟‌ یعنی یه ایتم بهش اضافه یا کم کنیم؟ یا ایتم هاش رو ویرایش کنیم؟میبینیم که شد!!!❓چرا؟ مگه متغیر رو final تعریف نکردیم ؟ پس چرا میتونیم لیست رو ویرایش کنیم؟?????جواب: خود متغیر final هست و پس از یکبار مقدار دهی نمیتونیم دیگه تغییرش بدیم و اون رو برابر با یه مقدار دیگه قرار بدیم ولی خود مقدار یعنی [&#x27;Mohammad&#x27; , &#x27;Arash&#x27;] یه مقدار ثابت نیست و چون که یه مقدار ثابت نیست و توی زمان کامپایل هم توی حافظه ثبت نشده امکان ویرایشش هست.حالت سوم : قبل اسم متغیر final بیاد و قبل مقدارش const بیاد .final names = const  [&#039;Mohammad&#039; , &#039;Arash&#039;];توی این حالت متغیرمون final هست و توی run-time مقدار دهی میشه و بعد از مقدار دهی امکان تغییرش نیست.ولی مقدارش (value) از نوع const هست  داره توی compile-time رصد میشه و ثبت میشه و وقتی که توی run-time کدمون میرسه به این نقطه مقداری که زمان کامپایل برای این value ثبت شده بود داخل متغیر قرار میگیره.??پس اینجا دو تا اتفاق مهم میوفته...اول اینکه چون متغیر final هست دیگه نمیتونیم اون رو برابر با یه مقدار جدید قرار بدیم.و دوم اینکه چون مقدارش const هست امکان ویرایش (اضافه و کم کردن یا ویرایش ایتم ها ) وجود نداره.به ارورهایی سمت چپ توجه کنید.❓چرا این اتفاق افتاد؟??چون که ما به کامپایلر گفتیم که یه لیست const با این مقادیر داریم . کامپایلر هم دقیقن اون رو ایجاد میکنه و هر جا لازم داشتیم همون رو بهمون میده و امکان ویرایش رو بهمون نمیده چون که اگه بتونیم ویرایش کنیم دیگ از مفهوم const بودن خارج میشه (این رو به عنوان مقدمه ای برای مبحث const constructor داشته باشین که اونجا خیلی مفصل راجبش صحبت کنیم.)حالت چهارم: قبل اسم متغیر const بیاد و قبل مقدارش هیچی نیاد یا قبل هر دو const بیاد (این دو حالت معادل هم هستن , یعنی وقتی قبل اسم متغیر const میاد به صورت ضمنی انگار که قبل مقدارش هم const گذاشتی)const names = const  [&#039;Mohammad&#039; , &#039;Arash&#039;]; 
//or 
const names =  [&#039;Mohammad&#039; , &#039;Arash&#039;];خب تحلیل این حالت هم خیلی باید واستون راحت باشه .هم متغیر از نوع const هست و توی compile-time مقدار میگیره و هم مقدارش const هست و توی compile-time ثبت میشه.پس نه میشه مقدار متغیر رو تغییر داد و نه میشه ویرایشش کرد.حالا مثال زیر رو با توجه به توضیحات این جلسه و جلسات قبل خودت تحلیل کن...و حالا این یکی ...❓چرا اولی درسته و دومی غلط؟حالت پنجم: قبل اسم متغیر هیچی نیاد ولی قبل مقدارش const بیاد.var names = const  [&#039;Mohammad&#039; , &#039;Arash&#039;];❓توی این حالت چه اتفاقی میوفته؟??خود متغیر توی run-time مقدار دهی میشه ولی مقدارش const هست و توی compile-time تکلیفش مشخص میشه.پس میتونیم مقدار متغیر رو برابر با یه متغیر دیگه قرار بدیم:ولی نمیتونیم ویرایشش کنیم:ولی اگه مقدارش رو برابر با یه مقدار غیر const گذاشتیم امکان ویرایش هم هست:???امیدوارم که از این جلسه لذت برده باشید.???قسمت بعدی : بررسی مفهوم const در کلاس (const constructor).برای دریافت آموزش های بیشتر و شرکت در چالش های فلاتری, کانال فلاتری Flutter Challenge(چالش فلاتر)رو دنبال کن.</description>
                <category>Mohammad Taheri</category>
                <author>Mohammad Taheri</author>
                <pubDate>Sat, 18 Sep 2021 22:23:01 +0430</pubDate>
            </item>
                    <item>
                <title>Dart Const (classes - static const)</title>
                <link>https://virgool.io/flutter-challenge/dartconstclassesstaticconst-yrs7sm2piaw1</link>
                <description>Flutter Challenge(چالش فلاتر)قسمت قبلی : بررسی مفاهیم اولیه و معرفی const variables.? توی قسمت قبلی در مورد const variables توضیح دادیم و فهمیدیم که در زمان کامپایل چه بلایی سر این نوع متغیر ها میاد.? توی این قسمت که اولین قسمت از بررسی مفهوم const در کلاس ها هست به بررسی static const میپردازیم.خب یکی از جملات مهمی رو که توی مقاله قبلی از داکیومنت با هم خوندیم رو دوباره مرور میکنیم.If the const variable is at the class level, mark it static const.اگر میخواهید یک متغیر const در سطح کلاس داشته باشید اون رو static کنید (static const ).???خب وقتشه که نفوذ کنیم به اعماق این جمله و زیر و بمشو بریزیم بیرون.???قبل از این وقتی که میخواستیم خارج از سطح کلاس یک متغیر رو const کنیم خیلی راحت این کار رو انجام میدادیم , ولی طبق جمله ای که اینجا گفته و تجربه ای که حتمن دارید وقتی بخوایم داخل یک کلاس یه متغیر رو const کنیم به ارور میخوریم و بهمون میگه که حتمن باید متغیر مورد نظر رو static هم کنی(static const).پس طبق توضیحاتی که دادیم کد بالا غلطه و اگه امتحان کنید بهتون میگه که یا متغیر رو final کنید و یا static.یعنی به شکل بالا.❓تا حالا به این فکر کردید که که چرا؟❓چرا اگه در سطح یه کلاس بخوایم یه const تعریف کنیم حتمن باید static باشه؟❓یا اینکه فقط حفظ کردین و استفاده کردین؟⛔️⛔️⛔️ اگه دلیل این موضوع واست مهم نیست خب میتونی بیخیال ادامه مقاله بشی ولی اگه دلیلش واست مهمه بزن بریم.برای جواب به این سوال اول یه یادآوری از قسمت قبلی میکنیم, توی قسمت قبلی گفتیم که وقتی که یه متغیر رو (خارج از سطح کلاس ) const تعریف میکنیم اون متغیر در زمان کامپایل توسط کامپایلر رصد میشه و مقدار میگیره.پس برای اینکه به جواب سوال بالا برسیم اول باید ببینیم که چه قسمت هایی از یک کلاس در زمان کامپایل توسط کامپایلر رصد میشن(یا بهتره بگیم قابلیت این رو دارن که توسط کامپایلر رصد بشن.)قبل از اون ببینیم یه کلاس از چه اجزایی تشکیل شده.به صورت ساده هر کلاس شامل یک سری property و یک سری method هست که روی اون property ها عمل میکنن.مثلن اینجا name و age همون property ها هستن و printName هم متد هستش.(از اینجا به بعد به property میگیم instance field - دلیل این نام گذاری هم اینجوری در نظر بگیرید که فقط در صورتی به property های یه کلاس دسترسی داریم که از اون کلاس نمونه یا instance بسازیم.)برای دسترسی به این instance field و method ها باید از کلاسمون نمونه بسازیم.User user = User(&#039;Arash&#039; , 12);user.printName();همچنین میتونیم داخل کلاس فیلد هایی به صورت static داشته باشیم که این فیلد ها بدون ساختن نمونه از کلاس قابل دسترسی هستن. یعنی ربطی به نمونه های ساخته شده از کلاس ندارن و در سطح خود کلاس تعریف و قابل استفاده هستن نه نمونه ها یا اشیای ساخته شده از کلاس.User.CLASS_NAME;خب حالا ببینیم که کدوم یک از این قسمت ها توسط چشمان کامپایلر قابل رصد شدن هست.گفتیم که instance field ها و method های یه کلاس بعد از اینکه از اون کلاس نمونه میسازیم قابل استفاده هستن و در واقع بعد از نمونه سازی مقدار میگیرن و وارد میدون میشن و قبل نمونه سازی نمیتونیم ازشون استفاده کنیم.⁉️نمونه سازی چه زمانی انجام میشه؟ compile-time یا run-time؟آفرین , توی run-time . پس این قسمت ها یعنی instance field ها و متد ها توسط کامپایلر رصد نمیشن(یا قابلیت این رو ندارن که در زمان کامپایل مقدار بگیرن چون که توی run-time نمونه ساخته میشه و این ها مقدار میگیرن) (منظور از رصد نشدن این نیست که کلن هیچ کاری روشون انجام نده , منظورمون اینجا اینه که مثل const ها باهاشون برخورد نمیکنه که همون لحظه کامپایل تجزیه و تحلیلشون کنه و بهشون مقدار بده.)اگه هنوز توجیه نشدی که چرا نمونه سازی توی run-time انجام میشه!!! خب وقتی مثلن مینویسیم:User user = new User(&#039;Arash&#039; , 7);این عملیات new کردن و ساختن نمونه توی run-time و وقتی که اجرای کد به اون قسمت رسید انجام میشه. و ممکنه توی حالت اجرا , کد ما چند بار بره و برگرده و دوباره برسه به این نقطه و هر بار که رسید به این نقطه دوباره یه نمونه جدید ساخته میشه.مثلن این کد توی صفحه دوم از اپ فلاترمون هست و ما هی صفحه رو push میکنیم و این کد اجرا میشه و دوباره pop میکنیم. هر بار که این کد اجرا میشه یه نمونه جدید ساخته میشه.پس فهمیدید چرا توی run-time اتفاق میوفته.پس وقتی که نمونه سازی توی run-time انجام میشه و از طرفی هم instance field ها در سطح نمونه های ساخته شده از یک کلاس قابل دسترسی هستن پس این instance field ها در زمان کامپایل قابل مقدار دهی نیستن.???نوع دیگه ای از نمونه سازی توی دارت داریم که به جای new از const استفاده میکنیم که باعث میشه قضیه یکم فرق کنه که اون رو توی مقاله بعدی یاد میگیریم.⁉️فیلد هایی که به صورت static تعریف شدن چی؟ برای استفاده از اون ها نیازی به نمونه سازی نیست و در سطح کلاس قابل استفاده هستن.پس الان میتونی به اون سوال جواب بدی ؟ چرا اگه بخوایم یه فیلد رو داخل کلاس const کنیم حتمن باید static هم بشه؟فکر...فکر...فکر..جواب: همون طور که قبلن گفتیم وقتی یه چیزی const هست همون لحظه کامپایل توسط کامپایلر تجزیه میشه , خب instance filed های یک کلاس هم که بعد از نمونه سازی و در run-time مقدار میگیرن و قابلیت این رو ندارن که در زمان کامپایل مقدار بگیرن , از طرفی توی کلاس ها دو نوع فیلد که بیشتر نداریم (یا instance filed هستن و یا static)  , پس اگه یه فیلدی بخواد const باشه چاره ای نداره جز اینکه static هم باشه که زمان کامپایل مقدار بگیره و از همون اول اول و نه وقتی که از کلاس نمونه میسازیم قابل استفاده باشه.پس یه جمع بندی داشته باشیم.هر کلاس تشکیل شده از یک سری property یا instance filed و method هایی که رو اون ها عمل میکنند . هم چنین هر کلاس میتونه فیلد هایی از نوع static داشته باشه.توی هر کلاس فقط و فقط دو نوع فیلد میتونیم داشته باشیم. یا instance filed و یا static.نوع اول یعنی instance filed ها در سطح نمونه های ساخته شده از کلاس قابل دسترسی هستن و تا از کلاس نمونه نسازیم نمیتونیم بهشون دسترسی داشته باشیم. پس در زمان کامپایل قابل رصد و مقدار دهی نیستن.(چون نمونه سازی یا new کردن در run-time انجام میشه.)نوع دوم یعنی static در سطح خود کلاس تعریف و قابل دسترسیه و ربطی به نمونه های ساخته شده از کلاس نداره. پس این قابلیت رو دارن که در زمان کامپایل قابل رصد و مقدار دهی باشن.(توجه کنید که فقط قابلیت این موضوع رو دارن و باید حتمن با const ترکیب بشن که این قابلیت بالقوه به بالفعل تبدیل بشه)وقتی یه متغیری رو const میکنیم در زمان کامپایل رصد میشه و مقدار میگیره.از بین دو نوع فیلد قابل تعریف در کلاس ها , فقط static ها رو که قابلیت رصد شدن در زمان کامپایل دارن رو میشه const کرد و instance filed ها قابلیت const شدن ندارن.??? پس اگه یه فیلدی در سطج کلاس static const باشه در زمان کامپایل مقدار میگیره.???اگه یه فیلدی در سطح کلاس static باشه و const نباشه(static خالی ) در زمان کامپایل مقدار نمیگیره و همون  run-time مقدار میگیره.قسمت بعدی : const values.برای دریافت آموزش های بیشتر و شرکت در چالش های فلاتری, کانال فلاتری Flutter Challenge(چالش فلاتر) رو دنبال کن.</description>
                <category>Mohammad Taheri</category>
                <author>Mohammad Taheri</author>
                <pubDate>Sat, 18 Sep 2021 02:26:03 +0430</pubDate>
            </item>
                    <item>
                <title>Dart Const (const variables)</title>
                <link>https://virgool.io/flutter-challenge/dartconstvariables-scuzpprkfzf7</link>
                <description>Flutter Challenge(چالش فلاتر)توی این قسمت وارد دنیای const میشیم و توضیحات اولیه در مورد نحوه ی برخورد کامپایلر دارت با این اعجوبه میدیم و در نهایت هم const variables رو معرفی میکینم. از اینجا میتونی بخش معرفی این مجموعه مقاله رو مطالعه کنی.ابتدا بخشی از توضیحاتی رو که توی بخش معرفی از داکیومنت اوردیم رو با هم مرور میکنیم.If you never intend to change a variable, use final or const, either instead of var or in addition to a type. A final variable can be set only once; a const variable is a compile-time constant. (Const variables are implicitly final.) A final top-level or class variable is initialized the first time it’s used.اگر هرگز قصد ندارید که یک متغیر رو تغییر بدید به جای استفاده از کلمه کلیدی var از final یا const برای تعریف اون استفاده کنید(یا علاوه بر مشخص کردن نوع متغیر از این کلید واژه ها استفاده کنید).متغیر هایی که به صورت final تعریف شده اند فقط یک بار میتوانند تنظیم شوند(مقدار بگیرند) و قابل تغییر نیستند. متغیرهایی که به صورت const تعریف شده اند ثابت های زمان کامپایل هستند.(توی پرانتز هم میگه که متغیرهای const به صورت ضمنی final هستند.)بعد از این تعریف چندتا مثال میاره...final name = &#x27;Bob&#x27;; // Without a type annotationfinal String nickname = &#x27;Bobby&#x27;;name = &#x27;Alice&#x27;; // Error: a final variable can only be set once.یک متغیر رو final گرفته و بعد خواسته مقدارش رو تغییر بده که به ارور خورده.در ادامه توضیحاتش این رو اضافه میکنه:Use const for variables that you want to be compile-time constants. Where you declare the variable, set the value to a compile-time constant such as a number or string literal, a const variable, or the result of an arithmetic operation on constant numbers:از const برای متغیرهایی استفاده کنید که می خواهید ثابت زمان کامپایل باشند.وقتی یک متغیر const تعریف میکنید و میخواهید به اون مقدار بدید مقدارش رو برابر با یک ثابت زمان کامپایل (compile-time constant) قرار بدید مانند یک رشته یا عدد (string or number literal) یا .... بعدش هم این مثال ها رو اورده :const bar = 1000000; // Unit of pressure (dynes/cm2)
const double atm = 1.01325 * bar; // Standard atmosphere?توی اولین پاراگراف دوتا کلید واژه final و const رو معرفی کرده و گفته از اینها برای تعریف متغیرهایی استفاده کن که قراره ثابت باشن و تغییر نکنن. مخاطب وقتی این رو میخونه میگه آیا توسعه دهندگان دارت دیوونه بودن؟??? چرا دو تا کلید واژه برای یک هدف؟????ولی خب در ادامه از یک واژه کلیدی و مهم رونمایی میکنه به اسم Compile-time.بله میگه const در واقع یک compile-time constant یا ثابت زمان کامپایل هست. پس در مقابلش final یک run-time constant یا ثابت زمان اجرا هست.? پس دو تا سوال توی ذهنمون شکل میگیره که باید بهش جواب بدیم!!!What is compile-time?What is run-time?شما ادیتور رو باز میکیند و شرو میکنید به کد نوشتن بعد از اون که کدتون تکمیل شد یه build از اپتون یا کدتون میگیرید و بعد خروجی رو توی گوشی یا هر دیوایس دیگه اجرا میکنید.موقعی که دارید از کدتون build میگیرید کدهای شما یه پروسه ای رو طی میکنند که به اون میگن کامپایل شدن (که وارد جزییاتش نمیشیم) . پس این زمان ینی زمان build گرفتن و ساختن خروجی از کدها برای اجرا روی دیوایس میشه زمان کامپایل یا compile-time.خیلی ساده بخوایم بگیم توی این زمان کامپایلر دارت میاد شرو میکنه به انالیز و تجیزه کد ها و تبدیل اون ها به کد ماشین و ... که کاری نداریم(فقط بدونیم این تایم compile-time هست کافیه).و بعد از اون وقتی که خروجی نهایی رو توی دیوایس اجرا میکنید اون زمان میشه run-time.پس یه نتیجه ای میگیریم اونم این که compile-time یا زمان کامپایل یه شروعی داره و یک پایانی(شروعش همون لحظه ای هست که اقدام میکنیم برای build گرفتن و پایانش هم لحظه آماده شدن خروجی هست) ولی run-time شروعش از لحظه اجرای اپ هست و پایانش لحظه ای هست که اپ رو میبندیم.(خب اینم که یه شروع و پایان داشت پس ولیش کجا بود / عجب جمله چرتی گفتم).نکته اینجاست که یه اپ یکبار کامپایل میشه ولی بارها و بارها میره توی run-time . ینی به ازای یک compile چند بار run-time رو تجربه میکنه.و نکته بعدی اینکه وقتی کدهامون کامپایل میشن تمام کدها تجزیه و تحلیل میشن و از زیر تیغ کامپایلر دارت میگذرن ولی موقع اجرا ممکنه بعضی از کدهامون اصلن اجرا نشن.مثلن یه اپ فلاتر داری که 4 تا صفحه داره که روی هم navigate میشن. وفتی کامپایل میشه همه این صفحات و کدها از زیر تیغ کامپایلر میگذرن ولی موقع اجرا ممکنه شما صفحه اول رو باز کنی و بعد کلن اپ رو ببندی بری پی کارت پس کدهای صفحات دیگ اصلن به حالت اجرایی در نمیان.حالا که معنی compile-time و run-time رو فهمیدیم برگردیم به تعریف.میگه const ها ثابت های زمان کامپایل هستن و final ها ثابت های زمان اجرا.در اینکه هر دو ثابتن و بعد از یکبار تعریف دیگ قابل تغییر نیستن که مشکلی نیست.??? کد ساده بالا رو ببینید و با توجه به توضیحاتی که تا اینجا گفتیم فکر کنید و بگید تفاوت این دو تا چیه؟اول فکر کنید بعد جواب رو بخونید.اولی final تعریف شده پس یک ثابت هست و غیر قابل تغییر و دومی هم const و اون هم ثابت هست.???تفاوت اینجا هست که کامپایلر دارت توجه ویژه ای به متغیرهایی داره که به صورت const تعریف شده اند.و متغیری  که const هست زمان کامپایل توسط کامپایلر تجزیه و تحلیل میشه و توسط چشمان تیزبین کامپایلر مورد رصد قرار میگیره و همون موقع یعنی زمان کامپایل مقدار میگیره,  ولی اونی که final هست توی زمان کامپایل مقدار نمیگیره و توی run-time وقتی اجرای کد به اون جا رسید و اون کد اجرایی شد مقدار میگیره.پس وقتی که یه متغیری const تعریف شد همون زمان کامپایل تکلیفش مشخص میشه (ینی کامپایلر کامل اون رو ارزیابی میکنه و مقدارش هم ثبت میشه) ولی وقتی که متغیر رو final تعریف میکنیم هنگامی که زمان اجرای کد , اجرای کدمون به اون قسمت رسید اون متغیر مقدار میگیره.❓خب سوال پیش میاد که این تفاوت حالا به چه دردمون میخوره؟ چه دردی رو ازمون دوا میکنه؟این سوال توی ذهنتون باشه بعدن بهش جواب میدیم.حالا بریم سراغ جمله کلیدی دیگه از تعاریف:Where you declare the variable, set the value to a compile-time constant such as a number or string literal, a const variable, or the result of an arithmetic operation on constant numbers:وقتی یا جایی که یک متغیر const تعریف میکنید و میخواهید به اون مقدار بدید مقدارش رو برابر با یک ثابت زمان کامپایل (compile-time constant) قرار بدید مانند یک رشته یا عدد (string or number literal) یا .... این چی میگه؟این میگه که وقتی که یک متغیر رو const تعریف کردیconst constVar = ....اون مقداری که جای ... و به عنوان مقدار (value) این متغیر قرار میدی مهمه و نمیتونی هر چیزی دلت خواست بذاری.❓پس چه مقادیری میتونیم بهش بدیم؟خود مقداره هم باید یه compile-time constant  یا ثابت زمان کامپایل باشه و این خاصیت رو داشته باشه که در زمان کامپایل توسط کامپایلر رصد بشه.خب چرا؟وقتی که یک متغیر رو مثل کد بالا به صورت const تعریف میکنیم , توی زمان کامپایل کل کد یعنی هم طرف چپ تساوی و هم طرف راست توسط کامپایلر رصد و تجزیه میشه. پس طرف راست (value) هم که قراره بریزمیش توی متغیرمون باید یه خاصیتی داشته باشه ک در زمان کامپایل توسط کامپایلر قابل رصد باشه , پس اونم باید یک compile-time constant باشه.حالا به دو تا مثال توجه کنید:کد بالا غلطه و ارور دریافت میکنید.چون که متغیر final که زمان اجرا  مقدار میگیره رو  ریختیم توی یه متغیر const که قراره زمان کامپایل مقدار بگیره.(زمان اجرا بعد از زمان کامپایل هست پس کد بالا غلطه)ولی برعکسش:کاملن درسته.چون که داریم متغیری رو که زمان کامپایل مقدار میگیره رو میریزیم داخل متغیری که زمان اجرا قراره مقدار دهی بشه(زمان کامپایل بر زمان اجرا مقدم تره پس کد بالا درسته).یه نتیجه دیگه میشه از این گفته هامون تا اینجا گرفت. اگه گفتید.تمام string literal ها و numeric literal ها و ...  مثل hello , 2 , true  , ... از نوع compile-time constant هستن.چرا؟واضحه , تمام کد های زیر درسته و برامون مثل بدیهیات هست:از طرفی هم گفتیم چون که یک متغیر const زمان کامپایل تجزیه و مقداردهی میشه پس طرف راست تساوی هم باید زمان کامپایل قابل ارزیابی باشه.پس hello world!!! , 3.14 , false هز سه compile-time constants هستن.پس تا اینجا یه جمع بندی از نکاتی که گفتیم داشته باشیم. متغیرهایی که به صورت const تعریف میشن compile-time constant هستن و final ها run-time هستن.منظور از compile-time زمانی هستش که کدهامون داره build میشه و منظور از run-time زمانی هست که کد ها داره توی دیوایس اجرا میشه.وقتی که یه متغیری const تعریف میشه کل معادله (طرف چپ و راست ) در زمان کامپایل توسط چشمان تیزبین کامپایلر رصد میشه.وقتی یک متغیری رو به صورت const تعریف میکنیم , مقدار یا value ای هم که قراره داخلش بریزیم باید یک compile-time constant باشه.تمام string literal ها , numeric literal ها , ... compile-time constants هستن و زمان کامپایل توسط کامپایلر رصد میشن. قسمت بعدی : بررسی مفهوم const در کلاس (static const).برای دریافت آموزش های بیشتر و شرکت در چالش های فلاتری, کانال فلاتری Flutter Challenge(چالش فلاتر)رو دنبال کن.</description>
                <category>Mohammad Taheri</category>
                <author>Mohammad Taheri</author>
                <pubDate>Thu, 16 Sep 2021 21:13:18 +0430</pubDate>
            </item>
                    <item>
                <title>Git dependencies in Flutter pubspec</title>
                <link>https://virgool.io/flutter-challenge/git-dependencies-in-flutter-pubspec-ppldypbmwns2</link>
                <description>سلام به فلاتری های عزیز ???حتمن همتون با فایل pubspec.yaml و نحوه ی استفاده از پکیج های pub.dev آشنایی دارین.توی این مینی آموزش میخوایم نحوه ی استفاده از یه Git Repository رو با هم یاد بگیریم.اول نحوه ی اضافه کردن یه Public Git Repository از github رو با هم بررسی میکنیم.و بعد هم استفاده یه از Private Git Repository از gitlab رو یاد میگیریم.فک کنم همه با روش معمولی اضافه کردن یه پکیج به پروزه فلاتری آشنایی دارین ولی با هم یه مرور میکنیم.مثلن اگه بخوایم پکیج flutter_bloc رو به پروژم اضافه کنیم.میبینیم که flutter_bloc: ^7.2.0  رو به قسمت dependencies اضافه کردیم. فعلن با علامت ^ که قبل ورژن اومده کاری نداریم و توی مقاله های دیگه راجبش صحبت میکنیم.حالا همین پکیج BLoC رو از طریق repository گیت هاب به پروژمون اضافه میکنیم.وقتی وارد repository گیت هاب این پکیج میشیم یه پروژه با اسم bloc میبینیم ک زیر مجموعش پکیج های مختلف مرتبط با اون قرار گرفته. آدرس گیت هاب پروژه اصلی (bloc) رو از اینجا میتونید دنبال کنید.وقتی وارد این ادرس میشیم قسمت های زیر رو میبینیم.وارد packages میشیم.و توی پروژه هایی که در این دایرکتوری وجود داره flutter_bloc رو انتخاب میکنیم.حالا بریم سراغ فایل pubspec و اضافه کردن این پکیج از طریق repository گیت هاب.همون طور که میبینید اول اسم پکیج رو نوشتم و بعدش زیرش مشخص کردم که میخوام از گیت استفاده کنم و  در آخر هم سه تا پارامتر مشخص کردیم.urlتوی این قسمت باید ادرس repository گیت هاب پروژه رو بدیم.گفتیم که پروژه اصلی با نام bloc ساخته شده و بعدش زیر مجموعش پکیج های مربوطه قرار گرفتن. پس به مسیر پروژه اصلی میریم.و با کلیک روی دکمه سبز رنگ (بالا سمت راست ) آدرسی رو که  داده رو کپی میکنیم.و همین ادرس رو توی قسمت url قرار میدیم.refتوی این قسمت میتونیم اسم branch مورد نظر یا ای دی commit مورد نظر رو قرار بدیم.من روی master گذاشتم.pathتوی این قسمت هم path پروژه مورد نظر خودمون رو میگذاریم. ما flutter_bloc رو میخاستیم.? در صورت خالی بودن ref از branch اصلی استفاده میکنه.?در صورت خالی بودن path از url برای clone کردن استفاده میکنه.???نکته مهمی که هست ادرسی که میدیم حتمن باید توی دایرکتوری اصلیش فایل pubspec وجود داشته باشه. مثلن اینجا آدرسی که ما در  نهایت داریم استفاده میکنیم https://github.com/felangel/bloc.git + packages/flutter_blocهست و توی دایرکتوری اصلی این آدرس حتمن باید فایل pubspec وجود داشته باشه (درواقع چیزی که داریم اضافه میکنیم خودش یه پروژه یا پکیج فلاتری باشه).خب تا اینجا نحوه اضافه کردن یه پکیج از طریق public git repository رو دیدیم. حالا بریم سراغ private repository ها و برای این یک مثال از gitlab میزنیم.همه مراحل دقیقن مثل public git repository هست فقط برای استفاده از private repository ها نیاز به یه username  و password داریم.در این حالت فقط فرمت url تغییر میکنه و به شکل زیر میشه.میبینید url به شکل زیر هست .https://&lt;deploy_token_name&gt;&lt;deploy_token_password&gt;@gitlab.com/my_user_name/package1.gitینی https://  + &lt;deploy_token_name&gt;  + &lt;deploy_token_password&gt;  + @  + gitlab project address.پس همه چیز مثل قبل هست و فقط دو تا پارامتر &lt;deploy_token_name&gt;  و &lt;deploy_token_password&gt; رو باید مقدار دهی کنیم.پس باید وارد تنظیمات پروژه گیت لب خودمون بشیم.برای این کار اول وارد پٰروژه خودمون میشیم و از منوی سمت چپ settings و بعد repository رو میزنیم.حالا از بخش Deploy tokens گزینه Expand رو میزنیم.حالا پارامتر های مورد نیاز (Name , Expiration date , Username و...) رو تکمیل میکنیم و روی create deploy token میزنیم.و بعد از ساخته شدن deploy token میتونیم username و password رو کپی کنیم و توی url مورد نظر قرار بدیم.????خب اینم از این آموزش . امیدوارم واستون مفید بوده باشه.????برای دریافت آموزش های بیشتر و شرکت در چالش های فلاتری, کانال فلاتری Flutter Challenge(چالش فلاتر) رو دنبال کن.</description>
                <category>Mohammad Taheri</category>
                <author>Mohammad Taheri</author>
                <pubDate>Fri, 03 Sep 2021 21:12:16 +0430</pubDate>
            </item>
                    <item>
                <title>Repository Pattern (+ Unit of Work)</title>
                <link>https://virgool.io/@mohammadtaherri/repository%D9%80pattern-nilqkip90u3w</link>
                <description>در این پست می خوایم در مورد Repository Pattern و Unit of Work و نحوه پیاده سازی اون صحبت کنیم.(در این مقاله از زبان Type scripts برای کد ها استفاده شده ولی کدهای استفاده شده در نهایت سادگی هست و پس از مطالعه این مقاله ,  این پترن رو با هر زبانی میتونید پیاده کنید.)پیش نیاز : تسلط به اصول شی گرایی (OOP)آشنایی با اصول سالید (ترجیحن تسلط نسبی)آشنایی با اصل IoC (ترجیحن تسلط نسبی)آشنایی با مفاهیم اولیه توسعه بک اندآشنایی با مفاهیم اولیه معماری نرم افزاراین پترن  در کتاب Patterns of Enterprise Application Architecture  نوشته ی Martin Fowler بیان شده و رفرنس من هم برای تعاریفی که در این مقاله بیان میشه همین کتاب هست.درابتدا تعریف Repository Pattern رو از این کتاب با هم بررسی می کنیم.Mediates between the domain and data mapping layers , acting like an in-memory collection of domain objects.⁉️ این تعریف چی میگه؟قبل از اینکه این تعریف رو تحلیل و موشکافی کنیم بهتره کلمات کلیدی این تعریف رو با هم بررسی کنیم.Domain توی معماری هایی مثل Clean Architecture یک لایه به اسم Domain داریم که منطق تجاری برنامه در اون قرار میگیره. توی این لایه مواردی که مربوط به جزییات پیاده سازی مثل دیتابیس و... هست قرار نمیگیره.Domain Object (Entity)این جا با یه تعریف  از کتاب Clean Architecture نوشته Uncle Bob این مفهوم رو بررسی می کنیم و در پست های بعدی به طور کامل Entity ها رو موشکافی می کنیم.An Entity is an object within our computer system that embodies a small set of critical business rules operating on Critical Business Data. The Entity object either contains the Critical Business Data  or has very easy access to that data. The interface of the Entity consists of the functions that implement the Critical Business Rules that operate on that data.با یک مثال این تعریف رو ساده می کنیم.مثلن توی هر اپلیکیشنی ما با کاربران سر و کار داریم (Users) پس یه کلاس برای User می سازیم.هر کاربر یک سری ویژگی ها داره مثل اسم , سن و ...این خصوصیات یا Property ها رو در واقع می تونیم Critical Business Data در نظر بگیریم و متد هایی که توی این کلاس اضافه میشن و روی این پراپرتی ها کار میکنن رو Critical Business Rules میگیم.? یک نکته این که هر  Entity حتمن باید یک id داشته باشه و دو Entity در صورتی با هم برابرند که اولن از یک نوع باشن و دومن id یکسانی داشته باشن. ینی دو Entity از جنس User همین که id برابری داشته باشن با هم دیگ یکسانن حتا اگه خصوصیات دیگه اون ها برابر نباشه.(این نکته رو توی مقاله مربوط به Entity ها و Value Object ها بیشتر بررسی می کنیم.)Data Mapperدر واقع Data Mapper Pattern هم یک پترن معماری هست که تعریف کاملش رو می تونید توی کتاب Martin Fowler پیدا کنید.Objects and relational databases have different mechanisms for structuring data. Many parts of an object, such as collections and inheritance, aren&#x27;t present in relational databases. When you build an object model with a lot of business logic it&#x27;s valuable to use these mechanisms to better organize the data and the behavior that goes with it. Doing so leads to variant schemas; that is, the object schema and the relational schema don&#x27;t match up.You still need to transfer data between the two schemas, and this data transfer becomes a complexity in its own right. If the in-memory objects know about the relational database structure, changes in one tend to ripple to the other.The Data Mapper is a layer of software that separates the in-memory objects from the database. Its responsibility is to transfer data between the two and also to isolate them from each other. With Data Mapper the in-memory objects needn&#x27;t know even that there&#x27;s a database present; they need no SQL interface code, and certainly no knowledge of the database schema. (The database schema is always ignorant of the objects that use it.) Since it&#x27;s a form of Mapper (473), Data Mapper itself is even unknown to the domain layer.حالا برگردیم به تعریف Repository Pattern Mediates between the domain and data mapping layers , acting like an in-memory collection of domain objects.این تعریف میگه که Repository در واقع یه کالکشن از Domain Object ها یا همون Entity ها هست که به عنوان واسط بین لایه Domain و Data Mapper ها عمل میکنه.خب این تعریف رو بیشتر بازش کنیم....گفتیم که Repository یه Collection از Entity ها هست , پس باید متدهایی رو داشته باشه که یه Collection داره , متد هایی مانند : addremovegetfind? اولین نکته ای که این جا باید بهش توجه کنیم اینه که داریم در مورد یه Collection صحبت می کنیم, پس متدی به اسم save یا update نداریم.⁉️ پس اگه save و update نداریم چطوری یه Entity جدید ایجاد کنیم یا اون رو اپدیت کنیم؟ این سوال رو وقتی که پترن Unit of Work رو گفتیم جواب میدیم.یکم بریم سراغ پیاده سازی ???گفتیم که هر Repository نماینده یک Entity هست و به عنوان Collection ای از اون Entity در Memory عمل میکنه.(به Memory هم توجه داشته باشید که بعد از توضیح Unit of Work مفهومشو میفهمیم). و همین طور گفتیم هر Repository به خاطر ویژگی Collection بودنش که داره متد هایی مثل add , remove , get , find رو داره. حالا چون که همه Repository ها باید این متد ها رو داشته باشن برای جلوگیری از تکرار کد ها یه کلاس بیس می سازیم که این متد های پایه رو داره و بقیه کلاس ها ازش ارث بری می کنند.همچنین برای رعایت اصول معماری اول یه دونه اینترفیس می سازیم که شامل این متد های پایه میشه.این جا اول یک کلاس بیس برای Entity ها ایجاد کردیم که شامل id هست و همه Entity ها باید از اون ارث بری کنن.یه اینترفیس هم برای Repository های خودمون ساختیم که جنریک هست و با استفاده از جنریک تایپی که داره مشخص میشه که نماینده کدوم Entity هست.? از نقطه نظر معماری این کلاس ها توی بخش Domain قرار میگیرن . یا اگه از معماری سه لایه استفاده میکنید میتونه توی بخشی که لاجیک رو کنترل میکنه قرار بگیره (Controller)?منظور از اصول معماری  رعایت اصول OCP (اصل دوم سالید ) و DIP (اصل پنجم سالید)  و ... هست.حالا باید یه کلاسی داشته باشیم که این اینترفیس رو پیاده سازی کنه .اینجا کلاس Repository رو می بینیم که اینترفیس قبلی رو پیاده سازی کرده و یه Abstract Generic Class هست.? برای هر دیتابیس یا هر Data Mapper که داریم می تونیم یه پیاده سازی جدا داشته باشیم. خب تا اینجا کلاس های بیس رو پیاده کردیم و باید بریم سراغ هر کدوم از Entity ها .به ازای هر Entity باید یه دونه Repository داشته باشیم که علاوه بر داشتن متد های پایه متد های اختصاصی مربوط به اون  Entity رو هم داره (رابطه یک به یک - یک Collection به ازای هر Entity).اینجا هم به ازای هر Entity یه اینترفیس میسازیم که از اینترفیس IRepository ارث بری میکنه.فرض کنید یه اپلیکیشن فروشگاهی داریم و یکی از موجودیت های ما محصولات هستن.میبینیم که یه IProductInterface داریم که نماینده محصولات هست و با ارث بری از IRepository متد های پیاه رو به ارث میبره و خودش هم دو تا متد اختصاصی برای دریافت پرفروش ترین محصولات و دریافت محصولات به وسیله ی دسته بندی اضافه میکنه.?از نقطه نظر معماری این اینترفیس هم باید در بخش Domain قرار بگیره.حالا بریم سراغ پیاده سازی این اینترفیس که توی بخش Data یا دیتابیس قرار میگیره.اینجا کلاس ProductRepository رو داریم که از کلاس Repository ارث بری کرده تا از پیاده سازی های متد های پایه استفاده کنه و همچنین اینترفیس IProductRepository رو هم پیاده سازی کرده.خب تا اینجا پیاده سازی Repository Pattern رو دیدیم ولی هنوز به چنتا سوال جواب ندادیم.⁉️منظور از in-memory توی تعریف Collection of Domain Objects in-memory چیه؟⁉️ چرا متدی برای ذخیره کردن یا اضافه کردن یه Entity نداریم و برای اضافه کردن یه Entity جدید باید چکار کنیم ( save action)؟⁉️ چرا متدی برای ویرایش یه Entity نداریم و برای ویرایش یه Entity  باید چکار کنیم ( update action)؟حالا سوالا رو دونه دونه جواب میدیم ??? اما کلید واژه اصلی جواب این سوالا ترکیب کردن Repository Pattern با Unit of Work Pattern هست.پس اول تعریف این پترن رو از کتاب Patterns of Enterprise Application Architecture با هم میبینیم.Maintains a list of objects affected by a business transaction and coordinates the writing out of changes.برای درک مفهوم این پترن و جواب به سوالات بالا یه مثال ساده مطرح میکنیم.فرض کنید یه اپلیکیشن فروشگاهی داریم که یه Entity به اسم دسته بندی داره (Category) و یه Entity هم به اسم محصول (Product) که هر محصول میتونه یه دسته بندی داشته باشه.حالا فرض میکنیم که 3 تا سرویس لازم داریم (یا به زبان Clean Architecture همون Use Case)یک سرویس برای اضافه کردن یا ساختن دسته بندی جدید AddCategoryServiceیک سرویس برای ویرایش دسته بندی EditCategoryServiceو یک سرویس برای حذف دست بندی RemoveCategoryServiceاول  RemoveCategoryService رو بررسی میکنیم. چون که هر محصول به یک دسته بندی کوپل شده تصمیم داریم که با حذف یک دسته بندی همه محصولات مربوط به اون دسته بندی هم حذف شه.پس کد مربوط به این سرویس رو به این شکل مینویسیم.اینجا هم یه اینترفیس IService داریم که RemoveCategoryService اون رو پیاده کرده که از توضیح جزییات مربوط به این بحث صرف نظر میکنیم.اگه به پیاده سازی متد execute توی سرویس مورد نظر توجه کنیم (فقط موارد ضروری اورده شده و از جزییات صرف نظر شده) میبینیم که ابتدا دسته بندی مورد نظر و محصولات مربوط به اون دریافت شدن و بعدن به ترتیب دسته بندی و محصولات حذف شدن.با یه نگاه ساده به این پیاده سازی مشکلی نمیبینیم و به ظاهر درسته.⁉️ پس مشکل کجاست؟ ???ما اول داریم دسته بندی رو حذف میکنیم و بعد که مطمین شدیم ک دسته بندی به درستی حذف شد محصولاتش رو حذف میکنیم. حالا اگه حین حذف محصولات یه مشکلی به وجود بیاد و محصولات به درستی حذف نشن , دسته بندی حذف شده و یه سری محصول رو هوا مونده داریم. ???اینجاست که Unit of Work Pattern در کنار Repository به کمکمون میاد.قبلن گفتیم که Repository در واقع یه کالکشن از Entity ها توی حافظه (رم) هست . وقتی داریم از حافظه صحبت میکنیم یعنی اینکه این تغییراتی که داریم اعمال میکنیم اصلن توی دیتابیس ذخیره نمیشن و فقط توی حافظه ثبت میشن(این پترن باید به نحوی پیاده بشه که تغییرات فقط توی حافظه ثبت بشن).یعنی وقتی که میگیم : await this.categories.remove(category);await this.products.removeRange(products);این تغییرات فقط توی حافظه ثبت میشن و باید یه راهی پیدا کنیم که اون ها رو به صورت دایم ثبت کنیم.اینجاست که Unit of Work به کمکمون میاد.اول یکم راجب پیاده سازی این پترن توضیح بدیم. این جا هم اول ی اینترفیس میسازیم.این اینترفیس شامل همه اینترفیس هایی هست که برای Repository هامون ساختیم(Abstract Factory Design Pattern) و یه متد complete داره.⁉️ ولی کارش چیه؟به جای ایکه توی سرویس های به صورت مستقیم به Repository ها دسترسی پیدا کنیم یه ابجکت از جنس IUnitOfWork رو به سرویس ها پاس میدیم و با استفاده از پراپرتی های این ابجکت (categories , products, ...)به Repository ها دسترسی پیدا میکنیم.اینجوری وقتی که روی هر Repository یه تغییری اعمال میشه اون تغییر فقط و فقط توی حافظه اعمال میشه و اخر کار که کار سرویس تموم شد و همه تغییرات اعمال شدن , سرویس متد complete رو صدا میزنه و این متد همه تغییرات اعمال شده روی حافظه  رو ذخیره میکنه.⁉️ مزیت این روش چیه؟???مزیت این روش اینه که وقتی توی مثال بالا اول دسته بندی و بعد محصولات رو حذف میکنیم این تغییرات فقط توی حافظه اعمال میشه و با صدا زدن متد complete یه transaction توی دیتابیس ساخته میشه و همه اون تغییرات رو با هم توی دیتابیس اعمال میکنه . حالا اگه یهو وسط کار یه مشکلی پیش بیاد و مثلن یه دونه از محصولات نتونه که حذف شه همه تغییرات به حالت اول برگردونده میشه و انگار که هیچ تغییری توی دیتابیس ندادیم (و این متد یه ارور برمیگردونه و به یوزر میگه حذف به درستی انجام نشد) و نه دسته بندی و نه محصولات هیچ کدوم حذف نمیشن.پس یا همه تغییرات با هم به درستی اعمال میشن یا هیچ کدوم.محصولات هم رو هوا نمیمونن. ???حالا پیاده سازی اینترفیس IUnitOfWork رو هم با ببینیم.توی سازنده این کلاس میبینیم که categories , products مقدار دهی شدن و پیاده سازی های واقعی برای این مقدار دهی استفاده شدن.پس فک میکنم که  مفهوم in_memory رو به خوبی درک کرده باشید.حالا بریم به دو سوال دیگه جواب بدیم ???⁉️ چرا متدی برای ذخیره کردن یا اضافه کردن یه Entity نداریم و برای اضافه کردن یه Entity جدید باید چکار کنیم ( save action)؟اینکه چرا متدی به اسم save توی Repository نداریم رو قبلن توضیح دادیم ولی برای اضافه کردن یه Entity جدید از متد add استفاده میکنیم . این متد هم تغییرات رو توی حافظه اعمال میکنه و در نهایت با صدا زدن complete این تغییرات ذخیره میشه.برای این منظور مثال AddCategoryService رو با هم میبینیم.سوال بعدی ...⁉️ چرا متدی برای ویرایش یه Entity نداریم و برای ویرایش یه Entity  باید چکار کنیم ( update action)؟گفتیم که Repository درو اقع یه کالکشن از ابجکت هاست. توی دنیای برنامه نویسی برای ویرایش یه عنصر از یه ارایه چکار میکنیم؟names = [&#039;Mohammad&#039; , &#039;Arash&#039; , &#039;Shayan&#039;];
names[0] = &#039;Daryoosh&#039;;اینجا هم دقیقن همین کار رو میکنیم. به مثال EditCategoryService توجه کنید.میبینیم که اول دسته بندی رو دریافت کردیم و بعد ویرایش کردیم و در نهایت تغییرات رو با صدا زدن متد complete ذخیره کردیم.حالا یکم از مزایای Repository Pattern بگیم :‌جلوگیری از تکرار کد. دیدیم که همه Repository ها به یک سری متد های پایه نیاز دارن و با استفاده از یه بیس کلاس این متد ها رو پیاده کردیم و از تکرار کد جلوگیری کردیم.⁉️ به نظرتون دیگه چه مواردی باعث جلوگیری از تکرار کد میشه؟کمک به تست پذیر شدن کد.این موضوع هم با رعایت اصول سالید از جمله اصل DIP و هچنین رعایت اصل IoC محقق میشه که به طور کامل این موارد رو رعایت کردیم.مستقل شدن برنامه از دیتابیس ها و ORM ها.این مورد هم همون طور که دیدین با رعایت اصل DIP محقق شد و ما میتونیم پیاده سازی های مختلفی از اینترفیس ها داشته باشیم و از هر کدوم که مایل بودیم استفاده کنیم و به سرویس هامون پاس بدیم (با رعایت اصل ioC).و...⁉️ دیگه به نظرتون استفاده از این پترن چه مزیت هایی داشت ؟‌شما بگین (توی کامنت ??? ).</description>
                <category>Mohammad Taheri</category>
                <author>Mohammad Taheri</author>
                <pubDate>Mon, 30 Aug 2021 14:49:06 +0430</pubDate>
            </item>
            </channel>
</rss>