10 ویژگی‌ عجیبِ زبانِ دارت

زبان برنامه نویسی دارت

بذار همین اول یه چیزی رو صاف کنیم. وقتی می‌گیم «عجیب»، منظورمون «بد» یا «به‌دردنخور» نیست. منظورمون «متفاوت»، «خفن»، «هوشمندانه» و گاهی «WTF!» هست. زبان دارت (Dart) یه زبانه که توسط یه سری از خفن‌ترین مهندس‌های گوگل (کسایی که موتور V8 کروم و HotSpot جاوا رو ساخته بودن) طراحی شده. این آدم‌ها جمع نشدن که یه کپی دیگه از جاوا یا جاوااسکریپت بسازن؛ اونا جمع شدن تا مشکلات واقعی دنیای برنامه‌نویسی، مخصوصاً تو ساخت UI (رابط کاربری)، رو حل کنن.

10 ویژگی‌ عجیبِ زبانِ دارت

نتیجه‌اش شده زبان دارت؛ زبانی که شاید در نگاه اول شبیه C یا جاوا باشه، اما وقتی یه کم عمیق‌تر می‌شی، می‌بینی پر از ویژگی‌های عجیب‌غریبه که هرکدوم مثل یه آچار فرانسه تخصصی، یه مشکل بزرگ رو به شیوه‌ای فوق‌العاده زیبا حل می‌کنه. خیلی‌ها فکر می‌کنن دارت فقط یه نوچه برای فلاتر flutter هست، اما حقیقت اینه که فلاتر flutter بدون قدرت و ویژگی‌های خاص زبان دارت، هیچی نبود. آینده زبان دارت به فلاتر گره خورده، چون این زبان دقیقاً برای همین کار تراشیده شده.

تو این مقاله، قرار نیست بگیم «دارت خوبه چون گوگل پشتشه». قراره بریم تو دل کد و ۱۰ تا از اون ویژگی‌های فنی و عمیقی رو بکشیم بیرون که باعث می‌شه یه توسعه‌دهنده جاوا، #C یا جاوااسکریپت با دهن باز به کد نگاه کنه و بگه «دمش گرم! کاش منم اینو داشتم!». اگه آماده‌ای مخت سوت بکشه، ادامه بده.

اولین و شاید مهم‌ترین ویژگی زبان دارت، مدل کامپایل دوگانه‌اش هست. این خفن‌ترین بخش ماجراست. ببین، زبان‌ها معمولاً یا مفسری/JIT هستن (مثل جاوااسکریپت، پایتون) یا کامپایلی/AOT هستن (مثل C++, Go, Swift). زبونای JIT (Just-in-Time) موقع اجرا کد رو خط به خط می‌خونن و کامپایل می‌کنن. این کار برای توسعه (Development) عالیه. چون می‌تونی کد رو عوض کنی، سیو کنی و همون لحظه تغییر رو ببینی. این همون چیزیه که بهش می‌گن Hot Reload.

هات ریلود فلاتر و دارت

زبونای AOT (Ahead-of-Time) قبل از اجرا، کل کد رو به زبان ماشین (مثلاً کد نیتیو ARM یا x86) تبدیل می‌کنن. این کار برای نسخه نهایی (Release) عالیه. چون اپلیکیشن مثل موشک اجرا می‌شه، هیچ مترجمی وسط کار نیست و پرفورمنسش در حد نیتیوه.

آموزش کامل فریم ورک فلاتر

آموزش فریم‌ورک فِلاتر

آموزش فلاتر !! می‌دونم چرا اینجایی. احتمالاً سرت از دست اطلاعات ضد و نقیض در مورد برنامه‌نویسی موبای...

مشاهده دوره

حالا زبان دارت چیکار کرده؟ گفته «من جفتشم!». وقتی تو داری با فلاتر flutter کد می‌زنی و تو شبیه‌ساز یا رو گوشی تست می‌کنی، دارت از کامپایلر JIT استفاده می‌کنه. تو دکمه رو آبی می‌کنی، سیو می‌کنی و در کمتر از یک ثانیه، دارت VM اون تیکه کد رو درجا کامپایل و تزریق می‌کنه و تو تغییر رو می‌بینی. این همون جادوی «Hot Reload» هست.

