لذا ، سأحاول المجادلة ضد روست.
ليست كل البرمجة منهجية
الصدأ هي لغة برمجة أنظمة. يوفر تحكمًا دقيقًا في تكوين البيانات وسلوك تنفيذ التعليمات البرمجية في وقت التشغيل لتحقيق أقصى قدر من الأداء والمرونة. على عكس لغات برمجة الأنظمة الأخرى ، فإنه يوفر أيضًا أمان الذاكرة - تنتهي برامج عربات التي تجرها الدواب بطريقة محددة جيدًا ، مما يمنع (يحتمل أن يكون خطيرًا) السلوك غير المحدد.
ومع ذلك ، في معظم الحالات ، الأداء المطلق أو التحكم في موارد الأجهزة غير مطلوب. في هذه المواقف ، توفر اللغات المُدارة الحديثة مثل Kotlin أو Go سرعة مناسبة وأداء يحسد عليه وأمان الذاكرة من خلال استخدام أداة تجميع البيانات المهملة للذاكرة المُدارة ديناميكيًا.
تعقيد
وقت المبرمج مكلف ، وفي حالة Rust ، عليك قضاء الكثير من الوقت في تعلم اللغة نفسها. لقد عمل المجتمع بجد لإنشاء مواد تعليمية عالية الجودة ، لكن اللغة كبيرة جدًا. حتى لو كان من المفيد لك إعادة كتابة المشروع في Rust ، فإن تعلم اللغة نفسها قد يكون مكلفًا للغاية.
ثمن تحسين التحكم هو لعنة الاختيار:
struct Foo { bar: Bar }
struct Foo<'a> { bar: &'a Bar }
struct Foo<'a> { bar: &'a mut Bar }
struct Foo { bar: Box<Bar> }
struct Foo { bar: Rc<Bar> }
struct Foo { bar: Arc<Bar> }
في Kotlin ، تقوم بكتابة فصل
Foo(val bar: Bar)دراسي وتبدأ في حل مشكلة ما. في Rust ، عليك أن تقوم باختيارات ، وأحيانًا تكون مهمة ، بتركيبة خاصة.
كل هذا التعقيد لسبب ما - فنحن لا نعرف كيفية إنشاء لغة منخفضة المستوى أبسط وأكثر أمانًا للذاكرة. لكن ليست كل مهمة تحتاج إلى لغة منخفضة المستوى.
انظر أيضًا العرض التقديمي لماذا تحافظ C ++ على قدميها عندما غرقت Vaza .
وقت التجميع
وقت التجميع هو عامل عالمي. إذا كان تشغيل أحد البرامج بلغة ما بطيئًا ، لكن هذه اللغة تسمح بالتجميع السريع ، فسيكون لدى المبرمج مزيد من الوقت للتحسين لتسريع بدء تشغيل البرنامج!
في معضلة الأدوية الجنيسة ، اختار Rust عمداً المترجمين البطيئين. هذا منطقي إلى حد ما (وقت التشغيل يتسارع حقًا) ، لكن سيتعين عليك القتال بجد للحصول على أوقات بناء معقولة في مشاريع أكبر.
rustcيطبق على الأرجح خوارزمية التجميع الأكثر تقدمًا في مجمعي الإنتاج ، ولكنه يشبه إلى حد ما محاربة نموذج الترجمة المدمج في اللغة.
على عكس C ++ ، لا يتوازى تجميع الصدأ مع الحد الأقصى ، ويقتصر عدد العمليات المتوازية على طول المسار الحرج في الرسم البياني للتبعية. سيكون الفرق ملحوظًا إذا كان لديك أكثر من 40 مركزًا لتجميعها.
في Rust ، لا توجد أيضًا نظائر لمصطلح pimpl ، لذا فإن تغيير الصندوق يتطلب إعادة تجميع (وليس فقط ربط) جميع تبعياته العكسية.
النضج
خمس سنوات هي بالتأكيد فترة قصيرة ، لذا فإن روست لغة شابة. بينما يبدو المستقبل مشرقًا ، فمن المرجح أنه في غضون عشر سنوات سنقوم بالبرمجة بلغة C بدلاً من Rust (انظر تأثير Lindy ). إذا كنت تكتب برنامجًا منذ عقود ، فعليك التفكير بجدية في مخاطر اختيار التقنيات الجديدة (على الرغم من أن اختيار Java على Cobol للبرامج المصرفية في التسعينيات اتضح أنه الاختيار الصحيح في وقت لاحق).
لا يوجد سوى تطبيق واحد كامل لـ Rust ، مترجم rustc . الأكثر تقدما تطبيق mrustc البديليتخطى عمدا العديد من فحوصات الأمان الثابتة. يدعم rustc حاليًا خلفية واحدة جاهزة للإنتاج فقط ، LLVM. وبالتالي ، فإن دعم معماريات المعالجات هنا أضيق من C ، والتي لها تطبيق دول مجلس التعاون الخليجي ، فضلاً عن دعمها لعدد من المجمعين الخاصين ببائعين.
أخيرًا ، لا يوجد لدى Rust مواصفات رسمية. المواصفات الحالية غير كاملة ولا توثق بعض تفاصيل التنفيذ البسيطة.
البدائل
إلى جانب Rust ، هناك لغات أخرى لبرمجة الأنظمة ، بما في ذلك C و C ++ و Ada.
يوفر الحديثة C ++ أدوات و مبادئ توجيهية لتحسين الأمن. حتى أن هناك اقتراح أمان مدى الحياة لكائن من طراز الصدأ! على عكس Rust ، لا يضمن استخدام هذه الأدوات عدم وجود مشكلات تتعلق بأمان الذاكرة. ولكن إذا كنت تدعم بالفعل كمية كبيرة من كود C ++ ، فمن المنطقي التحقق ، ربما اتباع التوصيات واستخدام المطهرات سيساعد في حل مشاكل الأمان. هذا صعب ، لكن من الواضح أنه أسهل من إعادة كتابة كل التعليمات البرمجية بلغة أخرى!
إذا كنت تستخدم لغة C ، فيمكنك تطبيق طرق رسمية للإثباتلا يوجد سلوك غير محدد ، أو مجرد اختبار شامل لكل شيء .
Ada هي ذاكرة آمنة ما لم تستخدم ذاكرة ديناميكية (لا تتصل أبدًا
free).
Rust هي لغة مثيرة للاهتمام من حيث التكلفة إلى الأمان ، ولكنها ليست اللغة الوحيدة!
مجموعة من الأدوات
أدوات Rust ليست مثالية. غالبًا ما يشار إلى مجموعة الأدوات الأساسية والمترجم ونظام البناء ( البضائع ) على أنها الأفضل في فئتها.
ولكن ، على سبيل المثال ، بعض الأدوات المتعلقة بوقت التشغيل (بشكل أساسي للتنميط الكومة) مفقودة ببساطة - من الصعب التفكير في وقت التشغيل إذا لم تكن الأداة موجودة! بالإضافة إلى ذلك ، فإن دعم IDE أقل بكثير من مستوى موثوقية Java. إعادة هيكلة معقدة آليًا لبرنامج بملايين الأسطر غير ممكن في Rust.
دمج
مهما كانت وعود Rust ، فإن عالم برمجة الأنظمة اليوم يتحدث بلغة C و C ++. لا يحاول Rust عن قصد تقليد هذه اللغات - فهو لا يستخدم فئات على غرار C ++ أو C ABI.
هذا يعني أنه يجب بناء الجسور بين العالمين. لن يكون التكامل سلسًا وغير آمن ولن يكون دائمًا فعالًا من حيث التكلفة ويتطلب التزامن بين اللغات. بينما يعمل التكامل في أماكن و أدوات و تتقارب، هناك عقبات في بعض الأحيان على طول الطريق نظرا لتعقيد العام.
تتمثل إحدى المشكلات المحددة في أن رؤية Cargo للعالم (رائعة لمشاريع Rust الخالصة) يمكن أن تجعل من الصعب التكامل مع أنظمة البناء الأكبر.
أداء
لا يعد "استخدام LLVM" حلاً واحدًا يناسب الجميع لجميع مشكلات الأداء. على الرغم من أنني لا أعرف المعايير التي تقارن أداء C ++ و Rust بشكل عام ، فليس من الصعب التفكير في المهام التي يكون فيها Rust أدنى من C ++.
ربما تكون المشكلة الأكبر هي أن دلالات حركة Rust تعتمد على القيمة (
memcpyعلى مستوى رمز الآلة). من ناحية أخرى ، تستخدم دلالات C ++ مراجع خاصة يمكن أخذ البيانات منها (مؤشرات على مستوى رمز الجهاز). من الناحية النظرية، ينبغي للمترجم رؤية سلسلة من النسخ، في الواقع هذا هو في كثير من الأحيان ليس كذلك: # 57077 . هناك مشكلة ذات صلة وهي عدم تخصيص بيانات جديدة - يحتاج Rust أحيانًا إلى نسخ البايت إلى / من المكدس ، بينما يمكن لـ C ++ إنشاء كائن في مكانه.
من المضحك أن Rust ABI الافتراضي (الذي ضحى بالاستقرار من أجل الكفاءة) يؤدي أحيانًا إلى أداء أسوأ من C: # 26494 .
أخيرًا ، بينما من الناحية النظرية ، يجب أن يكون كود Rust أكثر كفاءة نظرًا للمعلومات الأكثر ثراءً حول الأسماء المستعارة ، فإن تمكين التحسينات المتعلقة بالاسم المستعار يتسبب في حدوث أخطاء LLVM وتجميع غير صحيح: # 54878 .
لكن ، مرة أخرى ، هذه أمثلة نادرة ، وأحيانًا تكون المقارنة في الاتجاه الآخر. على سبيل المثال ، في
BoxRust لا توجد مشاكل في الأداء ، والتي لها في std::unique_ptr.
من المحتمل أن تكون المشكلة الأكبر هي أن Rust ، مع تعريفاتها العامة ، أقل تعبيرًا من C ++. إذن بعض الحيل التقليدية لا يمكن التعبير عن C ++ للأداء العالي في Rust مع بناء جملة جيد.
قيمة غير آمنة
ربما تكون الفكرة
unsafeأكثر أهمية لصدأ من الملكية والاقتراض. من خلال فصل جميع العمليات الخطرة إلى كتل unsafeووظائف والإصرار على تزويدها بواجهة آمنة ذات مستوى أعلى ، من الممكن إنشاء نظام يقوم في نفس الوقت بما يلي:
- موثوق (
unsafeلا يمكن أن يتسبب الرمز غير المحدد في سلوك غير محدد) ،
- معياري (يمكن اختبار الكتل غير الآمنة المختلفة بشكل منفصل).
من الواضح تمامًا أن هذا هو الحال: يتسبب الغموض في رمز Rust في الذعر ، ولكن ليس فيضان المخزن المؤقت.
لكن الآفاق النظرية ليست مشرقة.
أولاً ، لا يوجد تعريف لنموذج ذاكرة Rust ، لذلك من المستحيل التحقق رسميًا مما إذا كانت كتلة غير آمنة معينة صالحة أم لا. هناك تعريف غير رسمي لـ "الأشياء التي يمكن أن يقوم بها rustc أو يمكن الاعتماد عليها" والعمل جارٍ على أداة التحقق من وقت التشغيل ، لكن النموذج الفعلي غير واضح. وبالتالي ، قد يكون هناك بعض التعليمات البرمجية غير الآمنة التي تعمل بشكل جيد في مكان ما اليوم ، ولكن سيتم الإعلان عنها بأنها غير صالحة غدًا وتكسر تحسين مترجم جديد في غضون عام.
ثانيا، يُعتقد أن الكتل غير الآمنة ليست وحدات في الواقع. في الواقع ، يمكن للكتل القوية غير الآمنة أن توسع اللغة. لا يؤدي هذان الملحقان إلى أي خطأ بمعزل عن بعضهما البعض ، لكنهما يؤديان إلى سلوك غير محدد عند استخدامه في نفس الوقت:
أخيرًا ، هناك أخطاء واضحة في المترجم .
فيما يلي بعض الموضوعات التي حذفتها عمدًا:
- علم الاقتصاد ("من الصعب العثور على مبرمجي الصدأ") - أعتقد أن قسم "النضج" يعكس جوهر هذا السؤال ، والذي لا يقتصر على مشكلة الدجاج والبيض.
- التبعيات ("stdlib صغير جدًا / الكثير من التبعيات في كل مكان") - نظرًا لمدى جودة Cargo والأجزاء ذات الصلة من اللغة ، فأنا شخصياً لا أرى هذا على أنه مشكلة.
- الارتباط الديناميكي ("يجب أن يكون لدى Rust قيمة ABI مستقرة") - لا أعتقد أن هذه حجة قوية. لا يتوافق التمثيل الكوني بشكل أساسي مع الارتباط الديناميكي ، وإذا كنت بحاجة فعلاً إلى ذلك ، فهناك C ABI. أعتقد حقًا أنه يمكن تحسين الأشياء هنا ، لكن من غير المحتمل أننا نتحدث عن تغييرات محددة في Rust .
موضوع المناقشة في / r / rust .