Design: call_indirect مقابل التجريد

تم إنشاؤها على ٧ مايو ٢٠٢٠  ·  36تعليقات  ·  مصدر: WebAssembly/design

call_indirect ميزة مفيدة جدًا لـ WebAssembly. ومع ذلك ، فقد اعتمدت الكفاءة والسلوك الجيد للتعليمات ضمنيًا على بساطة نظام نوع الوسم. على وجه الخصوص ، كل قيمة wasm لها نوع واحد (ثابت) بالضبط تنتمي إليه. تتجنب هذه الخاصية بشكل ملائم عددًا من المشكلات المعروفة المتعلقة باستدعاءات الوظائف غير المطبوعة في اللغات المكتوبة. ولكن الآن هذا الوسم يمتد إلى ما وراء الأنواع الرقمية ، فقد وصل إلى النقطة التي نحتاج فيها إلى فهم هذه المشكلات ووضعها في الاعتبار.

call_indirect أساسي من خلال مقارنة توقيع المتصل المتوقع بالتوقيع المحدد للمستدعي. باستخدام الأنواع الرقمية فقط ، كان لدى WebAssembly الخاصية التي تفيد بأن هذه التوقيعات متساوية إذا وفقط إذا تم فحص نوع الاتصال المباشر بالدالة المشار إليها بواسطة funcref المقابل. لكن هناك سببان لن يكونا صحيحين قريبًا:

  1. مع التصنيف الفرعي ، يعمل الاستدعاء المباشر طالما أن التوقيع المحدد للوظيفة الفعلية هو "توقيع فرعي" للتوقيع المتوقع ، مما يعني أن جميع أنواع المدخلات هي أنواع فرعية من أنواع معلمات الوظيفة وجميع أنواع المخرجات هي أنواع فائقة من الدالة أنواع النتائج. هذا يعني أن فحص المساواة بين التوقيع المتوقع لمكالمة غير مباشرة والتوقيع المحدد للوظيفة من شأنه أن يعلق في عدد من المواقف الآمنة تمامًا ، والتي قد تكون مشكلة بالنسبة للغات الداعمة ذات الاستخدام المكثف للمكالمات الفرعية والمكالمات غير المباشرة (كما تم طرحه أثناء المناقشة في تأجيل التصنيف الفرعي). هذا يعني أيضًا أنه إذا قامت الوحدة النمطية بتصدير وظيفة عن قصد بتوقيع أضعف مما تم تحديد الوظيفة به ، فيمكن استخدام call_indirect للوصول إلى الوظيفة بتوقيعها الخاص المحدد بدلاً من مجرد توقيعها العام الأضعف ( قضية تم اكتشافها للتو وبالتالي لم تتم مناقشتها بعد).
  2. مع استيراد النوع ، يمكن للوحدة النمطية تصدير نوع دون تصدير تعريف هذا النوع ، مما يوفر التجريد الذي تخطط أنظمة مثل WASI للاعتماد عليه بشكل كبير. يمنع هذا التجريد الوحدات الأخرى من الاعتماد على تعريفها الخاص في وقت الترجمة . ولكن في وقت التشغيل ، يتم استبدال النوع المُصدَّر الملخص ببساطة بتعريفه. هذا مهم ، على سبيل المثال ، لتمكين call_indirect من العمل بشكل صحيح على الوظائف المصدرة التي تشير توقيعاتها المصدرة إلى ذلك النوع الذي تم تصديره. ومع ذلك ، إذا كانت الوحدة النمطية الخبيثة تعرف تعريف هذا النوع الذي تم تصديره ، فيمكنها استخدام call_indirect للتحويل ذهابًا وإيابًا بين النوع المُصدَّر والتعريف المقصود أن يكون سرًا لأن call_indirect يقارن . وبالتالي يمكن للوحدة الخبيثة استخدام call_indirect للوصول إلى الأسرار التي من المفترض أن يتم استخلاصها بواسطة النوع المُصدَّر ، ويمكنها استخدام call_indirect لتزوير قيم من النوع المُصدَّر والتي قد تنتهك ثوابت الأمان الحرجة التي لم يتم التقاطها في تعريف النوع نفسه.

