مطوّر Kotlin يتعلم Dart
نظرة مطوّر Android إلى لغة Dart.

قررت أن أدرس Flutter، وبدأت أتابع دروس App brewery في الدورة المسماة "The Introduction to Flutter Development with Dart". وبعد أن أنهيت جزء التثبيت، رأيت أنني سأتقدم أسرع إذا فهمت صياغة Dart قبل متابعة بقية الدروس. سأركّز في هذا المقال على اللغة وصياغتها. يقول فريق تطوير Dart إن هذه اللغة مُحسَّنة لبناء واجهات المستخدم، لكنني لن أتعمق في المترجم (compiler) وطبقاته الداخلية، لأنني لم أدرس Dart بما يكفي للحديث عن ذلك بعد.
الصياغة
كنت أطوّر تطبيقات Android بلغة Java قبل عدة سنوات، وأستخدم اليوم Kotlin لغةً رئيسية. لذلك أشعر بألفة كبيرة مع الصياغة. وفي رأيي تبدو Dart أقرب إلى Java منها إلى Kotlin، فأسلوب صياغتها يقع في مكان ما بين اللغتين. فلا يزال عليكم وضع الفاصلة المنقوطة في الكود، وهذا لا يزعجني كثيرًا.
ما ينقص Dart مقارنةً بـ Kotlin
أظن أن الوقت الحالي مناسب لتعلم Dart أكثر مما كان قبل عدة سنوات. فالإصدار الحالي من Dart هو 2.8، وقد تحسّن كثيرًا عن الإصدار 1.x، ومن ذلك إضافة extension methods. ومع أن ميزة null safety غير موجودة في الإصدار 2.8، فإنها باتت قريبة. وإليكم بعض ما في Kotlin ولا يوجد في Dart 2.8.
- لا توجد أنواع آمنة من القيم الفارغة (null-safe types): في Kotlin نستخدم
?لتحديد ما إذا كان المتغير يقبل القيمة null أم لا. أما حاليًا في Dart فتحتاجون إلى جهد إضافي للتحقق من القيم الفارغة عند التعامل مع أي متغير. لكن كما ذكرت، أوشكت ميزة null-safe types على الصدور، ويُتوقع أن تُضاف خلال الإصدارات القليلة القادمة. - غياب data classes: في Dart، حين تتعاملون مع أصناف الـ model، تحتاجون إلى إعادة تعريف equals وtoString وhashcode بأنفسكم، بخلاف Kotlin حيث تتولى data class ذلك تلقائيًا.
- Sealed classes: هذه ميزة رائعة في لغة Kotlin، إذ يمكنكم حصر الأنواع المسموح بها داخل الصنف. إنها أشبه بصنف enum يملك قوى خارقة. وإذا استخدمتموها فستلاحظون كم هي عملية. لكنكم تفقدون هذه الميزة حين تنتقلون إلى Dart.
ومقارنة Dart بـ Kotlin نقطةً بنقطة لن تكون منصفة، فـ Dart لا تحاول أن تكون Kotlin 2، وكل ما أريده هو التعبير عن أفكاري من منظور مطوّر Kotlin.
أمثلة من اللغة
سأتناول في هذا القسم القواعد البسيطة للغة Dart من منظور مطوّر Kotlin. ولن أتطرق إلى عبارات التحكم في التدفق مثل if وfor وwhile، لأنها تشبه عبارات التحكم المعتادة.
المتغيراتمثل Kotlin، تتميز Dart بأمان الأنواع (type-safe). وتدعم Dart استنتاج النوع (type inference)، فلا يحتاج المتغير إلى تصريح صريح بنوعه. ولتعريف متغير يُستنتج نوعه تلقائيًا استخدموا var.
var platform = 'Android';
ويمكن أن يكون المتغير في Dart من النوع الديناميكي. ولتعريف متغير ديناميكي استخدموا الكلمة المفتاحية dynamic.
dynamic platform = 'Android';
ويمكنكم أيضًا تحديد النوع صراحةً.
String platform = 'Android';
ولا يوجد في Dart مفهوم val وvar كما في Kotlin. ولإنشاء متغير لا يتغير استخدموا الكلمتين المفتاحيتين const أو final.
final platform = 'Android';
const version = '1.0';
ويمكن استخدام الكلمة المفتاحية const أيضًا لتعريف قيمة ثابتة.
var array = const []
محددات الوصول (Visibility Modifier)
بخلاف Java وKotlin، لا تحتوي Dart على الكلمات المفتاحية public وprotected وprivate. ولتعريف متغير خاص (private) استخدموا الشرطة السفلية (_) كبادئة لاسم المتغير.
الدوال
تشبه الدوال في Dart دوال Java كثيرًا، لكن يمكنكم حذف نوع القيمة المُعادة.
bool isAndroidVersion(String atomicNumber) { return _androidVersions[atomicNumber] != null;}
isAndroidVersion(String atomicNumber) { return _androidVersions[atomicNumber] != null;}
وتدعم الدوال في Dart المعاملات الاختيارية والقيم الافتراضية للمعاملات. ويمكنكم الاطلاع على الصياغة هنا. Lambda
تدعم Dart أيضًا تمرير الدوال المجهولة (anonymous functions) كمعاملات. ومقارنةً بـ Kotlin، تتغير الصياغة المختصرة من -> إلى =>.
var androidVerions = ['Cupcake', 'Donut', 'Eclair', 'Froyo', 'Gingerbread', 'Honeycomb', 'Ice Cream Sandwich', 'Jelly Bean', 'Kitkat', 'Lollipop', 'Marshmallow'];
androidVersions.where((name) => name.contains('lol')).forEach(print);
الأصناف (Classes)
كل صنف في Dart هو نسخة من Object. ولا يوجد فرق كبير بين الأصناف في لغات البرمجة كائنية التوجه الأخرى والأصناف في Dart. والشيء الوحيد الجديد عليّ في Dart هو الـ constructor المسمّى (named constructor). ففي Kotlin نستخدم عادةً الـ constructor الأساسي، ونادرًا ما نستخدم الـ constructor الثانوي. أما في Dart فيمكننا كتابة عدة constructors ومنح كل منها اسمًا.
class Point {
double x, y;
Point(this.x, this.y);
// Named constructor
Point.origin() {
x = 0;
y = 0;
}
}
Extension methods
كما في extension function في Kotlin، توجد في Dart extension methods. ويمكن القول إنكم ما إن تبدأوا باستخدام extension functions في Kotlin حتى لا تستطيعوا الاستغناء عنها، ولكان من المؤسف ألا تتوفر هذه الميزة في Dart. وتختلف طريقة تعريف extension method قليلًا عن Kotlin. وإليكم مثالًا مأخوذًا من الموقع الرسمي.
extension NumberParsing on String {
int parseInt() {
return int.parse(this);
}
double parseDouble() {
return double.parse(this);
}
}
الخلاصة
هذا ملخص مقارنتي بين Dart وKotlin. قد لا يغطي كل النقاط، لكنني حاولت فقط أن أشير إلى أول ما خطر في بالي حين بدأت أتعرّف على صياغة Dart. ولم أتناول البرمجة غير المتزامنة (asynchronous programming) في Dart، لأنها تستحق مقالًا مستقلًا في المستقبل. وأظن أنني أستطيع العمل بلغة Dart بإنتاجية جيدة بعد هذه الجولة السريعة في اللغة.
المصادر
- https://dart.dev/guides/language/language-tour#classes - https://dart.dev/samples


