نجح إيفان أوفاديا، أحد المساهمين الأساسيين في Mojo ومهندس جوجل السابق ومبتكر لغة Valen، في إنجاز عمل تجريبي يربط لغات البرمجة الجديدة بلغة Rust. يهدف هذا العمل إلى تمكين تمرير أنواع البيانات والوظائف العامة (generics) بين Rust واللغات الأخرى، وهو ما لا تدعمه واجهة C ABI. وصف أوفاديا عمله بأنه "Golden Spike" الذي يربط لغتين مختلفتين.
يُعد هذا الإنجاز انتصارًا تقنيًا كبيرًا، حيث يتيح لمكتبات البرمجة الغنية بالقدرات الانتقال بسرعة إلى بيئات برمجية أخرى دون الحاجة إلى التجريد إلى أنواع بيانات بدائية فقط لتناسب قيود C ABI. قال مضيف قناة Let’s Get Rusty على يوتيوب إن هذا العمل "من الناحية التقنية، هو الشيء الأكثر إثارة للاهتمام الذي قرأته منذ أشهر"، واصفًا إياه بـ "Rust++".
ما هي مشكلة C ABI مع الـ Generics؟
جاء هذا العمل في إطار سعي أوفاديا لإنشاء لغته الخاصة، Valen (وهي فرع من جهد سابق يسمى Vale)، والتي يتصورها نسخة أسرع وأكثر ملاءمة للمطورين من Rust. كانت المشكلة التي واجهها في إنشاء لغة جديدة من الصفر هي عدم قدرته على استخدام مكتبات Rust المفضلة لديه، مثل مكتبة الرسومات wgpu.
تتمثل الطريقة الشائعة حاليًا لاستخدام مكتبة من لغة ما في برنامج مكتوب بلغة أخرى في استخدام C ABI (واجهة التطبيق الثنائية)، وهي طبقة تشغيل بيني فعلية تحدد اتفاقيات تمرير البيانات واستدعاءات الوظائف بين التعليمات البرمجية المترجمة. تمتلك Rust واجهة ABI خاصة بها، لكنها لا تقدم ضمانات استقرار.
مع C ABI، إذا كانت مكتبة Rust تعرض وظائفها كـ extern "C" وأنواعها كـ repr(C)، فيمكن الوصول إليها من لغة أخرى باستخدام واجهة الوظائف الأجنبية (FFI). لكن المشكلة التي واجهها أوفاديا هي أن C ABI لا تفهم مفهوم الـ generics (أو العناصر النائبة لأنواع البيانات التي سيتم توفيرها لاحقًا)، لأن لغة C نفسها لا تفهم هذا المفهوم. ومع ذلك، تستخدم Rust الـ generics كثيرًا، وكذلك Valen، وإن لم يكن بنفس الطريقة. كتب أوفاديا: "لذا فإن السؤال المحوري، اللغز الأساسي الذي يجب حله، هو كيف نفعل الـ generics عبر اللغات؟"
كيف حقق أوفاديا الربط بين اللغات؟
يُعد جعل مترجمين يتعاونان أمرًا بالغ الصعوبة، حيث تميل المترجمات إلى أن تكون كيانات معزولة، ملوكًا منفردين لعوالمهم الخاصة. لذلك، احتاج أوفاديا إلى طريقة لتمكين Valen من استدعاء دالة Rust عامة، وأيضًا أن يكون لديه دالة Rust عامة تستدعي Valen مرة أخرى للحصول على القيم المطلوبة.
بعد الكثير من التفكير، توصل أوفاديا إلى حل من جزأين للـ generics عبر اللغات: أولاً، تشغيل مترجم Rust كمكتبة. تمتلك Rust بالفعل هذه القدرة (rustc_driver)، مما يسمح لـ Valen بتضمين rustc مباشرة في مساحة الذاكرة الخاصة بها. الخطوة الثانية ستكون تعديل Rust بحيث عندما تواجه أنواع Valen غير التابعة لـ Rust، فإنها تسلم التحكم إلى مترجم Valen للتعامل مع الجزء الخاص به، وتنتظر النتيجة المترجمة.
يقر أوفاديا بأن تعديل مترجم Rust كان "الخيار النووي". كتب: "بصراحة، كان هذا الجزء الأكثر خطورة في المسعى بأكمله". يبلغ حجم التعديل نفسه حوالي 100 سطر من التعليمات البرمجية فقط، لكنه يعتمد على حيل برمجية ويفترض أن Rust تستخدم LLVM لتوليد التعليمات البرمجية للآلة، وهو ما ليس هو الحال دائمًا. كتب أوفاديا: "إنه يعمل، لكنه بالتأكيد لا يمكن دمجه في المصدر الرئيسي".
على الرغم من ذلك، تُعد الـ generics ثنائية الاتجاه وعبر اللغات التي ابتكرها أوفاديا خطوة حقيقية إلى الأمام في قابلية التشغيل البيني للغات البرمجة. يركز أوفاديا حاليًا على Valen، لكن عمله في الـ generics عبر اللغات يفتح إمكانية استخدام Rust لإنشاء لغات جديدة أخرى يمكن بناؤها من مكتبات Rust. مع بعض التعديلات على Rust نفسها، قد يصبح الاعتماد على C ABI القديمة شيئًا من الماضي يومًا ما.
في منتديات المبرمجين على Reddit و Lobste.rs، أشاد المراقبون بأوفاديا لمعالجته مشكلة صعبة كهذه، حتى مع قلقهم بشأن التفاصيل. كتب أحد المعلقين: "أقدر هذه الخطوة لاستبدال C كلغة FFI عالمية. إنه خيار جريء للغاية وسيتطلب جهدًا". وعلق قارئ آخر بأن Rust قد لا تكون اللغة المثالية للتشغيل البيني، نظرًا لقيود نظام أنواعها الخاص. كتب القارئ نفسه: "ومع ذلك، تخيل لو كان بإمكانك بناء روابط فوق Ada! سيكون ذلك مذهلاً".
جرّب الأداة: منسق ومتحقق JSON