في كلتا الحالتين المذكورتين أعلاه ، يمكن استخدام call_indirect لتجاوز استخلاص التوقيع المُصدَّر للوحدة النمطية. كما ذكرت ، لم يكن هذا مصدر قلق حتى الآن لأن wasm كان لديه فقط أنواع رقمية. وفي الأصل اعتقدت أنه من خلال تأجيل التصنيف الفرعي ، تم أيضًا تأجيل جميع المخاوف المتعلقة بـ call_indirect بشكل فعال. ولكن ما أدركته مؤخرًا هو أنه من خلال إزالة التصنيف الفرعي ، فإن النوع "الجديد" (المسمى externref في https://github.com/WebAssembly/reference-types/pull/87) يعد بديلًا فعليًا لاستيراد نوع الملخص. إذا كان هذا هو ما يريده الناس بالفعل ، فلسوء الحظ نحتاج إلى أن نأخذ في الاعتبار التفاعل أعلاه بين call_indirect واكتب عمليات الاستيراد.

يوجد الآن العديد من الطرق المحتملة لمعالجة المشكلات المذكورة أعلاه باستخدام call_indirect ، لكن لكل منها مقايضاته ، وهي ببساطة مساحة تصميم كبيرة جدًا بحيث لا يمكن اتخاذ قرار بشأنها بسرعة. لذا فأنا لا أقترح أن نحل هذه المشكلة هنا والآن. بدلاً من ذلك ، فإن القرار الذي يجب اتخاذه في الوقت الحالي هو شراء الوقت لحل المشكلة بشكل صحيح فيما يتعلق بـ externref . على وجه الخصوص ، إذا قمنا في الوقت الحالي بتقييد call_indirect و func.ref للتحقق من الكتابة فقط عندما يكون التوقيع المرتبط رقميًا بالكامل ، فإننا نخدم جميع حالات الاستخدام الأساسية للمكالمات غير المباشرة وفي في نفس الوقت اترك مساحة لجميع الحلول المحتملة للقضايا المذكورة أعلاه. ومع ذلك ، لا أعرف ما إذا كان هذا التقييد عمليًا ، سواء من حيث جهود التنفيذ أو من حيث ما إذا كان يعيق تطبيقات externref التي ينتظرها الأشخاص. البديل هو ترك call_indirect و func.ref كما هو. من المحتمل فقط أن هذا يعني أنه ، اعتمادًا على الحل الذي توصلنا إليه ، قد لا يكون externref قابلاً للتكرار مثل استيراد النوع الحقيقي ، و / أو أن externref ربما (من المفارقات) لا تكون قادرًا على الحصول على أي أنواع فائقة (على سبيل المثال ، قد لا تكون قادرًا على أن تكون نوعًا فرعيًا من anyref إذا قررنا في النهاية إضافة anyref ).

أنا ، أتحدث عن نفسي فقط ، أعتبر كلا الخيارين قابلين للإدارة. على الرغم من أنني أملك تفضيلًا ، إلا أنني لا أدفع بقوة القرار للذهاب في اتجاه أو آخر ، وأعتقد أن لديكم وصولاً أفضل إلى المعلومات اللازمة للتوصل إلى قرار مستنير. أردت فقط أن تعرفوا جميعًا أن هناك قرارًا يتعين اتخاذه ، وفي نفس الوقت أردت إنشاء وعي بالمشكلة الشاملة باستخدام call_indirect . إذا كنت ترغب في الحصول على شرح أكثر شمولاً لهذه المشكلة مما يوفره الملخص أعلاه ، فيرجى قراءة ما يلي.

call_indirect مقابل التجريد بالتفصيل

سأستخدم الترميز call_indirect[ti*->to*](func, args) ، حيث [ti*] -> [to*] هو التوقيع المتوقع للوظيفة ، func هو ببساطة funcref (بدلاً من جدول funcref وفهرس) ، و args هي قيم to* لتمريرها إلى الوظيفة. وبالمثل ، سأستخدم call($foo, args) لاستدعاء مباشر للوظيفة مع وسيطات تمرير الفهرس $foo args .

لنفترض الآن أن $foo هو فهرس دالة مع أنواع المدخلات المعلنة ti* وأنواع المخرجات to* . قد تتوقع أن call_indirect[ti*->to*](ref.func($foo), args) يعادل call($foo, args) . في الواقع ، هذا هو الحال الآن. لكن ليس من الواضح أنه يمكننا الحفاظ على هذا السلوك.

call_indirect والترتيب الفرعي

ظهر أحد الأمثلة على مشكلة محتملة في مناقشة التصنيف الفرعي. افترض ما يلي:

  • tsub هو نوع فرعي من tsuper
  • يقوم مثيل الوحدة النمطية IA بتصدير دالة $fsub تم تعريفها بالنوع [] -> [tsub]
  • وحدة MB تستورد دالة $fsuper النوع [] -> [tsuper]
  • مثيل الوحدة النمطية IB هو وحدة ميغابايت تم إنشاؤها باستخدام IA $fsub كـ $fsuper (وهو ما يجب القيام به - حتى لو لم يكن ذلك ممكنًا الآن ، فهذه المشكلة تتعلق بالمشكلات القادمة المحتملة)

فكر الآن فيما يجب أن يحدث إذا نفذ الوسيط المعرف call_indirect[ -> tsuper](ref.func($fsuper)) . فيما يلي النتيجتان اللتان تبدوان أكثر معقولية:

  1. نجح الاستدعاء لأن التوقيع المتوقع والتوقيع المعرّف متوافقان.
  2. فخ الاستدعاء لأن التوقيعين مختلفان.

إذا أردنا اختيار النتيجة 1 ، فعلينا أن ندرك أننا سنحتاج على الأرجح إلى استخدام إحدى الطريقتين لجعل ذلك ممكنًا:

  1. بالنسبة للوظائف المستوردة ، قارن بين call_indirect مع توقيع الاستيراد بدلاً من توقيع التعريف.
  2. قم بإجراء فحص وقت التشغيل الخطي على الأقل للتأكد من توافق النوع الفرعي للتوقيع المتوقع وتوقيع التعريف.

إذا كنت تفضل الأسلوب 1 ، فعليك إدراك أنه لن يعمل بمجرد إضافة مراجع الوظيفة المكتوبة (مع نوع فرعي متغير). أي أن func.ref($fsub) سيكون ref ([] -> [tsub]) وأيضًا ref ([] -> [tsuper]) ، ومع ذلك لن تكون التقنية 1 كافية لمنع call_indirect[ -> super](ref.func($fsub)) من الاصطياد. هذا يعني أن النتيجة 1 تتطلب على الأرجح تقنية 2 ، والتي لها آثار متعلقة بالأداء.

لذلك دعونا ننظر إلى النتيجة 2 أكثر قليلاً. تتمثل تقنية التنفيذ هنا في التحقق مما إذا كان التوقيع المتوقع لـ call_indirect في IB يساوي توقيع تعريف $fsub في IA. في البداية ، قد يبدو أن الجانب السلبي الرئيسي لهذه التقنية هو أنها تحاصر عددًا من المكالمات التي يمكن تنفيذها بأمان. ومع ذلك ، هناك جانب سلبي آخر وهو أنه من المحتمل أن يؤدي إلى تسرب أمني لـ IA.

لنرى كيف، دعونا التبديل حتى مثالنا قليلا ونفترض أنه على الرغم المثال IA يحدد داخليا $fsub لديها اكتب [] -> [tsub] مثيل IA تصدر فقط مع نوع [] -> [tsuper] . باستخدام تقنية النتيجة 2 ، يمكن لـ IB المثيل (بشكل ضار) تنفيذ call_indirect[ -> tsub]($fsuper) وستنجح المكالمة. أي ، يمكن لـ IB استخدام call_indirect للتحايل على تضييق IA لتوقيع وظيفته. في أحسن الأحوال ، هذا يعني أن الوسيط المعرف (IB) يعتمد على جانب من جوانب IA لا يضمنه توقيع IA. في أسوأ الأحوال ، يمكن لـ IB استخدام هذا للوصول إلى الحالة الداخلية التي ربما كانت IA تخفيها عن قصد.

call_indirect ونوع الواردات

الآن دعنا نضع التصنيف الفرعي جانبًا ونفكر في استيراد النوع . للراحة ، سأتحدث عن استيراد النوع ، بدلاً من مجرد استيراد النوع المرجعي ، ولكن هذه التفاصيل غير مهمة. للمثال الجاري هنا ، افترض ما يلي:

  • يعرّف IC لمثيل الوحدة النمطية نوعًا capability ويصدر النوع وليس تعريفه كـ $handle
  • مثيل الوحدة النمطية IC يصدر دالة $do_stuff تم تعريفها بالنوع [capability] -> [] ولكن تم تصديرها بالنوع [$handle] -> []
  • تستورد الوحدة النمطية MD نوعًا $extern ووظيفة $run بالنوع [$extern] -> []
  • معرف مثيل الوحدة النمطية هو الوحدة النمطية MD الذي تم إنشاء مثيل له باستخدام IA الذي تم تصديره $handle كـ $extern ومع تصدير IA $do_stuff كـ $run

ما يتم إعداده في هذا المثال هو وحدتان حيث تقوم وحدة واحدة بعمل أشياء مع قيم الوحدة الأخرى دون معرفة هذه القيم أو السماح لها بمعرفة هذه القيم. على سبيل المثال ، هذا النمط هو الأساس المخطط للتفاعل مع WASI.

لنفترض الآن أن معرف المثيل تمكن من الحصول على قيمة e من النوع $extern وتنفيذ call_indirect[$extern -> ](ref.func($run), e) . فيما يلي النتيجتان اللتان تبدوان أكثر معقولية:

  1. نجح الاستدعاء لأن التوقيع المتوقع والتوقيع المعرّف متوافقان.
  2. فخ الاستدعاء لأن التوقيعين مختلفان.

النتيجة 2 تجعل call_indirect عديمة الفائدة إلى حد كبير مع الأنواع المستوردة. لذلك بالنسبة للنتيجة 1 ، عليك أن تدرك أن نوع الإدخال $extern ليس نوع الإدخال المحدد $do_stuff (والذي بدلاً من ذلك capability ) ، لذلك من المحتمل أن نحتاج إلى استخدام أحد تقنيتان لسد هذه الفجوة:

  1. بالنسبة للوظائف المستوردة ، قارن بين call_indirect مع توقيع الاستيراد بدلاً من توقيع التعريف.
  2. أدرك أنه في وقت التشغيل ، النوع $extern في معرف المثيل يمثل capability .

إذا كنت تفضل التقنية 1 ، فعليك إدراك أنها لن تعمل مرة أخرى بمجرد إضافة مراجع الوظائف المكتوبة. (السبب الأساسي هو نفسه مع التصنيف الفرعي ، لكن الأمر يتطلب المزيد من النص لتوضيح التناظرية هنا.)

هذا يتركنا مع التقنية الثانية. لسوء الحظ ، هذا يمثل مرة أخرى مشكلة أمنية محتملة. لمعرفة السبب ، افترض أن المعرف ضار ويريد الحصول على محتويات $handle التي احتفظت بها IC سرا. افترض أيضًا أن المعرف لديه تخمين جيد لما يمثله $handle حقًا ، أي capability . يمكن للمعرف تحديد وظيفة الهوية $id_capability من النوع [capability] -> [capability] . عند إعطاء قيمة e من النوع $extern ، يمكن للمعرف تنفيذ call_indirect[$extern -> capability](ref.func($id_capability), e) . باستخدام التقنية 2 ، سينجح هذا الاستدعاء غير المباشر لأن $extern يمثل capability في وقت التشغيل ، وسيحصل المعرف على capability الخام الذي يمثله e . وبالمثل ، عند إعطاء قيمة c من النوع capability ، يمكن للمعرف تنفيذ call_indirect[capability -> $extern](ref.func($id_capability), c) لتكوين c في $extern .

استنتاج

آمل أن أكون قد أوضحت أن call_indirect لديها عدد من المشكلات المهمة القادمة المتعلقة بالأداء والدلالات و / أو الأمان / التجريد — المشكلات التي كان WebAssembly محظوظًا بتجنبها حتى الآن. لسوء الحظ ، نظرًا لكون call_indirect جزءًا من WebAssembly الأساسي ، تتقاطع هذه المشكلات مع عدد من المقترحات قيد التقدم. في الوقت الحالي ، أعتقد أنه سيكون من الأفضل التركيز على الاقتراح الأكثر إلحاحًا ، أنواع المراجع ، حيث نحتاج إلى تحديد ما إذا كان سيتم تقييد أو عدم تقييد call_indirect و func.ref للأنواع الرقمية فقط من أجل الآن — وهو قيد قد نتمكن من تخفيفه اعتمادًا على الطريقة التي ننتهي بها في النهاية إلى حل المشكلات الشاملة باستخدام call_indirect .

(آسف على المنشور الطويل. لقد بذلت قصارى جهدي لشرح التفاعلات المعقدة لميزات الكتابة متعددة الوحدات ، والكتابة ، والوقت ، والتقاء ، ووقت التشغيل ، وإظهار أهمية تلك التفاعلات بإيجاز قدر الإمكان.)

التعليق الأكثر فائدة

من ناحية أخرى ، لقد أثبتت أنه يمكن استخدام أي مرجع castable للتحايل على آليات التجريد الثابتة.

تجريد النوع الثابت غير كافٍ في لغة ذات قوالب كتابة ديناميكية. لأن التجريد الساكن يعتمد على البارامترية ، ويفكك ذلك. لا يوجد شيء جديد في ذلك ، فقد كُتبت أوراق حول هذا الموضوع. هناك حاجة إلى آليات تجريد أخرى في مثل هذا السياق.

محاولة التغلب على ذلك من خلال تقييد استخدام الأنواع المجردة يتعارض مع الغرض منها. ضع في اعتبارك حالة استخدام WASI. لا يهم ما إذا كان يتم تنفيذ وحدة WASI وأي نوع تصدره بواسطة المضيف أو في Wasm. إذا قمت بتقييد أنواع الملخصات التي يحددها المستخدم بشكل تعسفي ، فلن يكون تطبيق Wasm قابلاً للتبادل مع تطبيق المضيف بشكل عام.

  1. لا يساعد في إنشاء تصنيف فرعي للاحترام غير المباشر (والذي أعتقد أنك قلته بالفعل صراحة)

هاه؟ إنه جزء من قواعد التصنيف الفرعي ، وكذلك بالتعريف.

  1. لا يمنع استخدام call_indirect لاستخدام وظيفة مُصدَّرة بتوقيعها المحدد بدلاً من توقيعها المُصدَّر.

أنا لم أقل ذلك. لقد قلت إن هذه المشكلة ليست مشكلة في call_indirect نفسها ، ولكنها مسألة اختيار آلية تجريد مناسبة للنوع للغة ذات قوالب.

جانبا ، لا يوجد سبب مقنع لتجميع OCaml (أو أي لغة مماثلة) يجب أن يتطلب إدخال أنواع المتغيرات. حتى لو كان ذلك أسرع قليلاً من الناحية النظرية (والذي أشك في أنه سيكون هو الحال في محركات الجيل الحالي ، على الأرجح العكس) ، فإن الأنواع المتغيرة تعد من المضاعفات المهمة التي لا ينبغي أن تكون ضرورية لـ MVP. أنا لا أشاركك تمامًا في شهيتك للتعقيد المبكر. ؛)

إعادة المساواة في الوظائف: هناك لغات ، مثل Haskell أو SML ، لا تدعم ذلك ، لذلك قد تستفيد مباشرة من المراجع الوظيفية. يرمي OCaml لتحقيق المساواة الهيكلية ولديه بشكل صريح سلوك محدد للتنفيذ لشخص مادي. يُترك مفتوحًا سواء كان ذلك يسمح دائمًا بإرجاع خطأ أو رمي للوظائف ، ولكن قد يكون أي منهما كافياً من الناحية العملية ، ويستحق الاستكشاف قبل الالتزام بتغليف إضافي مكلف.

[كتعليق ميتا ، سأكون ممتنًا حقًا إذا قللت من محاضرتك وربما فكرت في فكرة أن هذا العالم ، ربما ، مجموعة الأشخاص الأكفاء ليست فردية وأن آثار الأدمغة قد تم تطبيقها من قبل.]

ال 36 كومينتر

شكرا لهذه الكتابة التفصيلية ، روس! لدي سؤال صغير: في قسم " call_indirect ونوع الواردات" تكتب ،

إذا كنت تفضل التقنية 1 ، فعليك إدراك أنها لن تعمل مرة أخرى بمجرد إضافة مراجع الوظائف المكتوبة.

هل يخضع هذا أيضًا للتحذير من القسم السابق بأن المشكلة موجودة فقط بمجرد إضافة نوع فرعي متغير إلى مراجع الوظائف المكتوبة؟

