سی شارپ و دات نت مدرن:‌ بخش اول -‌ آشنایی با سی شارپ

فهرست مطالبچرا سی شارپ؟ به عبارت دیگه، چرا باید بین انبوه زبان های برنامه نویسی موجود سی شارپ رو انتخاب کنیم؟ صادقانه بگویم که نباید! در واقع هر برنامه نویسی با چند سال تجربه این نکته رو به خوبی می دونه که طرفداری محض از یک زبان برنامه نویسی خاص، چیزی جز عقب ماندن از روند تکنولوژی به همراه نداره. در دنیای واقعی شما به سرعت یاد می گیرید که باید با زبان ها و فریم ورک های مختلف و متفاوتی کار کنید. سی شارپ یکی دیگر از این زبان هاست و دات نت هم یک فریم ورک دیگر. بنابر این سوال درست اینه که: آیا سی شارپ ارزش یاد گرفتن رو داره یا خیر؟ برای پاسخ به این سوال باید با سی شارپ و اکوسیستم دات نت بیشتر آشنا بشیم:آناتومی سی شارپاز اونجایی که هدف یک آشنایی کلی هست؛ در این قسمت به سه نکته اصلی بسنده می کنم:نکته اول: این که سی شارپ یک زبان statically typed هست. statically typed یعنی این زبان طوری طراحی شده که شما به عنوان یک برنامه نویس باید نوع متغیر ها رو پیش از استفاده تعیین کنید. برای مثال اگر تعیین کنید که x یک متغیر از نوع عدد صحیح هست؛ بعدا نمی تونید یک عدد اعشاری رو به x نسبت بدید. شاید این یک محدودیت به نظر میاد اما در پروژه های بزرگ در واقع یک مزیت هست. در نظر بگیرید که روی پروژه ای کار می کنید که هزاران خط کد داره که توسط چندین تیم مختلف نوشته شدند. در چنین مواقعی این که بدونید متغیری که قراره باش کار کنید از چه نوعی هست؛ کار شما رو برای نوشتن کد درست راحت تر می کنه. برای مثال تصور کنید که روی فرم ثبت نام یک وب اپلیکیشن کار می کنید که متغیری به نام userAge در اون تعریف شده که برابر با سن کاربر هست. وقتی میدونید این متغیر از نوع int یا عدد صحیح هست؛ می تونید با خیال راحت در مراحل بعدی (در صورت نیاز) اعمال ریاضی رو با خیال راحت روی اون انجام بدید. اما وقتی این متغیر اصطلاحا dynamic باشه و نشه نوعش رو پیشبینی کرد؛ ممکنه سن کاربر به عنوان یک string (متن) ذخیره شده باشه. در نتیجه در ظاهر امر می بینید که مثلا سن کاربر ۱۸ وارد شده. اما این عدد ۱۸ نیست و فقط یک متنه. پس امکان انجام اعمال ریاضی روش وجود نخواهد داشت و اگه اقدام به چنین کاری کنید؛‌ اپلیکیشن شما در زمان اجرا با خطا مواجه میشه. رفع کردن این نوع خطا ها (خطا های زمان اجرا یا runtime) هم گاها بسیار پیچیده و گیج کننده خواهد بود. بنابر این استاتیک تایپ بودن سی شارپ عملا یک مزیت محسوب میشه. کما این که در دنیای وب اپلیکیشن ها می بینیم که برنامه نویس ها تمایل دارند به جای Javascript از Typescript استفاده کنند که در واقع نسخه استاتیک تایپ جاوا اسکریپت هست و شانس بروز خطای runtime رو کاهش می ده.همه این ها که گفته شد؛ باید اضافه کنم که سی شارپ قابلیت استفاده از تایپ های dynamic رو هم داره. اما به عنوان یک قاعده کلی، بهتره که از اون ها در پروژه های بزرگ و جدی و تیمی استفاده نکنیم.نکته دوم: سی شارپ یک زبان multiparadigm هست. پارادایم های مختلفی در برنامه نویسی تعریف شده که آشنایی با تک تک اون ها در حوصله این سری از مطالب نیست. اما به طور خیلی کلی ۳ پارادایم اصلی رو میتونیم procedural, object oriented و functional تعریف کنیم. بعضی زبان های قدیمی مثل C، از مفاهیم برنامه نویسی شیء گرا و فانکشنال پشتیبانی نمی کنند اما قابلیت استفاده از مفهوم تابع در اون ها وجود داره. تابع ها شامل ورودی، کدی که ورودی رو پردازش می کنه و خروجی هستند. چنین زبان هایی صرفا procedural نامیده میشن. زبان هایی مثل C++ قابلیت تعریف کلاس و آبجکت رو هم دارند. پس شیء گرا هستند. فانکشنال پروگرمینگ هم یک پارادایم جدید تر هست که تفاوت های زیادی با دو پارادایم قبلی داره اما مزیتش نوشتن کد های خلاصه تر و سریع تر و شانس کمتر بروز باگ هست. زبان هایی مثل Haskell برای برنامه نویسی فانکشنال طراحی شدند. زبان های جدید تر مثل پایتون، GO، Kotlin و سی شارپ، توانایی پشتیبانی تمام پارادایم های بالا رو دارند و اصطلاحا مولتی پارادایم نامیده میشوند. بنابر این صرف نظر از استایلی که برای برنامه نویسی پروژه‌تون انتخاب خواهید کرد؛ سی شارپ دست شما رو در پیاده سازی باز خواهد گذاشت. نکته سوم: سی شارپ شباهت ساختاری زیادی به جاوا داره. توضیح این نکته نیازمند کمی مقدمه چینی هست. خیلی ساده توضیح بدم: کدی که با زبان برنامه می نویسید؛‌ با کدی که به CPU برای اجرا تحویل داده می شه هیچ شباهتی نداره. CPU دستورات و داده ها رو به صورت صفر و یک دریافت می کنه از این رو کدی که قابل اجرا توسط پردازنده هست byte code نامیده میشه. بنابر این کدی که به یک زبان سطح بالا (مثل سی یا جاوا یا هر زبان دیگری) می نویسید؛ قبل از اجرا باید ابتدا به بایت کد ترجمه بشه. به این فرایند ترجمه کامپایل گفته میشه و برنامه ای که این ترجمه رو انجام میده Compiler نام داره. قبل از جاوا، زبان های برنامه نویسی به صورت static یا ahead-of-time کامپایل می شدن. به این معنا که کد به بایت کد کامپایل می شد و نتیجه می شد یک فایل قابل اجرا (executable) و این فایل به کاربر نهایی برای اجرا تحویل داده می شد. اما جاوا به داستان کامپایلیشن نگاه دیگری داشت:در جاوا دو نوع کامپایلر مورد استفاده قرار میگیرند. یک کامپایلر استاتیک کد شما رو به یک زبان اسمبلی (یک زبان حد واسط بین زبان سطح بالا و بایت کد) اختصاصی جاوا کامپایل می کنه. فایل حاصل شده که Java bytecode نامیده میشه در اختیار کاربر قرار میگیره. اما این فایل به طور مستقیم توسط پردازنده قابل اجرا نیست و به عبارتی بایت کد واقعی نیست. برای اجرای فایل کاربر باید JVM یا ویرچوال ماشین جاوا رو روی سیستمش نصب کنه. این جاست که مرحله دوم کامپایلیشن صورت میگیره و بایت کد واقعی تولید و برنامه اجرا میشه. از اون جایی که این مرحله دوم در لحظه اجرای برنامه انجام میشه و نه از قبل، به این نوع کامپایل JIT یا Just In Time Compilation گفته میشه.کد های سی شارپ هم برای اجرا یک فرایند خیلی مشابه رو طی می کنند و ابتدا به CIL یا Common Intermediate Language (مشابه Java bytecode) کامپایل می شن بعد توسط CLR یا Common Language Runtime (کامپایلر JIT‌ که مشابه JVM) به بایت کد کامپایل شده و اجرا میشن. اما چرا دات نت فرایند کامپایل رو به این شیوه انجام میده؟ مزیت این فرایند سازگاری با سخت افزار ها و سیستم عامل های مختلف هست. به این معنا که CIL شما می تونه توسط CLR علاوه بر ویندوز روی مک، ویندوز، لینوکس، اندروید و iOS هم اجرا بشه و به این شیوه شما امکان نوشتن یک نرم افزار کراس پلتفرم رو خواهید داشت که با سیستم عامل ها و پردازنده های مختلف (ARM, x86, x64) سازگار خواهد بود. البته این فرایند معایبی هم داره. از جمله حجم بیشتر فایل ها، نیاز به نصب دات نت برای اجرای فایل ها و نهایتا این که کامپایلر های JIT بار اضافه یا Overhead به سیستم تحمیل می کنند و برنامه شما کند تر از برنامه ای که به شیوه کاملا استاتیک کامپایل شده اجرا خواهد شد. هرچند در بسیاری از سناریو ها و با توجه به قدرت روز افزون پردازنده ها این کندی برای کاربر چندان ملموس نیست. در چه مواردی سی شارپ انتخاب خوبی نیست؟سناریو هایی وجود دارن که نقاط قوت سی شارپ رو به نقطه ضعف تبدیل می کنند. برای مثال وقتی برنامه قراره بار محاسباتی بالایی به سیستم وارد کنه، کامپایل دو مرحله ای سی شارپ، به علت استفاده از JIT در مرحله دوم (CLR) محاسبات رو به طرز قابل توجهی سنگین و کند خواهد کرد. بنابر این در توسعه موتور های بازی سازی، موتور های هوش مصنوعی (مثل tensorflow) و نرم افزار های آنالیز عددی (مثل MATLAB) زبان هایی مثل سی شارپ، پایتون و جاوا انتخاب های خوبی نیستند و این نرم افزار ها معمولا با زبان های static و سریع تر مثل C و C++ توسعه داده میشن. البته دات نت امکان کامپایل کردن تک مرحله ای static را هم در اختیار کاربر قرار میده اما در اون صورت مزیت کراس-پلتفرم بودن رو از دست خواهید داد. ضمن این که باز هم زبان هایی مثل C++ در این حالت معمولا سرعت بیشتری دارند. علاوه بر استفاده از JIT، سی شارپ یک زبان managed هست. توضیح این که زبان های شیء گرا، برای مدیریت حافظه (رم) سیستم نیازمند فرایندی به نام Garbage Collection هستند که به زبان ساده، حافظه رو از اشغال اشیائی که دیگر مورد استفاده قرار نمی گیرند آزاد می کنه. در زبان های managed، این فرایند به صورت خودکار انجام می شه. مزیت چنین چیزی ساده تر شدن کار برنامه نویس در کد نویسی هست. اما عیب بزرگش این هست که مدیریت حافظه خودکار به ندرت به اندازه مدیریت دستی حافظه بهینه هست. از این رو در توسعه firmware ها و سیستم عامل ها که مدیریت بهینه حافظه در اون ها یک جزء کلیدی محسوب میشه؛ سی شارپ انتخاب خوبی نیست. خلاصه کلامدر این مطلب آموختیم که سی شارپ یک زبان statically typed، مولتی پارادایم و managed هست که شباهت ساختاری زیادی با جاوا داره و همچنین با برخی نقاط قوت و ضعف سی شارپ آشنا شدیم. در مطلب بعدی با دات‌نت بیشتر آشنا خواهیم شد. شاد باشید :)