اما وقتی کارت تموم شد و می‌خوای خروجی apk یا ipa بگیری که بدی دست مشتری، به دارت می‌گی «حالت AOT فعال شه!». اینجا کامپایلر AOT دارت میاد کل کدهای تو رو مستقیماً به کد نیتیو ARM64 یا x86-64 کامپایل می‌کنه. نتیجه‌اش یه اپلیکیشنه که با سرعت نور اجرا می‌شه و هیچ پلی (Bridge) مثل ری‌اکت نیتیو به جاوااسکریپت نداره. این دوگانگی شخصیت، بزرگترین مزیت زبان دارت و دلیل اصلی پیروزی فلاتر یا ری اکت نیتیو تو بنچمارک‌های پرفورمنسه.

javascript Bridge nabegheha

خیلی از زبونای مدرن (مثل کاتلین یا سوئیفت) «Null Safety» دارن. جاوااسکریپت با تایپ‌اسکریپت هم یه جورایی داره. اما زبان دارت یه چیز دیگه داره: «Sound Null Safety». این کلمه «Sound» (به معنی استوار یا ۱۰۰٪) همه‌چیز رو عوض می‌کنه. تو زبان‌های دیگه، Null Safety گاهی اوقات یه پیشنهاده. تو تایپ‌اسکریپت می‌تونی خاموشش کنی یا با any دورش بزنی. تو جاوا اگه یه کتابخونه قدیمی (که Nullable-aware نیست) رو صدا بزنی، کل سیستم به هم می‌ریزه. اما تو زبان دارت (از نسخه ۲.۱۲ به بعد)، این یه قانونه، نه پیشنهاد. وقتی تو یه متغیر رو اینطوری تعریف می‌کنی:

String name;

کامپایلر دارت قسم می‌خوره که این متغیر هیچ‌وقت null نخواهد بود. نه فقط موقع کامپایل، بلکه موقع اجرا (Runtime) هم چک می‌کنه. این یعنی چی؟ یعنی خطای مخوف NullPointerException (یا Cannot read properties of null تو JS) در زبان دارت رسماً مرده و به تاریخ پیوسته. تو نمی‌تونی همچین خطایی بگیری، مگه اینکه خودت رسماً با علامت ! به کامپایلر دروغ بگی (که اونم تقصیر خودته).

این سیستم «Sound» به کامپایلر اجازه می‌ده کدهای بهینه‌تری تولید کنه. چون وقتی می‌دونه name هیچ‌وقت null نیست، دیگه لازم نیست ۵۰ بار چکش کنه. این یعنی کد سریع‌تر و اپلیکیشن‌های پایدارتر. این یکی از اون ویژگی‌هاییه که تا باهاش کد نزنی، نمی‌فهمی چه نعمتیه. این مقاله رو داخل وبلاگ بخون تا همه چیز رو در مورد ویژگی Sound Null Safety بدونی.

برنامه نویسی دارت

خب، رسیدیم به یه بخش عجیب. «چطور تو دارت کارهای همزمان (Concurrency) انجام بدیم؟». اگه از جاوا یا #C بیای، میگی «خب معلومه، Thread می‌سازیم». اگه از جاوااسکریپت بیای، میگی «با Event Loop و Async/Await کار می‌کنیم». زبان دارت میگه: «هر دو تاش اشتباهه!». دارت یه مدل منحصربه‌فرد داره به اسم Isolates (ایزولیت‌ها).

تو جاوا، وقتی دو تا ترد می‌سازی، هر دو به یه حافظه (Memory) مشترک دسترسی دارن. این یعنی کابوس! باید حواست به lock کردن متغیرها، Mutex، Semaphore و هزارتا کوفت و زهرمار دیگه باشه تا یهو دو تا Thread با هم ننویسن رو یه متغیر و همه‌چیز رو خراب کنن (بهش میگن Race Condition). تو جاوااسکریپت، تو اصلاً Thread نداری. همه‌چی Single-threaded هست. اگه یه محاسبه سنگین (مثلاً پردازش یه عکس) رو شروع کنی، کل UI (رابط کاربری) قفل می‌کنه تا کارش تموم شه.

cover dart 344x408 1

آموزش برنامه نویسی دارت

آموزش زبان برنامه نویسی دارت؛ از صفر تا حرفه‌ای وقتی میای تو این صفحه، می‌دونم دنبال یه چیزی بیشتر ا...