ليس. تكون كافة الإصدارات في قسم التصنيف الفرعي مستقلة عن عمليات استيراد النوع ، وتكون كافة الإصدارات في قسم استيراد النوع مستقلة عن التصنيف الفرعي. فيما يتعلق بالمشكلة المحددة التي تسأل عنها ، ضع في اعتبارك أنه يمكن إرجاع قيمة من النوع ref ([] -> [capability]) بواسطة دالة مُصدرة كقيمة من النوع ref ([] -> [$handle]) ، والتي يمكن تحويلها بعد ذلك إلى funcref واستدعى بشكل غير مباشر. على عكس الوظيفة التي تم تصديرها ، يحدث هذا التغيير في المنظور للقيمة في وقت التشغيل بدلاً من وقت الارتباط ، لذلك لا يمكننا حلها من خلال المقارنة مع توقيع الاستيراد نظرًا لأن مرجع الوظيفة لم يتم استيراده أبدًا.

module instance IC defines a type capability and exports the type but not its definition as $handle
كيف سيعمل هذا؟ يجب أن يكون هناك شيء يربط بين capability و $handle حتى يعرف IC كيف يتعامل معه؟
استنادًا أيضًا إلى https://github.com/WebAssembly/proposal-type-imports/blob/master/proposals/type-imports/Overview.md#exports ، تعد الأنواع المستوردة مجردة تمامًا. لذلك حتى لو تم تصدير $capability ، فهو مجرد. ربما أسيء فهم شيء ما.

سؤال مشابه للتصدير module instance IC exports a function $do_stuff that was defined with type [capability] -> [] but exported with type [$handle] -> [] .

يمكنني أن أتخيل نوعًا من علاقة النوع الفرعي المستخدمة لهذا ، على سبيل المثال إذا كان $capability <: $handle ، فيمكننا إذن export $capability as $handle . لكن في بداية هذا القسم ، تمت الإشارة إلى وضع التصنيف الفرعي جانبًا ، لذلك سأضع ذلك جانبًا ... لكنني فكرت أيضًا في الأمر أكثر قليلاً:
إذا: $capability <: $handle ، يمكننا export $capability as $handle ، لكن export ([$capability] -> []) as ([$handle] -> []) يجب أن "تفشل" لأن الدوال متعارضة في الوسيطة.

باستخدام عمليات تصدير النوع ، تحدد الوحدة توقيعًا ، مثل type $handle; func $do_stuff_export : [$handle] -> [] ، ثم تُنشئ التوقيع ، مثل type $handle := capability; func $do_stuff_export := $do_stuff . (تجاهل الصيغة المحددة تمامًا.) يقوم مدقق النوع بعد ذلك بفحص "نظرًا لأن $handle يمثل capability في هذه الوحدة ، فهل التصدير func $do_stuff_export := $do_stuff صالح في هذه الوحدة؟". نظرًا لأن نوع $do_stuff هو [capability] -> [] ، فإن توقيعه يتطابق تمامًا مع توقيع $do_stuff_export بعد إنشاء مثيل $handle بـ capability ، لذا تحقق نجاح. (لا يوجد تصنيف فرعي هنا ، فقط استبدال متغير.)

لاحظ ، مع ذلك ، أن التوقيع نفسه لا يقول شيئًا عن $handle . هذا يعني أنه من المفترض أن يتعامل أي شخص آخر مع $handle كنوع مجرد. أي أن التوقيع يلخص عن قصد تفاصيل تنفيذ الوحدة ، ويفترض أن يحترم كل شخص آخر هذا التجريد. الغرض من هذه المشكلة هو توضيح أنه يمكن استخدام call_indirect للتحايل على هذا التجريد.

نأمل أن يوضح هذا الموضوع قليلاً!

شكرا ، هذا يوضح الأشياء. لدي سؤال حول قسم التصنيف الفرعي (آسف للقفز):

أنا أتبع السيناريو الذي نريد أن ينجح فيه IB الذي ينفذ call_indirect[ -> tsuper](ref.func($fsuper)) ، من خلال مقارنة call_indirect "بتوقيع الاستيراد بدلاً من توقيع التعريف."

وقد أضفت أنه (بسبب مراجع الوظيفة المكتوبة) نحتاج أيضًا

  1. قم بإجراء فحص وقت التشغيل الخطي على الأقل للتأكد من توافق النوع الفرعي للتوقيع المتوقع وتوقيع التعريف.

هل يجب أن يكون هذا التوافق بين "التوقيع المتوقع وتوقيع الاستيراد "؟ نظرًا لأننا نفترض أننا قمنا بإجراء مقارنة استيراد call_indirect مع التوقيع المتوقع.

إذا تم التحقق من التوافق بين المتوقع والاستيراد ، فمن المفترض أن يفشل call_indirect[ -> tsub]($fsuper) لاحقًا.

يتم إعطاء التقنيات 1 و 2 كطريقتين متعامدتين للحصول على هذه الدعوة غير المباشرة للعمل. لسوء الحظ ، لا تتوافق التقنية 1 مع مراجع الوظائف المكتوبة ، ومن المحتمل أن تكون التقنية 2 باهظة الثمن. لذلك لا يبدو أن أيًا من هذه الأمور سينجح. وبالتالي فإن بقية القسم يأخذ في الاعتبار ما يحدث إذا لم نستخدم أيًا من هذين الأمرين وتمسكنا فقط بمقارنة المساواة البسيطة بين التوقيع المتوقع والمحدّد. اسف لخلط الامور؛ عدم وجود دلالات مخططة يعني أنه يجب علي مناقشة ثلاثة دلالات محتملة.

احرص على عدم القفز إلى الكثير من الاستنتاجات. ؛)

افترض أن call_indirect يجب أن يظل سريعًا كما هو الحال اليوم ، وبالتالي لا يتطلب سوى اختبار تكافؤ النوع ، بغض النظر عن مقدار التصنيف الفرعي الذي نضيفه إلى اللغة. في نفس الوقت ، يجب أن يكون فحص وقت التشغيل متماسكًا مع نظام النوع الثابت ، أي يجب أن يحترم علاقة النوع الفرعي.

الآن ، يمكن في الواقع التوفيق بين هذه المتطلبات التي تبدو متناقضة بسهولة إلى حد ما ، طالما أننا نتأكد من أن الأنواع القابلة للاستخدام مع call_indirect موجودة دائمًا في أوراق التسلسل الهرمي للنوع الفرعي.

إحدى الطرق المعمول بها لفرض ذلك هي إدخال مفهوم الأنواع _exact_ في نظام النوع. النوع الدقيق ليس له أنواع فرعية ، فقط الأنواع الفائقة ، وسيكون لدينا (exact T) <: T .

مع ذلك ، يمكننا أن نطلب النوع المستهدف في call_indirect ليكون نوعًا دقيقًا. علاوة على ذلك ، فإن نوع الوظائف نفسها بشكل طبيعي هي النوع الدقيق لتلك الوظيفة بالفعل.

قد تتطلب الوحدة النمطية أيضًا أنواعًا دقيقة على عمليات استيراد الوظائف ، إذا أرادت التأكد من أنه لا يمكن إنشاء مثيل لها إلا مع الوظائف التي تنجح في فحص وقت التشغيل المقصود.

هذا كل ما هو مطلوب للتأكد من أن تقنية التنفيذ الحالية لمقارنة مؤشر بسيطة على أنواع الوظائف المتعارف عليها تظل صالحة. إنها مستقلة عن الأنواع الفرعية الأخرى الموجودة ، أو كيف نقوم بعمل تصنيف فرعي للوظيفة. (FWIW ، لقد ناقشت هذا الأمر مع Luke منذ فترة ، وخططت لإنشاء علاقات عامة ، ولكن تم حظره بسبب التغييرات المعلقة للقصة الفرعية ، والمقترح الذي ينتقل إليه الآن).

(أحد الجوانب السلبية هو أن تنقيح تعريف دالة لنوع فرعي لم يعد تغييرًا متوافقًا مع الإصدارات السابقة بشكل عام ، على الأقل ليس إذا تم استخدام نوعه الدقيق في أي مكان. ولكن هذا العيب لا مفر منه في ظل قيودنا ، بغض النظر عن كيفية فرضنا بالضبط معهم.)

زوجان من الجوانب:

البديل هو ترك call_indirect و func.ref كما هو.

AFAICS ، ليس من المجدي عدم السماح لـ ref.func بالوظائف التي تتضمن أنواعًا مرجعية. سيؤدي ذلك إلى شل العديد من حالات الاستخدام ، على سبيل المثال ، كل شيء يتضمن وظائف من الدرجة الأولى تعمل على externref (الاسترجاعات ، الخطافات ، إلخ).

من الممكن فقط أن يعني هذا ، اعتمادًا على الحل الذي توصلنا إليه ، أن externref قد لا يكون قابلاً للتشغيل مثل استيراد النوع الحقيقي ، و / أو أن المراجع الخارجي قد (ومن المفارقات) لا يكون قادرًا على الحصول على أي أنواع فائقة (على سبيل المثال ، قد لا يكون أن تكون نوعًا فرعيًا من anyref إذا قررنا في النهاية إضافة anyref).

هل يمكنك التفصيل؟ لا أرى الاتصال.

احرص على عدم القفز إلى الكثير من الاستنتاجات. ؛)

لست متأكدًا من الاستنتاج الذي تشير إليه. استنتاجي المعلن هو أن هناك عددًا من المشكلات مع call_indirect يجب أن نكون على دراية بها ويجب أن نبدأ في التخطيط لها. يبدو أنك تقترح أن هذه المشكلات غير مهمة لأن لديك حلًا في ذهنك. لكن لم تتم مراجعة هذا الحل أو قبوله من قِبل CG ، ولا ينبغي أن نخطط له حتى يتم ذلك. لقد طلبت على وجه التحديد عدم مناقشة الحلول لأن الأمر سيستغرق بعض الوقت لتقييمها ومقارنتها وهناك قرارات نحتاج إلى اتخاذها قبل أن يكون لدينا الوقت لإجراء تلك التقييمات والمقارنات بشكل صحيح. ولكن ، من أجل منع الناس من تكوين تصور بأن هذه المشكلة قد تم حلها وبالتالي تجنب القرار الملح ، سأستغرق ثانية لمناقشة الحل بسرعة.

إحدى الطرق المعمول بها لفرض ذلك هي إدخال مفهوم الأنواع الدقيقة في نظام النوع.

الأنواع الدقيقة ليست حلاً راسخًا. إذا كان هناك أي شيء ، فقد أثبتت الأنواع الدقيقة المشكلات التي لا يزال مؤيدوها يعملون على معالجتها. ومن المثير للاهتمام، هنا هو الخيط حيث الفريق نسخة مطبوعة على الآلة الكاتبة شهد أصلا كيف أنواع من النموذج الدقيق الذي نقترحه يمكن حل بعض المشاكل، ولكن بعد ذلك في نهاية المطاف [أدرك) (https://github.com/microsoft/TypeScript/issues/12936 # issuecomment-284590083) هذه الأنواع الدقيقة قدمت مشاكل أكثر مما تم حلها. (ملاحظة للسياق: تمت المطالبة بهذه المناقشة من خلال أنواع الكائنات الدقيقة في Flow ، والتي ليست في الواقع شكلاً من أشكال النوع الدقيق (بالمعنى النظري) ولكن بدلاً من ذلك ببساطة لا تسمح بالتناظرية للكائن من البادئة الفرعية.) يمكنني أن أتخيل أننا نعيد تشغيل هذا الخيط هنا.

كمثال على كيفية حدوث هذه الأنواع من المشكلات في WebAssembly ، افترض أننا لم نؤجل التصنيف الفرعي. نوع ref.null سيكون exact nullref باستخدام الأنواع الدقيقة. لكن exact nullref لن يكون نوعًا فرعيًا من exact anyref . في الواقع ، وفقًا للدلالات المعتادة للأنواع الدقيقة ، من المحتمل ألا تنتمي أي قيم إلى exact anyref لأنه من المحتمل ألا يكون نوع وقت التشغيل للقيمة هو anyref بالضبط. سيؤدي هذا إلى جعل call_indirect غير قابل للاستخدام تمامًا مقابل anyref s.

الآن ربما يكون لديك بعض الإصدارات المختلفة من الأنواع الدقيقة في الاعتبار ، ولكن قد يستغرق الأمر بعض الوقت للتحقق من أن هذا الإصدار المختلف يعالج بطريقة ما المشكلات المفتوحة العديدة ذات الأنواع الدقيقة. لذلك وجهة نظري هنا ليست لطرد هذا الحل، ولكن لنعترف أنه ليس من الواضح أن هذا هو الحل وليس اتخاذ قرارات مع هذا التوقع.

هل يمكنك التفصيل؟ لا أرى الاتصال.

أنت تشير إلى جملة طويلة. أي جزء منه تريد مني أن أتوسع فيه؟ أحد التخمينات هو أنك قد تفقد المشكلة الإجمالية مع call_indirect واكتب عمليات الاستيراد. لا يعالج اقتراح الأنواع الدقيقة سوى مشاكل التصنيف الفرعي ، لكننا توصلنا أعلاه إلى أن call_indirect يواجه مشاكل حتى بدون أي نوع فرعي.

سيؤدي ذلك إلى شل العديد من حالات الاستخدام ، على سبيل المثال ، كل شيء يتضمن وظائف من الدرجة الأولى تعمل على externref (الاسترجاعات ، الخطافات ، إلخ).

نعم ، هذا شيء كنت أتمنى الحصول على مزيد من المعلومات عنه. ما أفهمه هو أن حالة الاستخدام الأساسية لـ call_indirect هي دعم مؤشرات دالة C / C ++ والطرق الافتراضية لـ C ++. أفهم أيضًا أن حالة الاستخدام هذه محصورة حاليًا في التوقيعات الرقمية. أعرف المزيد من الاستخدامات المحتملة لـ call_indirect ، لكن كما ذكرت ، كنت أقترح تقييدًا مؤقتًا ، لذا ما يهم هو ما هي الاستخدامات الحالية لـ call_indirect . بالنظر إلى أن call_indirect لا يزال يتطلب جدولًا وفهرسًا بدلاً من مجرد funcref ، لا يبدو أنه مصمم جيدًا لدعم عمليات الاسترجاعات. لم أكن أعرف اذا كان ذلك بسبب حاليا هو عدم استخدامه لهذا الغرض.

تعلمون جميعًا أن قواعد الكود التي تستهدف هذه الميزة أفضل بكثير مني ، لذلك إذا كنت تعرف بعض البرامج الحقيقية التي تحتاج إلى هذه الوظيفة الآن ، فسيكون من المفيد جدًا تقديم بعض الأمثلة لأنماط الاستخدام المطلوبة هنا. إلى جانب كونها مفيدة لمعرفة ما إذا كنا بحاجة إلى دعم هذه الوظيفة في الوقت الحالي ، إذا كانت الوظيفة مطلوبة الآن ، فستكون هذه الأمثلة مفيدة في معرفة أفضل السبل لتقديمها بسرعة أثناء معالجة المشكلات المذكورة أعلاه.

RossTate :

إذا كان هناك أي شيء ، فقد أثبتت الأنواع الدقيقة المشكلات التي لا يزال مؤيدوها يعملون على معالجتها. ومن المثير للاهتمام ، هنا هو الخيط حيث رأى فريق TypeScript في الأصل كيف يمكن للأنواع الدقيقة من النموذج الذي تقترحه أن تحل بعض المشكلات ، لكنهم أدركوا في النهاية أن الأنواع الدقيقة قدمت مشاكل أكثر مما تم حلها. (ملاحظة للسياق: تمت المطالبة بهذه المناقشة من خلال أنواع الكائنات الدقيقة في Flow ، والتي ليست في الواقع شكلاً من أشكال النوع الدقيق (بالمعنى النظري) ولكن بدلاً من ذلك ببساطة لا تسمح بالتناظرية للكائن من البادئة الفرعية.) يمكنني أن أتخيل أننا نعيد تشغيل هذا الخيط هنا.

الأقواس هي المفتاح هنا. لست متأكدًا مما يدور في ذهنهم بالضبط في هذا الموضوع ، لكن لا يبدو أنه نفس الشيء. بخلاف ذلك ، فإن عبارات مثل "يُفترض أن النوع T & U قابل دائمًا للتخصيص إلى T ، لكن هذا يفشل إذا كان T النوع الدقيق" لن يكون له معنى (هذا ليس ' فشل t ، لأن T & U سيكون غير صالح أو بالأسفل). تتعلق الأسئلة الأخرى بشكل أساسي بالبراغماتية ، أي أين قد يرغب المبرمج في استخدامها (للأشياء) ، والتي لا تنطبق في حالتنا.

بالنسبة للأنظمة ذات المستوى المنخفض ، ألم تكن الأنواع الدقيقة مكونًا حاسمًا حتى في بعض أوراقك الخاصة؟

كمثال على كيفية حدوث هذه الأنواع من المشكلات في WebAssembly ، افترض أننا لم نؤجل التصنيف الفرعي. سيكون نوع ref.null هو nullref باستخدام الأنواع الدقيقة. لكن nullref الدقيق لن يكون نوعًا فرعيًا من anyref بالضبط.

لا خلاف هنا. عدم وجود أنواع فرعية هو الغرض من الأنواع الدقيقة.

في الواقع ، وفقًا للدلالات المعتادة للأنواع الدقيقة ، من المحتمل ألا تنتمي أي قيم إلى أي مرجع دقيق لأنه من المحتمل ألا يكون نوع وقت التشغيل للقيمة هو أي مرجع بالضبط.

حسنًا ، الدمج (exact anyref) ليس نوعًا مفيدًا ، نظرًا لأن الغرض الوحيد من anyref هو أن يكون نوعًا فائقًا. لكن لماذا هذه مشكلة؟

هذا من شأنه أن يجعل call_indirect غير قابل للاستخدام تمامًا لأي مرجع.

هل أنت متأكد من أنك لا تربك المستويات الآن؟ نوع الوظيفة (exact (func ... -> anyref)) مفيد تمامًا. إنه غير متوافق مع النوع ، على سبيل المثال ، (func ... -> (ref $T)) . وهذا يعني أن exact يمنع التصنيف الفرعي غير التافه على أنواع الوظائف. لكن هذا هو بيت القصيد!

ربما تقوم بخلط (exact (func ... -> anyref)) مع (func ... -> exact anyref) ؟ هذه أنواع غير ذات صلة.

لا يعالج اقتراح الأنواع الدقيقة إلا مشاكل التصنيف الفرعي ، لكننا توصلنا أعلاه إلى أن call_indirect بها مشاكل حتى بدون أي نوع فرعي.

أنت تفترض بطريقة ما أنك ستتمكن من تصدير نوع بدون تعريفه كوسيلة لتعريف نوع بيانات مجردة. من الواضح أن هذا النهج لا يعمل في ظل وجود أنواع من النوع الديناميكي (call_indirect أو غير ذلك). لهذا السبب أستمر في القول إننا سنحتاج إلى تجريد بنمط جديد ، وليس تجريد بنمط ML.

ما أفهمه هو أن حالة الاستخدام الأساسية لـ call_indirect هي دعم مؤشرات دالة C / C ++

نعم ، ولكن هذه ليست حالة الاستخدام الوحيدة لـ ref.func ، التي كنت أشير إليها ، لأنك أدرجتها في التقييد الذي اقترحته (ربما بدون داعٍ؟). على وجه الخصوص ، سيكون هناك call_ref ، والذي لا يتضمن فحص النوع.

أنت تفترض بطريقة ما أنك ستتمكن من تصدير نوع بدون تعريفه كوسيلة لتعريف نوع بيانات مجردة. من الواضح أن هذا النهج لا يعمل في ظل وجود أنواع من النوع الديناميكي (call_indirect أو غير ذلك). لهذا السبب أستمر في القول إننا سنحتاج إلى تجريد بنمط جديد ، وليس تجريد بنمط ML.

حسنًا ، يبدو أنك توافق على أن الأنواع الدقيقة لا تفعل شيئًا لمعالجة المشكلة بـ call_indirect واكتب import. لكنك تقول أيضًا أنه لا جدوى من معالجة هذه المشكلة لأنها ستكون مشكلة على أي حال بسبب فرق وقت التشغيل. هناك طريقة سهلة لمنع هذه المشكلة: لا تسمح للأشخاص بأداء عمليات التمثيل في وقت التشغيل على أنواع مجردة (ما لم ينص النوع المجرد صراحةً على أنه قابل للتخصيص). بعد كل شيء ، إنه نوع معتم ، لذلك لا ينبغي أن نكون قادرين على افتراض أنه يعرض البنية اللازمة لأداء فريق عمل. لذا ، حتى إذا كان هناك احتمال أن تعالج الأنواع الدقيقة مشكلة التصنيف الفرعي ، فمن السابق لأوانه تجاهل النصف الآخر من المشكلة.

كما قلت ، كل حل له مفاضلات. يبدو أنك تفترض أن الحل الخاص بك يحتوي فقط على المفاضلات التي حددتها بنفسك ، ويبدو أنك تفترض أن CG يفضل الحل الخاص بك على الآخرين. أنا أيضًا لديّ حل محتمل لهذه المشكلة. إنه يضمن عمليات فحص مستمرة ، ويستند إلى تقنية مستخدمة بالفعل في الأجهزة الافتراضية ، ويعالج جميع المشكلات هنا (على ما أعتقد) ، ولا يتطلب إضافة أي أنواع جديدة ، ويضيف بالفعل وظائف إضافية إلى WebAssembly مع التطبيقات المعروفة. ومع ذلك ، فأنا لا أفترض أنها تعمل كما أتوقع وأنني لم أغفل بعض أوجه القصور لأنك أنت والآخرين لم تتح لي الفرصة للنظر فيها. كما أنني لا أفترض أن CG ستفضل المقايضات الخاصة بها على تلك الخيارات البديلة. بدلاً من ذلك ، أحاول معرفة ما يمكننا القيام به لمنحنا الوقت لتحليل الخيارات بحيث يكون CG ، وليس أنا فقط ، هو الذي يتخذ قرارًا مستنيرًا بشأن هذا الموضوع الشامل.

على وجه الخصوص ، سيكون هناك call_ref ، والذي لا يتضمن فحوصات النوع.

الكلمة الأساسية في جملتك هي will . وأنا أدرك تماما أن هناك تطبيقات call_indirect مع أنواع غير رقمية أن الناس تريد أن يكون معتمد. وأتوقع أننا سوف يأتي مع التصميم الذي يدعم هذه الوظيفة وعناوين القضايا أعلاه. ولكن ، كما قلت ، من الناحية المثالية ، يمكن أن يكون لدينا بعض الوقت لتطوير هذا التصميم حتى لا نشحن بسرعة ميزة ذات آثار شاملة قبل أن تتاح لنا الفرصة للتحقيق في هذه الآثار. لذا سؤالي هو هل هناك برامج رئيسية تحتاج إلى هذه الوظيفة الآن . إذا كان هناك ، فلا داعي للافتراض ؛ فقط أشر إلى البعض ووضح كيف يعتمدون حاليًا على هذه الوظيفة.

أنت تفترض بطريقة ما أنك ستتمكن من تصدير نوع بدون تعريفه كوسيلة لتعريف نوع بيانات مجردة. من الواضح أن هذا النهج لا يعمل في ظل وجود أنواع من النوع الديناميكي (call_indirect أو غير ذلك). لهذا السبب أستمر في القول إننا سنحتاج إلى تجريد بنمط جديد ، وليس تجريد بنمط ML.

هذا يبدو وكأنه قضية أساسية بالنسبة لي. هل التمكين من سرية تعريفات الأنواع المصدرة هدف لمقترح النوع المستورد؟ أجمع من هذا الموضوع أن RossTate يعتقد أنه يجب أن يكون هدفًا ويعتقد rossberg أنه ليس هدفًا حاليًا. دعنا نناقش هذا السؤال ونتفق عليه قبل مناقشة الحلول حتى نتمكن جميعًا من العمل من نفس مجموعة الافتراضات.

RossTate :

حسنًا ، يبدو أنك توافق على أن الأنواع الدقيقة لا تفعل شيئًا لمعالجة المشكلة مع call_indirect واكتب import.

نعم ، إذا كنت تقصد بذلك السؤال عن كيفية إضافة ميزة لتعريف أنواع البيانات المجردة. هناك عدد من الطرق التي يمكن أن يعمل بها تجريد الكتابة بشكل متسق ، ولكن هذه الميزة في المستقبل.

الكلمة الأساسية في جملتك هي will. أدرك تمامًا أن هناك تطبيقات لـ call_indirect مع أنواع غير رقمية سيرغب الأشخاص في دعمها.

التعليمات call_ref موجودة في اقتراح مرجع الوظيفة ، لذا فهي قريبة إلى حد ما ، على أي حال قبل أي آلية محتملة لنوع البيانات المجردة. هل تقترح أن نعلقها حتى ذلك الحين؟

tlively :

هل التمكين من سرية تعريفات الأنواع المصدرة هدف لمقترح النوع المستورد؟ أجمع من هذا الموضوع أن RossTate يعتقد أنه يجب أن يكون هدفًا ويعتقد rossberg أنه ليس هدفًا حاليًا.

إنه هدف ، لكن آلية نوع البيانات المجردة هي ميزة منفصلة. ويجب تصميم هذه الآلية بحيث لا تؤثر على تصميم الواردات. إذا كان الأمر كذلك ، فسنقوم بذلك بشكل خاطئ للغاية - يجب ضمان التجريد في موقع التعريف ، وليس في موقع الاستخدام. لحسن الحظ ، هذا ليس علم الصواريخ ، ومساحة التصميم جيدة إلى حد ما.

شكرًا ، rossberg ، هذا منطقي. يبدو أن إضافة العناصر الأولية للتجريد في اقتراح المتابعة بعد استيراد وتصدير النوع أمر جيد بالنسبة لي ، ولكن سيكون من الرائع أن نتمكن من تدوين تفاصيل كيف نخطط للقيام بذلك في مكان ما قريبًا. يقيد تصميم استيراد وتصدير النوع وإعلام تصميم استيراد وتصدير النوع المجرد ، لذلك من المهم أن يكون لدينا فكرة جيدة عن كيفية عمل التجريد على الطريق قبل الانتهاء من التصميم الأولي.

بالإضافة إلى تفصيل تلك الخطة ، نظرًا لأن هذه المشكلة مع call_indirect تُظهر أنها تؤثر على القرارات الملحة ، هل يمكنك توضيح سبب رفضك لاقتراحي بأن الأنواع المجردة لا ينبغي أن تكون قابلة للنقاش (ما لم تكن مقيدة صراحة لتكون قابلة للسحب) )؟ إنها مبهمة ، لذا يبدو أن الاقتراح يتماشى مع الممارسات الشائعة للأنواع المجردة.

tlively ، نعم ، موافق. بالإضافة إلى العديد من الأشياء الأخرى التي قصدت كتابتها لفترة من الوقت. سأفعل بمجرد أن أعمل من خلال كل التداعيات من رقم 69 . ؛)