مشاهده دوره

ایزولیت‌های دارت یه مدل سومه: «عدم اشتراک حافظه» (No Shared Memory). هر ایزولیت، مثل یه کارگر تو یه اتاق در بسته می‌مونه. حافظه و منابع خودشو داره. هیچ ایزولیتی حق نداره به حافظه یه ایزولیت دیگه دست بزنه. تموم شد! کل مشکلات Threading مرد! «خب پس چطور با هم حرف می‌زنن؟» با «نامه» فرستادن (Message Passing). یه ایزولیت یه پیام (مثلاً یه آبجکت) رو می‌ذاره تو یه صندوق پستی (Port)، ایزولیت دیگه اون پیام رو برمی‌داره و کپی می‌کنه تو حافظه خودش.

این مدل باعث می‌شه زبان دارت برای UI فوق‌العاده باشه. تو یه ایزولیت اصلی داری که UI رو رندر می‌کنه (و هیچ‌وقت قفل نمی‌شه). هر وقت کار سنگین داری، یه ایزولیت جدید باز می‌کنی، کار رو بهش می‌دی، اونم وقتی تموم شد، نتیجه رو برات «پست» می‌کنه. این یعنی UI همیشه نرم و روون، بدون هیچ دردسر قفل‌گذاری.

آموزش دارت

این یکی از اون «عجیب»هاییه که همون لحظه اول عاشقش می‌شی. یه Syntactic Sugar نابه. فرض کن یه کلاس Person داری و می‌خوای یه آبجکت بسازی و مقداردهیش کنی. تو جاوا یا JS اینکارو می‌کنی:

void main() {
  // ### مثال ۱: روش سنتی (بدون عملگر آبشاری)

  var p1 = Person();
  p1.name = "Ali";
  p1.age = 30;
  p1.sayHello();
}

خیلی تکراری و خسته‌کننده است، نه؟ حالا تو زبان دارت می‌تونی از «عملگر آبشاری» (Cascade Notation) یا همون دو نقطه .. استفاده کنی:

void main() {
  // ### مثال ۲: روش دارت (با عملگر آبشاری ..)

  var p2 = Person()
    ..name = "Ali"
    ..age = 30
    ..sayHello();
}

این کد دقیقاً همون کار کد بالایی رو می‌کنه. جادوش چیه؟ عملگر .. هر کاری که می‌خوای رو روی آبجکت p انجام می‌ده، ولی در نهایت، به جای برگردوندن نتیجه اون کار (مثلاً sayHello که void برمی‌گردونه)، خودِ آبجکت اصلی (p) رو برمی‌گردونه. این ویژگی برای ساختن UI تو فلاتر flutter یه نعمته. مخصوصاً وقتی داری از یه «Builder» استفاده می‌کنی و می‌خوای ۱۰ تا متد رو پشت سر هم روی یه آبجکت صدا بزنی. این کد رو فوق‌العاده تمیز و خوانا می‌کنه.

۵. متدهای Extension – قدرت هک کردن کلاس‌ها!

اینم یکی دیگه از اون قدرتهای عجیبه. فرض کن می‌خوای یه متد به کلاس String اضافه کنی. مثلاً می‌خوای یه متد به اسم ()toInt داشته باشی که یه رشته رو به عدد تبدیل کنه. مشکل اینه که کلاس String مال تو نیست، مال خود زبان دارت هست و تو نمی‌تونی بازش کنی و بهش متد اضافه کنی. تو زبان‌هایی مثل جاوااسکریپت، مجبوری یه فایل کمکی (Helper) بسازی و اینطوری صداش بزنی:

Utils.parseInt(myString)

خیلی زشته.

تو زبان دارت، می‌تونی از Extension Methods استفاده کنی. یعنی بدون اینکه به کلاس دست بزنی، بهش متد اضافه کنی. اینطوری:

extension NumberPars on String { int toInt() { return int.parse(this); } }

همین! حالا هر جای برنامه‌ات که این فایل رو import کرده باشی، می‌تونی اینطوری کد بزنی :

void main() {
  var myString = "123";
  var myInt = myString.toInt();
}

به همین راحتی! این قابلیت تو فلاتر flutter داره منفجر می‌شه. مثلاً تو می‌تونی یه extension روی Widget بنویسی که بهش padding بده. بعد به جای اینکه بنویسی :