RossTate ، لأن ذلك من شأنه أن يجعل أنواع البيانات المجردة غير متوافقة مع القوالب. فقط لأنني أريد منع الآخرين من رؤية _ من خلال_ نوع مجردة ، لا أريد بالضرورة منعهم (أو نفسي) من إرسال نوع مجردة. إن إنشاء مثل هذا الانقسام الخاطئ من شأنه أن يكسر حالات الاستخدام المركزي للقوالب. على سبيل المثال ، بالطبع أريد أن أكون قادرًا على تمرير قيمة من النوع المجرد إلى وظيفة متعددة الأشكال.

rossberg هل يمكنك توضيح حالة الاستخدام المركزية التي تفكر فيها؟ أفضل تخميني في تفسير مثالك هو حل بسيط ، لكن ربما تقصد شيئًا آخر.

RossTate ، ضع في اعتبارك الدوال متعددة الأشكال. باختصار من مولدات Wasm ، عند تجميعها باستخدام قوالب لأعلى / لأسفل من anyref ، ينبغي أن يكون من الممكن استخدامها مع قيم من النوع المجرد مثل أي نوع آخر ، دون الحاجة إلى التفاف إضافي في كائنات أخرى. تريد عمومًا أن تكون قادرًا على التعامل مع قيم من النوع المجرد مثل أي قيم أخرى.

حسنًا ، دعنا نفكر في الدوال متعددة الأشكال ، ولنفترض أن النوع الذي تم استيراده هو Handle :

  1. Java لها وظائف متعددة الأشكال. تتوقع وظائفها متعددة الأشكال أن تكون جميع قيم (مرجع Java) كائنات. على وجه الخصوص ، يجب أن يكون لديهم جدول v. من المحتمل أن تحدد وحدة Java النمطية التي تستخدم Handle فئة Java CHandle ربما تنفذ واجهات. سيكون لمثيلات هذه الفئة عضو (على مستوى wasm) من النوع Handle وجدول v الذي يوفر مؤشرات دالة لتطبيقات طرق مختلفة للفئة والواجهة. عند إعطائها لوظيفة متعددة الأشكال على مستوى السطح ، والتي تكون على مستوى wasm مجرد وظيفة على الكائنات ، يمكن للوحدة استخدام نفس الآلية التي تستخدمها للإرسال إلى فئات أخرى للإرسال إلى CHandle .
  2. OCaml له وظائف متعددة الأشكال. تتوقع وظائفها متعددة الأشكال أن تدعم جميع قيم OCaml المساواة الجسدية. نظرًا لأن wasm لا يمكنه التفكير في أمان نوع OCaml ، فمن المحتمل أيضًا أن تحتاج وظائفه متعددة الأشكال إلى استخدام القوالب بكثافة. من المحتمل أن تجعل بنية الصب المتخصصة هذا أكثر كفاءة. لأي من هذين السببين ، من المحتمل أن تحدد وحدة OCaml نوع البيانات الجبرية أو نوع السجل THandle الذي يتناسب مع هذه المعايير ولديه عضو (على مستوى wasm) من النوع Handle . ستؤدي وظائفها متعددة الأشكال بعد ذلك إلى تحويل قيم OCaml إلى THandle تمامًا كما تفعل مع أي نوع بيانات جبري أو نوع سجل آخر.

بعبارة أخرى ، نظرًا لأن الوحدات النمطية تعتمد على معايير حول كيفية تمثيل قيم المستوى السطحي من أجل تنفيذ أشياء مثل الوظائف متعددة الأشكال ، وأن الأنواع المستوردة المجردة مثل Handle لا تفي بهذه المعايير ، فإن التفاف القيم أمر لا مفر منه. هذا هو نفس سبب استبدال أحد التطبيقات الأصلية لـ anyref بأنواع الواجهة. وقمنا بتطوير دراسات حالة توضح أن anyref ليس ضروريًا ، ولا حتى مناسبًا تمامًا ، لدعم الوظائف متعددة الأشكال.

من ناحية أخرى ، لقد أظهرت أنه يمكن استخدام castable anyref للتحايل على آليات التجريد الثابتة. إن خطة آلية التجريد التي أشرت إليها هي محاولة لإصلاح هذه المشكلة من خلال آليات التجريد الديناميكي. لكن هناك عددًا من المشكلات المتعلقة بآليات التجريد الديناميكي. على سبيل المثال ، لا يمكن تصدير نوع i31ref كنوع تجريدي Handle بدون المخاطرة بوحدات نمطية أخرى تستخدم anyref والصب لتزوير مقابض (على سبيل المثال للقدرات). بدلاً من ذلك ، يتعين على المرء أن يقفز من خلال الأطواق والنفقات الإضافية التي ستكون غير ضرورية إذا قمنا بدلاً من ذلك فقط بالتأكد من التجريد الثابت القياسي.

أيضًا ، الآن (على ما أعتقد) فهمت بشكل أفضل كيف تنوي استخدام الأنواع الدقيقة ، أدرك أن نيتك لا تعالج أيًا من المشكلتين الرئيسيتين اللتين لفتت انتباهي إليهما باستخدام call_indirect والتصنيف الفرعي:

  1. لا يساعد في إنشاء تصنيف فرعي لاحترام call_indirect (والذي أعتقد أنك قلته بالفعل صراحة)
  2. لا يمنع استخدام call_indirect لاستخدام دالة مُصدَّرة بتوقيعها المحدد بدلاً من توقيعها المُصدَّر.

لذا فهذه ليست مشكلة تافهة يجب حلها. لهذا السبب ، نظرًا لضيق الوقت ، أفضل التركيز على تقييم كيفية منحنا الوقت لحلها بشكل صحيح. لا أعتقد أنه من الضروري إجراء مناقشة أولاً حول ما إذا كان anyref يستحق التخلص من التجريد الثابت. هذا هو نوع المناقشة الكبيرة التي كنت آمل في تجنبها من أجل عدم تأخير الأمور أكثر.

من ناحية أخرى ، لقد أثبتت أنه يمكن استخدام أي مرجع castable للتحايل على آليات التجريد الثابتة.

تجريد النوع الثابت غير كافٍ في لغة ذات قوالب كتابة ديناميكية. لأن التجريد الساكن يعتمد على البارامترية ، ويفكك ذلك. لا يوجد شيء جديد في ذلك ، فقد كُتبت أوراق حول هذا الموضوع. هناك حاجة إلى آليات تجريد أخرى في مثل هذا السياق.

محاولة التغلب على ذلك من خلال تقييد استخدام الأنواع المجردة يتعارض مع الغرض منها. ضع في اعتبارك حالة استخدام WASI. لا يهم ما إذا كان يتم تنفيذ وحدة WASI وأي نوع تصدره بواسطة المضيف أو في Wasm. إذا قمت بتقييد أنواع الملخصات التي يحددها المستخدم بشكل تعسفي ، فلن يكون تطبيق Wasm قابلاً للتبادل مع تطبيق المضيف بشكل عام.

  1. لا يساعد في إنشاء تصنيف فرعي للاحترام غير المباشر (والذي أعتقد أنك قلته بالفعل صراحة)

هاه؟ إنه جزء من قواعد التصنيف الفرعي ، وكذلك بالتعريف.

  1. لا يمنع استخدام call_indirect لاستخدام وظيفة مُصدَّرة بتوقيعها المحدد بدلاً من توقيعها المُصدَّر.

أنا لم أقل ذلك. لقد قلت إن هذه المشكلة ليست مشكلة في call_indirect نفسها ، ولكنها مسألة اختيار آلية تجريد مناسبة للنوع للغة ذات قوالب.

جانبا ، لا يوجد سبب مقنع لتجميع OCaml (أو أي لغة مماثلة) يجب أن يتطلب إدخال أنواع المتغيرات. حتى لو كان ذلك أسرع قليلاً من الناحية النظرية (والذي أشك في أنه سيكون هو الحال في محركات الجيل الحالي ، على الأرجح العكس) ، فإن الأنواع المتغيرة تعد من المضاعفات المهمة التي لا ينبغي أن تكون ضرورية لـ MVP. أنا لا أشاركك تمامًا في شهيتك للتعقيد المبكر. ؛)

إعادة المساواة في الوظائف: هناك لغات ، مثل Haskell أو SML ، لا تدعم ذلك ، لذلك قد تستفيد مباشرة من المراجع الوظيفية. يرمي OCaml لتحقيق المساواة الهيكلية ولديه بشكل صريح سلوك محدد للتنفيذ لشخص مادي. يُترك مفتوحًا سواء كان ذلك يسمح دائمًا بإرجاع خطأ أو رمي للوظائف ، ولكن قد يكون أي منهما كافياً من الناحية العملية ، ويستحق الاستكشاف قبل الالتزام بتغليف إضافي مكلف.

[كتعليق ميتا ، سأكون ممتنًا حقًا إذا قللت من محاضرتك وربما فكرت في فكرة أن هذا العالم ، ربما ، مجموعة الأشخاص الأكفاء ليست فردية وأن آثار الأدمغة قد تم تطبيقها من قبل.]

كتعليق ميتا ، سأكون ممتنًا حقًا إذا قمت بتخفيف حدة محاضرتك

سمع.

وربما أخذنا في الاعتبار فكرة أن هذا عالم حيث ، ربما ، مجموعة الأشخاص الأكفاء ليسوا منفردون وأن آثار الأدمغة قد تم تطبيقها في بعض الأحيان من قبل.

نصيحتي هنا مبنية على التشاور مع خبراء متعددين.

تجريد النوع الثابت غير كافٍ في لغة ذات قوالب كتابة ديناميكية. لأن التجريد الساكن يعتمد على البارامترية ، ويفكك ذلك. لا يوجد شيء جديد في ذلك ، فقد كُتبت أوراق حول هذا الموضوع. هناك حاجة إلى آليات تجريد أخرى في مثل هذا السياق.

يشمل هؤلاء الخبراء الذين استشرت معهم مؤلفي بعض الأوراق المذكورة.

الآن ، كمحاولة للتحقق من أنني قمت بتجميع نصائحهم بشكل صحيح ، قمت فقط بإرسال بريد إلكتروني لمؤلف آخر لبعض الأوراق المذكورة ، أحدهم لم أقم بمناقشة هذا الموضوع من قبل. هذا ما سألته:

افترض أن لدي وظيفة متعددة الأشكال f(...). تحتوي لغتي المكتوبة على تصنيف فرعي (فرعي) وصياغة صريحة. ومع ذلك ، يتحقق نوع المصبوب من t1 إلى t2 فقط إذا كان t2 نوعًا فرعيًا من t1. افترض أن متغيرات النوع مثل X افتراضيًا لا تحتوي على أنواع فرعية أو أنواع فائقة (باستثناء نفسها بالطبع). هل تتوقع أن تكون f بارامترية فيما يتعلق بـ X؟

كان هذا ردهم:

نعم ، أعتقد أن هذا سيكون حدوديًا لأن القدرة الوحيدة التي يمنحها لك هذا هي كتابة قوالب على X مكافئة لوظيفة الهوية ، والتي هي بالفعل معلمية علائقية.

هذا يتماشى مع نصيحتي. الآن ، بالطبع ، هذا تبسيط للمشكلة المطروحة ، لكننا بذلنا جهدًا للتحقيق في المشكلة بشكل أكثر تحديدًا لـ WebAssembly ، وحتى الآن اقترح استكشافنا أن هذا التوقع يستمر حتى على مستوى WebAssembly باستثناء call_indirect ، ومن هنا جاءت هذه المشكلة.

لاحظ أن النظريات التي تشير إليها تنطبق على اللغات التي يمكن فيها نقل جميع القيم. هذه الملاحظة هي المكان الذي حصلنا فيه على فكرة تقييد قابلية النقل.

ضع في اعتبارك حالة استخدام WASI.

أنا لا أفهم الادعاءات التي تقدمها. لقد نظرنا في حالة استخدام WASI. من خلالنا ، أقوم بتضمين العديد من الخبراء في مجال الأمن وحتى الأمن القائم على القدرات على وجه التحديد.

كتعليق تعريفي ، سأكون ممتنًا حقًا لعدم الحاجة إلى مناشدة السلطة أو إلى CG لسماع اقتراحاتي. لقد اقترحت أن تقييد القوالب سيمكن من ضمان بارامترية ثابتة حتى في وجود القوالب. لقد تجاهلت على الفور هذا الاقتراح ، وناشدت الأوراق السابقة لتبرير هذا الفصل. ومع ذلك ، عندما قدمت هذا الاقتراح نفسه إلى مؤلف تلك الأوراق ، توصلوا على الفور إلى نفس النتيجة التي توصلت إليها وكما كان يمكن أن تتوصلوا إليه. قبل ذلك ، اقترحت أن تقييم الحلول المحتملة سيكون عملية طويلة. لقد تجاهلت هذا الاقتراح ، وأصررت على أنك (جميعًا بمفردك) قد حللت المشكلة ، وجذبتنا إلى هذه المحادثة الطويلة. من الصعب للغاية إحراز تقدم ، وعدم الشعور بالإحباط ، عندما يتم رفض اقتراحات المرء مرارًا وتكرارًا بشكل عرضي. (يجب أن أوضح أنني لا أحاول رفض اقتراحك كحل ممكن هنا ؛ إنني أحاول إثبات أنه ليس الحل الوحيد ولذا يجب تقييمه جنبًا إلى جنب مع العديد من الحلول الأخرى).

أعتقد أن وجود تصميم تفصيلي مسمر ومدقق يعالج المخاوف التي أثيرت في هذه المسألة أمر مهم وفي الوقت المناسب: لا أعتقد في الواقع أنه يجب اعتبار الأنواع المجردة ميزة بعيدة ؛ WASI يحتاجهم الآن-العش.

آمل أيضًا أن يتمكن exact + newtype معالجة هذه المخاوف ، لكنني أوافق على أنه لا يمكننا ببساطة المراهنة على المزرعة على هذا الحدس في هذه المرحلة من الوقت من خلال الالتزام قبل الأوان بالتصميم عندما نحن (قريبًا) نشحن أنواعًا مرجعية. نحن بحاجة إلى وقت لإجراء مناقشة مناسبة حول هذا الموضوع.

ومع ذلك ، لا أرى الخطر في السماح بتوقيعات externref في call_indirect في اقتراح أنواع المراجع. نعم ، إذا قامت الوحدة بتصدير قيمة externref (كقيمة ثابتة عامة أو إعادتها من دالة ...) ، فإننا لم نتمكن من تحديد ما إذا كان بإمكاننا تقليل externref . لكن call_indirect لا يقلل من قيمة externref ؛ إنه يقلل من قيمة funcref ، و externref لا يختلف عن دور i32 wrt فحص المساواة من نوع funcref. وبالتالي ، في حالة عدم وجود عمليات استيراد من النوع ، وكتابة الصادرات ، والتصنيف الفرعي أثناء اللعب بـ call_indirect ، لا أرى كيف نلتزم باختيار تصميم جديد لم نلتزم به بالفعل في MVP .

إذا لم يكن هناك خطر ، فربما يمكننا تحويل هذه المناقشة المكثفة إلى مناقشة أقل كثافة في مقترح استيراد النوع (حيث ما زلت أعتقد أنه يجب علينا تضمين دعم النوع المجرد المناسب)؟