// روش سنتی و تودرتو
Padding(
  padding: const EdgeInsets.all(10.0),
  child: MyWidget(),
)

خیلی شیک می‌نویسی:

import 'package:flutter/material.dart';

extension PaddingExtension on Widget {
  
  Widget withPadding(double padding) {
    return Padding(
      padding: EdgeInsets.all(padding),
      child: this,
    );
  }
}

این کد رو به شدت خوانا و ماژولار می‌کنه.

۶. همه‌چیز یه شیء هست (حتی Null و توابع)

این یکی یه کم فلسفیه ولی خیلی مهمه. تو زبان‌هایی مثل جاوا یا #C، تو دو نوع داده داری: «انواع اولیه» (Primitives) مثل int, double, boolean و «انواع مرجع» (Reference Types) یا همون آبجکت‌ها. این دوگانگی همیشه دردسرسازه. تو زبان دارت، این دوگانگی وجود نداره. همه‌چیز یک شیء (Object) است. int یه شیء هست و از کلاس Object ارث‌بری می‌کنه. double یه شیء هست. bool یه شیء هست. این یعنی چی؟ یعنی int هم می‌تونه متد داشته باشه. مثلاً می‌تونی بنویسی ()toString. و کار می‌کنه!

عجیب‌تر اینکه، توابع (Functions) هم آبجکت هستن. اونا نمونه‌ای از کلاس Function هستن. این یعنی تو می‌تونی یه تابع رو بریزی تو متغیر، به عنوان آرگومان پاسش بدی به یه تابع دیگه، یا از یه تابع به عنوان خروجی برش گردونی. (به این میگن First-class functions). و عجیب‌ترین بخش: null هم یه شیء هست! null تنها نمونه‌ی موجود از کلاس Null هست. این باعث می‌شه کل سیستم تایپ زبان دارت یه دست و یکپارچه باشه. این سادگی و یکپارچگی فلسفی، نوشتن کدهای پیچیده رو خیلی راحت‌تر می‌کنه.

برنامه نویسی دارت

۷. سازنده‌های Factory – وقتی سازنده، سازنده نیست!

تو ۹۹٪ زبان‌های برنامه‌نویسی، وقتی کلمه کلیدی new (یا معادلش) رو صدا می‌زنی، اون زبان موظفه یه آبجکت جدید از اون کلاس تو حافظه بسازه. زبان دارت یه مفهوم «عجیب» داره به اسم Factory Constructors. وقتی یه سازنده (Constructor) رو با کلمه factory علامت‌گذاری می‌کنی، به دارت می‌گی: «هی رفیق! وقتی کسی این سازنده رو صدا زد، الزامی نیست که یه آبجکت جدید بسازی!». سازنده factory در واقع یه متد استاتیک با قیافه سازنده‌ است. این به چه دردی می‌خوره؟

۱. الگوی Singleton : می‌خوای از یه کلاس فقط یه دونه تو کل برنامه ساخته بشه (مثلاً کلاس اتصال به دیتابیس). با سازنده factory چک می‌کنی اگه قبلاً ساخته شده، همون قبلی رو برگردون، وگرنه یه جدید بساز.

۲. الگوی Factory : می‌خوای بر اساس یه ورودی، یکی از زیرکلاس‌ها رو برگردونی. مثلاً سازنده Shape(‘circle’) رو صدا می‌زنی، ولی اون تو پشت صحنه یه آبجکت از کلاس Circle برمی‌گردونه.

۳. کش کردن (Caching) : می‌خوای آبجکت‌هایی که قبلاً ساخته شده رو کش کنی. مثلاً :

Color.fromHex('#FF0000')

لازم نیست هر بار یه آبجکت جدید برای «رنگ قرمز» بسازی. سازنده factory چک می‌کنه اگه «قرمز» تو کش بود، همون رو برمی‌گردونه. این قابلیت، کنترل بی‌نظیری روی نحوه ساخته شدن آبجکت‌ها بهت می‌ده که تو زبان‌های دیگه به این تمیزی وجود نداره.

۸. رکوردها (Records) – بازگشت چند مقدار بدون دردسر