بالتأكيد. أعتقد أنه من الجيد فحص ما إذا كان هناك خطر أم لا.

فيما يتعلق بـ WASI ، لا يزال التصميم في حالة تغير مستمر ، ولكن أحد الخيارات التي لا تزال قابلة للتطبيق هو استخدام شيء مثل i31ref لـ "مقابضه" ، على سبيل المثال لأنه لا يتطلب تخصيصًا ديناميكيًا للذاكرة. قد يقرر WASI خيارات أخرى ، ولكن النقطة المهمة هي أن لا أحد يعرفه في الوقت الحالي ، وسيكون من الجيد أن لا تؤثر القرارات المتخذة الآن على مثل هذه القرارات في المستقبل.

حاليًا ، externref هو نوع الملخص الوحيد المتاح ، ولذا فإن المضيف المستند إلى WASI سيقوم بإنشاء مثيل externref مع i31ref (أو أيًا كانت "مقابض" WASI). لكن ما أفهمه هو أن WASI تريد نقل تنفيذها إلى WebAssembly قدر الإمكان لتقليل الشفرة المعتمدة على المضيف. لتسهيل ذلك ، قد ترغب أنظمة WASI في مرحلة ما في التعامل مع externref تمامًا مثل أي استيراد من نوع آخر وإنشاء مثيل له باستخدام ملخص WASI الذي تم تصديره Handle type. ولكن إذا كان Handle هو i31ref ، فإن التطبيق أعلاه call_indirect المطلوب لتمكينه من العمل عبر حدود الوحدة يمكن استخدامه أيضًا للسماح للأشخاص بتشكيل المقابض عبر externref .

إذن أحد أسئلتي ، الذي ألاحظ الآن أنه لم يتم ذكره بوضوح في رسالتي الأصلية ، هل يريد الأشخاص أن يكون externref قابلاً للتشغيل تمامًا مثل عمليات استيراد الأنواع المجردة الأخرى؟

إذن أحد أسئلتي ، الذي ألاحظ الآن أنه لم يتم ذكره بوضوح في رسالتي الأصلية ، هل يريد الأشخاص أن يكون externref قابلاً للتشغيل تمامًا مثل عمليات استيراد الأنواع المجردة الأخرى؟

شكرا لطرح هذا السؤال صراحة. FWIW ، لم أفهم أبدًا أن externref يمكن تطبيقه من داخل وحدة WebAssembly. هذا يعني مشاركة المضيف في الظاهرية إذا أراد WASI استخدام externref كمقابض ، لكن هذا يبدو جيدًا بالنسبة لي ، أو على الأقل يبدو مناقشة قابلة للفصل.

حسنًا ، دعني أرى ما إذا كان بإمكاني التوضيح. أظن أنك بالفعل على متن الطائرة مع مجموعة مما يلي ، ولكن من الأسهل بالنسبة لي أن أبدأ من نقطة الصفر.

من منظور وحدة wasm ، لا يعني externref مرجع المضيف. إنه مجرد نوع معتم لا تعرف الوحدة النمطية عنه شيئًا. بدلاً من ذلك ، فإن الاصطلاحات حول externref التي تفسرها كمرجع مضيف. على سبيل المثال ، قد تظهر اصطلاحات وحدة نمطية تستخدم externref للتفاعل مع DOM في الوظائف التي تتضمن externref التي تستوردها الوحدة ، مثل parentNode : [externref] -> [externref] و childNode : [externref, i32] -> [externref] . بيئة الوحدة ، مثل المضيف نفسه ، هي التي تعطي في الواقع تفسير externref كمراجع مضيف ، وتوفر تطبيقات للطرق المستوردة التي تدعم هذا التفسير.

ومع ذلك، لم يكن للبيئة وحدة لاستضافة و externref لا يجب أن تكون المراجع المضيف. يمكن أن تكون البيئة وحدة نمطية أخرى توفر وظائف لنوع ما يشبه مراجع المضيف التي تعرض الاصطلاحات المتوقعة. لنفترض أن الوحدة E هي بيئة الوحدة M ، وأن الوحدة M تستورد parentNode و childNode النحو الوارد أعلاه. لنفترض أن E يريد استخدام الوحدة M ولكنه يريد تقييد وصول M إلى DOM ، على سبيل المثال لأن E لديه ثقة محدودة بـ M أو لأن E يريد ربط أي أخطاء قد يكون لدى M ويعرف أن احتياجات M يجب ألا تتجاوز هذه القيود. ما يمكن أن يفعله E هو إنشاء مثيل M باستخدام "MonitoredRef" باعتباره M externref . لنفترض أنه ، على وجه الخصوص ، يريد E إعطاء عقد M DOM ولكن تأكد من أن M لا يسير أعلى شجرة DOM. ثم يمكن أن يكون MonitoredRef الخاص بـ E على وجه التحديد ref (struct externref externref) ، حيث يكون externref (من منظور E) هو عقدة DOM التي يعمل عليها M ، لكن أول externref هو سلف لـ تلك العقدة التي لا يُسمح لـ M بتجاوزها. يمكن لـ E بعد ذلك إنشاء مثيل M's parentNode بحيث يخطئ إذا كان هذان المرجعان متماثلان. ستقوم E نفسها باستيراد وظائفها parentNode و childNode ، مما يجعل E بشكل فعال مراقب وقت تشغيل لتفاعلات DOM.

نأمل أن يكون ذلك ملموسًا بدرجة كافية لرسم الصورة الصحيحة ، بينما لم يكن ملموسًا جدًا بحيث لا تضيع في التفاصيل. من الواضح أن هناك عددًا من الأنماط مثل هذا. لذا أعتقد أن هناك طريقة أخرى لصياغة السؤال وهي ، هل نريد externref لتمثيل مراجع المضيف فقط؟

الجزء الوحيد الذي يبدو مشكوكًا فيه بالنسبة لي هو "ما يمكن أن يفعله E هو إنشاء مثيل M بـ" MonitoredRef "مثل M externref ." ليس لدي انطباع بأن هناك خططًا للسماح بتجريد الأشياء بالظهور على أنها externref في الوحدات النمطية الأخرى. ما أفهمه هو أن externref ليس أداة تجريد على الإطلاق.

أنا لا أعرف أي خطط من هذا القبيل أيضا ؛ أنا أيضًا لا أعرف ما إذا كان أي شخص قد فكر في هذا الخيار. بمعنى ، هل يجب أن يكون externref نوعًا "بدائيًا" ، مثل i32 ، أم نوع "قابل للتجربة" ، مثل الأنواع المستوردة؟

في رسالتي الأصلية ، أشرت إلى أن أيًا من الحالتين يمكن التحكم فيهما. تتمثل مقايضة الذهاب إلى التفسير "البدائي" في أن externref أقل فائدة / قابلية للتركيب بشكل كبير من الأنواع المستوردة ، نظرًا لأن الأخير سيدعم حالات استخدام externref بالإضافة إلى الأنماط المذكورة أعلاه. على هذا النحو ، يبدو من المحتمل أن يصبح "البدائي" externref أثرًا - موجود فقط للتوافق مع الإصدارات السابقة. لكن من غير المرجح أن يكون ذلك مشكلة بشكل خاص ، إنه مجرد مصدر إزعاج. أكبر مشكلة يمكنني رؤيتها هي أنه ، تمامًا مثل حسن التصرف call_indirect على الأنواع الرقمية ، لأنه لا يحتوي على أنواع فائقة ، فإن حسن التصرف البالغ call_indirect قد ينتهي به الأمر بالاعتماد على externref بدون أنواع فائقة أيضًا.

آه هاها ، نعم ، هذا يفسر الاختلاف في الفهم: أتفق مع tlively أن externref ليس مجرّدًا على الإطلاق وليس هناك فكرة "إنشاء مثيل externref بنوع" ، وأنا أعتقد أننا يمكن أن نشعر بثقة تامة بشأن هذا في المستقبل. (نظرًا لأن externref هو نوع بدائي ، على عكس معلمة النوع المعلنة صراحة ، فليس من الواضح كيف يمكن للمرء محاولة إنشاء مثيل له على أساس كل وحدة نمطية.)

في حالة عدم وجود عمليات هبوط ، فإن هذه الحقيقة تجعل wasm شبه عديم الفائدة لتنفيذ / محاكاة واجهات برمجة تطبيقات WASI وهذا هو السبب في أن خطة WASI كانت تنتقل من مقابض i32 مباشرة إلى Type Imports (ولماذا قمت بتقديم نوع استيراد / # 6 ، ب / ج نحتاج حتى قليلا أكثر).

نظرًا لأن externref هو نوع بدائي ، على عكس معلمة النوع المعلنة صراحة ، فليس من الواضح كيف يمكن للمرء محاولة إنشاء مثيل له على أساس كل وحدة.

عندما نضيف استيراد النوع ، يمكننا التعامل مع الوحدات النمطية بدون استيراد النوع ولكن مع وجود externref كوجود import type externref في الأعلى. كل شيء سيتحقق من النوع تمامًا لأنه ، على عكس الأنواع البدائية الأخرى ، لا يحتوي externref على عمليات بدائية مرتبطة (بخلاف وجود قيمة افتراضية). ولكن مع هذا الاستيراد الضمني ، يمكننا الآن القيام بأشياء مثل المحاكاة الافتراضية ووضع الحماية ومراقبة وقت التشغيل.

لكن قبل أن أذهب ذهابًا وإيابًا في ذلك ، أعتقد أنه سيساعد على قياس ما إذا كنا جميعًا على نفس الصفحة حول شيء ما. يُرجى إعلامي إذا كنت توافق أو لا توافق على العبارة التالية والسبب في ذلك: "بمجرد توفر عمليات استيراد النوع ، لا يكون للوحدات النمطية أي سبب لاستخدام externref وتكون أكثر قابلية لإعادة الاستخدام / قابلة للتكوين إذا كانت تستخدم استيراد النوع بدلاً من ذلك."

يُرجى إعلامي إذا كنت توافق أو لا توافق على العبارة التالية والسبب في ذلك: "بمجرد توفر عمليات استيراد النوع ، لا يكون للوحدات النمطية أي سبب لاستخدام externref وتكون أكثر قابلية لإعادة الاستخدام / قابلة للتكوين إذا كانت تستخدم استيراد النوع بدلاً من ذلك."

أنا أتفق مع هذا البيان في الملخص. من الناحية العملية ، أعتقد أن externref سيظل شائعًا في سياقات الويب للإشارة إلى كائنات JS الخارجية لأنه لا يتطلب تكوينًا إضافيًا في وقت إنشاء مثيل. لكن هذا مجرد توقع ولن أمانع إذا تبين أنني مخطئ وتحول الجميع إلى استخدام استيراد النوع بعد كل شيء. تكمن قيمة externref في أنه يمكننا الحصول عليه في وقت أقرب مما يمكننا الحصول عليه بآليات أكثر ثراءً مثل استيراد النوع. أفضل أن أبقي externref بسيطًا وأرى أنه لا يصلح للاستخدام بدلاً من وضعه بشكل محرج ليصبح شيئًا أكثر قوة في وقت لاحق عندما تكون هناك بدائل أكثر أناقة.

tlively ،

FWIW ، لم أفهم أبدًا أن externref قابل للتشغيل من داخل وحدة WebAssembly.

صحيح ، الفكرة هي أن externref هو النوع "البدائي" للمؤشرات الأجنبية. لتلخيص تفاصيل التنفيذ لنوع مرجعي ، ستحتاج إلى شيء آخر: شيء مثل anyref أو استيراد النوع.

lukewagner ،

RossTate :

يشمل هؤلاء الخبراء الذين استشرت معهم مؤلفي بعض الأوراق المذكورة.

ممتاز. ثم أفترض أنك لاحظت أن كتابك هو مؤلف بضع ورقات بنفسه ، في حال كنت تبحث عن مزيد من السلطة. :)