این یکی از ویژگی‌های مدرن زبان دارت (که تو Dart 3 در سال ۲۰۲۳ معرفی شد) و فوق‌العاده «عجیب» و کاربردیه. مشکل همیشگی: تو می‌خوای از یه تابع، دو یا سه تا مقدار رو برگردونی. مثلاً اسم و فامیل کاربر. تو زبان‌های قدیمی چیکار می‌کردی؟

راه ۱ (افتضاح) : یه List برمی‌گردوندی: [‘Ali’, ‘Rezayi’]. که تایپ-سیف نیست و افتضاحه.

راه ۲ (خسته‌کننده) : یه کلاس جدید به اسم UserResult می‌ساختی که دو تا فیلد firstName و lastName داشت. خیلی کد اضافه می‌خواد.

حالا تو زبان دارت مدرن، می‌تونی از Records استفاده کنی:

(String, String) getUserName() {
  return ('Ali', 'Rezayi');
}

void main() {
  var user = getUserName();

  print(user.$1); // Prints 'Ali'
  print(user.$2); // Prints 'Rezayi'
}

یا حتی بهتر :

({String firstName, String lastName}) getUserName() {
  return (firstName: 'Ali', lastName: 'Rezayi');
}

void main() {
  var user = getUserName();

  print(user.firstName); // Prints 'Ali'
  print(user.lastName);  // Prints 'Rezayi'
}

اینا آبجکت‌های ناشناس (Anonymous)، سبک‌وزن و تایپ-سیف هستن که همون لحظه ساخته می‌شن. این قابلیت که مستقیماً از زبان‌هایی مثل Swift و Go اومده، کدنویسی رو به شدت تمیز و سریع می‌کنه.

۹. تطبیق الگو (Pattern Matching) – سوئیچ روی استروئید!

اینم یه غول دیگه که با Dart 3 اومد. ما همه‌مون با دستور switch آشنایی داریم. یه switch ساده تو جاوا یا C، فقط می‌تونه روی مقادیر ثابت (مثل عدد، رشته یا enum) کار کنه. خیلی محدوده. زبان دارت حالا Pattern Matching داره. این یعنی switch تو دیگه یه ابزار ساده نیست، یه چاقوی جراحی لیزریه! تو می‌تونی switch رو روی ساختار آبجکت‌ها بزنی! ( تمام این چیزایی که گفتم، 0 تا 100 آموزشش توی پکیج دارت هست، جوری که یه بچه 7 ساله هم بتونه درک کنه برنامه نویسی و مفاهیمش رو )

فرض کن یه لیست داری:

void main() {
  var command = ['delete', 'user.txt'];

  switch (command) {
    case ['delete', var fileName]:
      print('Deleting $fileName...');
      break;

    case ['copy', var from, var to]:
      print('Copying $from to $to...');
      break;

    default:
      print('Unknown command');
  }
}

می‌بینی چی شد؟ switch داره ساختار لیست رو چک می‌کنه و همون‌جا متغیرها (fileName) رو از دلش می‌کشه بیرون (به این میگن Destructuring). یا حتی خفن‌تر، روی آبجکت‌ها:

sealed class Shape {}

class Circle implements Shape {
  final double radius;
  Circle(this.radius);
}

class Square implements Shape {
  final double side;
  Square(this.side);
}

void main() {
  Shape shape = Circle(10.5);

  switch (shape) {
    case Circle(radius: var r):
      print('This is a circle with radius $r');
      break;

    case Square(side: var s):
      print('This is a square with side $s');
      break;
  }
}

این قابلیت، کدهای if/else تو در تو و کثیف رو به یه switch تمیز و خوانا تبدیل می‌کنه. این ویژگی برای مدیریت State تو فلاتر flutter (مثلاً با BLoC) یه انقلاب مطلقه.

۱۰. کلمه کلیدی late – قول شرف برنامه‌نویسی!

این آخرین ویژگی «عجیب» ماست که دقیقاً برای حل یه مشکل اعصاب‌خردکن تو فلاتر flutter و سیستم Sound Null Safety به وجود اومد. مشکل این بود که تو Sound Null Safety، هر متغیری که null نباشه، باید همون لحظه که تعریف می‌شه یا تو سازنده (Constructor) مقداردهی بشه.

// This code will cause an ERROR in Sound Null Safety:

class MyWidget {
  
  // ERROR: The non-nullable field 'name' must be initialized.
  String name; 
  MyWidget();
}