هذا ما سألته:

افترض أن لدي وظيفة متعددة الأشكال f (...). تحتوي لغتي المكتوبة على تصنيف فرعي (فرعي) وصياغة صريحة. ومع ذلك ، يتحقق نوع المصبوب من t1 إلى t2 فقط إذا كان t2 نوعًا فرعيًا من t1. افترض أن متغيرات النوع مثل X افتراضيًا لا تحتوي على أنواع فرعية أو أنواع فائقة (باستثناء نفسها بالطبع). هل تتوقع أن تكون f بارامترية فيما يتعلق بـ X؟

تنهد. سأقدم نفس الرد على هذا السؤال المحدد. لكن هذا السؤال يجسد عدة افتراضات محددة ، على سبيل المثال حول طبيعة القوالب ، وحول التمييز غير المعتاد بين القياس الكمي المحدود وغير المحدود الذي نادرًا ما يوجد في أي لغة برمجة. وأعتقد أن هذا لسبب ما.

عندما قلت "التجريد من النوع الثابت غير كافٍ" ، فأنا لم أقصد أنه غير ممكن من الناحية الفنية (بالطبع هو كذلك) ، لكنه ليس ملائمًا من الناحية العملية. في الممارسة العملية ، لا تريد تشعبًا بين تجريد النوع والتصنيف الفرعي / القابلية (أو بين الأنواع البارامترية وغير البارامترية) ، لأن ذلك من شأنه أن يكسر التركيب المصطنع بناءً على القوالب.

أنا لا أفهم الادعاءات التي تقدمها.

إذا تلقيت قيمة من النوع المجرد ، فقد لا تزال ترغب في نسيان نوعها بالضبط ، على سبيل المثال وضعها في نوع من الاتحاد ، ثم استعادتها لاحقًا من خلال هبوط. قد ترغب في القيام بذلك لنفس السبب الذي قد ترغب فيه لأي نوع مرجعي آخر. لا ينبغي أن يعيق تجريد النوع طريق بعض أنماط الاستخدام الصالحة مع الأنواع العادية من نفس النوع.

يبدو أن إجابتك هي: ماذا إذن ، قم بلف كل شيء في أنواع مساعدة في مواقع الاستخدام المعنية ، على سبيل المثال في المتغيرات. ولكن هذا قد يعني ضمناً التفاف / فك عبوات كبيرة ، ويتطلب ميزات نظام أكثر تعقيدًا ، كما أنه أكثر تعقيدًا في الاستخدام.

أعتقد أن هذا هو ما تخلص إليه العديد من خلافاتنا: ما إذا كان يجب على MVP دعم اتحادات أنواع المراجع ، أو ما إذا كان ينبغي أن يتطلب إدخال أنواع متغيرات صريحة وتشفيرها. للأفضل أو للأسوأ ، تعتبر النقابات مطابقة طبيعية لواجهة كومة المحركات النموذجية ، وهي سهلة ورخيصة لدعمها اليوم. المتغيرات ليست كثيرًا ، فهي نهج بحثي أكثر بكثير من المحتمل أن يؤدي إلى زيادة الحمل وأداء أقل قابلية للتنبؤ ، على الأقل في المحركات الحالية. وأنا أقول ذلك كشخص من النوع الذي يفضل الأنظمة على النقابات في ظروف أخرى ، مثل اللغات التي تواجه المستخدم. ؛)

كتعليق تعريفي ، سأكون ممتنًا حقًا لعدم الحاجة إلى مناشدة السلطة أو إلى CG لسماع اقتراحاتي.

هل لي أن أقترح أن المحادثات حول المقترحات المختلفة قد تعمل بشكل أفضل إذا بدأت من خلال "سؤال" الأبطال المعنيين عن الأشياء غير الواضحة ، على سبيل المثال الأسباب المنطقية المحددة أو الخطط المستقبلية (التي ليست واضحة دائمًا أو مكتوبة بعد) ، قبل _تفهم_ عدم وجود إجابة وتقديم تأكيدات واقتراحات واسعة تستند إلى هذه الافتراضات؟

ممتاز. ثم أفترض أنك لاحظت أن كتابك هو مؤلف بضع ورقات بنفسه ، في حال كنت تبحث عن مزيد من السلطة. :)

نعم ، مما يجعل الأمر إشكاليًا للغاية عندما تقترح أن هناك أوراقًا تدعي أن اقتراحي لا يعمل ، على الرغم من أنك تعلم أن اقتراحي يعالج على وجه التحديد الشروط التي تم تقديم تلك الادعاءات بموجبها.

في الممارسة العملية ، لا تريد تشعبًا بين تجريد النوع والتصنيف الفرعي / القابلية (أو بين الأنواع البارامترية وغير البارامترية) ، لأن ذلك من شأنه أن يكسر التركيب المصطنع بناءً على القوالب.

هذا رأي وليس حقيقة (مما يجعل الاختلاف عليه أمرًا منطقيًا تمامًا بالنسبة لنا). أود أن أقول إنه لا توجد لغات تجميع مكتوبة للصناعة لا تعرف اللغة للأنظمة متعددة اللغات ، وبالتالي من المستحيل تقديم ادعاءات حول الممارسة. هذا شيء يستحق مناقشة شاملة (منفصلة). بالنسبة لهذه المناقشة ، قد يساعدك أولاً تقديم بعض دراسات الحالة التفصيلية حتى يتمكن CG من مقارنة المقايضات.

هل لي أن أقترح أن المحادثات حول المقترحات المختلفة قد تعمل بشكل أفضل إذا بدأت بسؤال الأبطال المعنيين عن الأشياء غير الواضحة ، مثل الأسباب المنطقية المحددة أو الخطط المستقبلية (التي ليست واضحة دائمًا أو مكتوبة بعد) ، قبل افتراض عدم وجود إجابة وتقديم تأكيدات واقتراحات واسعة تستند إلى هذه الافتراضات؟

WebAssembly / Propos-type-import # 4 ، WebAssembly / Propos-type-import # 6 ، و WebAssembly / Propos-type-import # 7 ، كل منها طلب بشكل أساسي مزيدًا من التفاصيل حول هذه الخطة. يُحدد آخر هذه المشكلة إلى GC ، لكن WebAssembly / gc # 86 يشير إلى أن اقتراح GC الحالي لا يدعم في الواقع آليات التجريد الديناميكي.

على مستوى التعريف ، طُلب منا وضع هذه المناقشة جانبًا والتركيز على الموضوع المطروح. لقد وجدت إجابةtlively على سؤالي مفيدة للغاية. أنا في الواقع مهتم جدًا بالحصول على أفكارك تحديدًا حول هذا السؤال.

RossTate :

لقد وجدت إجابةtlively على سؤالي مفيدة للغاية. أنا في الواقع مهتم جدًا بالحصول على أفكارك تحديدًا حول هذا السؤال.

حسنًا ، اعتقدت أنني قد علقت عليه بالفعل أعلاه . أو هل تعني شيئا اخر؟

لا. اعتقدت أن هذا التعليق قد يعني ضمناً الموافقة على رده ، لكنني أردت التأكيد أولاً. شكرا!

lukewagner ، ما هي أفكارك؟

أتفق مع ما سبق أن externref سيكون نوعًا بدائيًا إلى الأبد ولن يُعاد تفسيره بأثر رجعي كمعامل نوع. أعتقد ، بالنظر إلى ذلك ، أنواع المراجع جيدة للعمل كما هي.

أود أن أتناول عرضrossberg لتوسيع نطاق مقترح Type Imports بحيث يغطي قدرة wasm على تنفيذ أنواع مجردة. بمجرد أن نتمكن من تحديد ذلك ، أعتقد أنه سيفتح مزيدًا من المناقشة حول مراجع الوظائف والتصنيف الفرعي.

مذهل. ثم نحن جميعًا في نفس الصفحة (وأنا أيضًا ، أعتقد أن tlively يقدم ملخصًا لطيفًا

لذلك لن يكون externref قابلًا للتشغيل ، ومن المتوقع أن تتحول الوحدات التي تبحث عن تلك المرونة الإضافية لواردات النوع إلى استيراد النوع عند إصدار الميزة. يحدث لي أنه ، لجعل هذا الانتقال سلسًا ، سنحتاج على الأرجح إلى إجرائه بحيث يتم إنشاء مثيل لواردات النوع (بعض؟) بواسطة externref افتراضيًا إذا لم يتم توفير مثيل.

وأود أيضًا قبول العرض لتوسيع نطاق واردات النوع. تحتاج العديد من التطبيقات الرئيسية لواردات النوع إلى التجريد ، لذلك يبدو من الطبيعي بالنسبة لي أن يكون التجريد جزءًا من هذا الاقتراح.

في غضون ذلك ، على الرغم من أننا عالجنا السؤال الملح حول externref ، ما يجب فعله بشكل عام حول call_indirect لا يزال بدون حل ، وإن كان ذلك مع بعض المناقشات المفيدة حول كيفية حلها ، لذلك أنا سأظل نترك القضية مفتوحة.

شكرا!

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات

القضايا ذات الصلة

beriberikix picture beriberikix  ·  7تعليقات

cretz picture cretz  ·  5تعليقات

chicoxyzzy picture chicoxyzzy  ·  5تعليقات

thysultan picture thysultan  ·  4تعليقات

jfbastien picture jfbastien  ·  6تعليقات