خب، مشکل اینجاست که تو فلاتر، خیلی از متغیرها تو سازنده مقدار نمی‌گیرن، بلکه تو متد ()initState (که بعد از سازنده صدا زده می‌شه) مقدار می‌گیرن. مثلاً وقتی داری از دیتابیس چیزی رو می‌خونی. راه حل چی بود؟

راه ۱ (زشت) متغیر رو Nullable کنیم String? name که این کار کل فلسفه Null Safety رو زیر سوال می‌بره، چون حالا باید همه‌جا چک می‌کردی که name نال هست یا نه.

راه ۲ (جادویی) استفاده از کلمه کلیدی late :

// THE SOLUTION: Using the 'late' keyword

class MyWidget {

  late String name; 

  MyWidget();

  void loadDataFromServer() {
    name = "Data loaded successfully!";
  }

  void displayName() {
    print(name);
  }
}

کلمه late یه «قول شرف» به کامپایلره. تو بهش می‌گی: «داداش، می‌دونم الان مقدار نداره، ولی تو به من اعتماد کن. من قول می‌دم قبل از اینکه برای اولین بار ازش استفاده کنم، حتماً مقداردهیش می‌کنم.» کامپایلر هم می‌گه «باشه، قبوله». اینجوری name تو همچنان Non-Nullable و تمیز باقی می‌مونه. البته اگه قولتو بشکنی و زودتر ازش استفاده کنی، دارت یه خطای Runtime بهت می‌ده. این کلمه late یه ویژگی به ظاهر کوچیک، ولی به شدت حیاتی برای آموزش زبان دارت و فلاتره.

خب، اینم از ۱۰ ویژگی عجیب. حالا می‌بینی زبان دارت یه کپی ساده نیست. اینا ویژگی‌هاییه که نشون می‌ده خالقین زبان دارت نترسیدن که متفاوت باشن. اونا به جای کپی کردن، «انتخاب» کردن.

آینده برنامه نویسی دارت روشنه، چون زبانیه که برای «بهره‌وری» (Productivity) ساخته شده. این ویژگی‌ها، چه اونایی که سرعت توسعه رو مثل Hot Reload (به لطف JIT) زیاد می‌کنن، چه اونایی که سرعت اجرا رو مثل AOT تضمین می‌کنن، و چه اونایی که کد تو رو مثل Pattern Matching و Cascade Notation تمیز می‌کنن، همشون یه هدف دارن: اینکه تو به عنوان برنامه‌نویس، سریع‌تر، تمیزتر و با باگ کمتر، یه محصول خفن بسازی.

این ویژگی‌ها دقیقاً همون چیزایی هستن که فلاتر flutter رو انقدر قدرتمند کردن. فلاتر فقط یه UI کیت خوشگل نیست؛ یه غولیه که روی شونه‌های یه زبان برنامه‌نویسی فوق‌العاده هوشمند و مدرن وایساده.

اگه از خوندن این ویژگی‌ها به وجد اومدی و دوست داری این غول رو رام کنی، باید از پایه شروع کنی. آموزش دارت ما دقیقاً برای همینه. ما این زبان رو از صفرِ صفر، با همین دید عمیق و فنی بهت یاد می‌دیم تا برای ورود به دنیای فلاتر کاملاً آماده باشی.

امتیاز شما به مقاله

4.9 / 5. 42

42 رای 4.9
4.9
(42)
قوانین ارسال دیدگاه متوجه شدم
  • برای ثبت نظر، حتما اسم و فامیل خود را به فارسی وارد کنید.
  • حتما ایمیل صحیح را وارد کنید تا در صورت بررسی کارشناسان، پاسخ برای شما ایمیل شود.
  • داخل متن کامنت کدهای برنامه نویسی قرار ندهید.
2 نقد و بررسی‌ها
  • احسان
    احسان 29 اسفند 1402

    سلام لطفاً زبان سی پلاس پلاس رو هم جزو آموزش هاتون قرار بدید

    ( 0 )
  • پویش ترابی
    پویش ترابی 23 آذر 1402

    مثل همیشه عالی

    ( 0 )
+ ارسال دیدگاه به عنوان مهمان دیدگاه ارسال نمایید
سوالات متداول

نابغه‌ها را در   دنبال کنید