call_indirect
ميزة مفيدة جدًا لـ WebAssembly. ومع ذلك ، فقد اعتمدت الكفاءة والسلوك الجيد للتعليمات ضمنيًا على بساطة نظام نوع الوسم. على وجه الخصوص ، كل قيمة wasm لها نوع واحد (ثابت) بالضبط تنتمي إليه. تتجنب هذه الخاصية بشكل ملائم عددًا من المشكلات المعروفة المتعلقة باستدعاءات الوظائف غير المطبوعة في اللغات المكتوبة. ولكن الآن هذا الوسم يمتد إلى ما وراء الأنواع الرقمية ، فقد وصل إلى النقطة التي نحتاج فيها إلى فهم هذه المشكلات ووضعها في الاعتبار.
call_indirect
أساسي من خلال مقارنة توقيع المتصل المتوقع بالتوقيع المحدد للمستدعي. باستخدام الأنواع الرقمية فقط ، كان لدى WebAssembly الخاصية التي تفيد بأن هذه التوقيعات متساوية إذا وفقط إذا تم فحص نوع الاتصال المباشر بالدالة المشار إليها بواسطة funcref
المقابل. لكن هناك سببان لن يكونا صحيحين قريبًا:
call_indirect
للوصول إلى الوظيفة بتوقيعها الخاص المحدد بدلاً من مجرد توقيعها العام الأضعف ( قضية تم اكتشافها للتو وبالتالي لم تتم مناقشتها بعد).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
$fsub
تم تعريفها بالنوع [] -> [tsub]
$fsuper
النوع [] -> [tsuper]
$fsub
كـ $fsuper
(وهو ما يجب القيام به - حتى لو لم يكن ذلك ممكنًا الآن ، فهذه المشكلة تتعلق بالمشكلات القادمة المحتملة)فكر الآن فيما يجب أن يحدث إذا نفذ الوسيط المعرف call_indirect[ -> tsuper](ref.func($fsuper))
. فيما يلي النتيجتان اللتان تبدوان أكثر معقولية:
إذا أردنا اختيار النتيجة 1 ، فعلينا أن ندرك أننا سنحتاج على الأرجح إلى استخدام إحدى الطريقتين لجعل ذلك ممكنًا:
call_indirect
مع توقيع الاستيراد بدلاً من توقيع التعريف.إذا كنت تفضل الأسلوب 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
ونوع الوارداتالآن دعنا نضع التصنيف الفرعي جانبًا ونفكر في استيراد النوع . للراحة ، سأتحدث عن استيراد النوع ، بدلاً من مجرد استيراد النوع المرجعي ، ولكن هذه التفاصيل غير مهمة. للمثال الجاري هنا ، افترض ما يلي:
capability
ويصدر النوع وليس تعريفه كـ $handle
$do_stuff
تم تعريفها بالنوع [capability] -> []
ولكن تم تصديرها بالنوع [$handle] -> []
$extern
ووظيفة $run
بالنوع [$extern] -> []
$handle
كـ $extern
ومع تصدير IA $do_stuff
كـ $run
ما يتم إعداده في هذا المثال هو وحدتان حيث تقوم وحدة واحدة بعمل أشياء مع قيم الوحدة الأخرى دون معرفة هذه القيم أو السماح لها بمعرفة هذه القيم. على سبيل المثال ، هذا النمط هو الأساس المخطط للتفاعل مع WASI.
لنفترض الآن أن معرف المثيل تمكن من الحصول على قيمة e
من النوع $extern
وتنفيذ call_indirect[$extern -> ](ref.func($run), e)
. فيما يلي النتيجتان اللتان تبدوان أكثر معقولية:
النتيجة 2 تجعل call_indirect
عديمة الفائدة إلى حد كبير مع الأنواع المستوردة. لذلك بالنسبة للنتيجة 1 ، عليك أن تدرك أن نوع الإدخال $extern
ليس نوع الإدخال المحدد $do_stuff
(والذي بدلاً من ذلك capability
) ، لذلك من المحتمل أن نحتاج إلى استخدام أحد تقنيتان لسد هذه الفجوة:
call_indirect
مع توقيع الاستيراد بدلاً من توقيع التعريف.$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
.
(آسف على المنشور الطويل. لقد بذلت قصارى جهدي لشرح التفاعلات المعقدة لميزات الكتابة متعددة الوحدات ، والكتابة ، والوقت ، والتقاء ، ووقت التشغيل ، وإظهار أهمية تلك التفاعلات بإيجاز قدر الإمكان.)
شكرا لهذه الكتابة التفصيلية ، روس! لدي سؤال صغير: في قسم " 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
"بتوقيع الاستيراد بدلاً من توقيع التعريف."
وقد أضفت أنه (بسبب مراجع الوظيفة المكتوبة) نحتاج أيضًا
- قم بإجراء فحص وقت التشغيل الخطي على الأقل للتأكد من توافق النوع الفرعي للتوقيع المتوقع وتوقيع التعريف.
هل يجب أن يكون هذا التوافق بين "التوقيع المتوقع وتوقيع الاستيراد "؟ نظرًا لأننا نفترض أننا قمنا بإجراء مقارنة استيراد 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
:
CHandle
ربما تنفذ واجهات. سيكون لمثيلات هذه الفئة عضو (على مستوى wasm) من النوع Handle
وجدول v الذي يوفر مؤشرات دالة لتطبيقات طرق مختلفة للفئة والواجهة. عند إعطائها لوظيفة متعددة الأشكال على مستوى السطح ، والتي تكون على مستوى wasm مجرد وظيفة على الكائنات ، يمكن للوحدة استخدام نفس الآلية التي تستخدمها للإرسال إلى فئات أخرى للإرسال إلى CHandle
.THandle
الذي يتناسب مع هذه المعايير ولديه عضو (على مستوى wasm) من النوع Handle
. ستؤدي وظائفها متعددة الأشكال بعد ذلك إلى تحويل قيم OCaml إلى THandle
تمامًا كما تفعل مع أي نوع بيانات جبري أو نوع سجل آخر.بعبارة أخرى ، نظرًا لأن الوحدات النمطية تعتمد على معايير حول كيفية تمثيل قيم المستوى السطحي من أجل تنفيذ أشياء مثل الوظائف متعددة الأشكال ، وأن الأنواع المستوردة المجردة مثل Handle لا تفي بهذه المعايير ، فإن التفاف القيم أمر لا مفر منه. هذا هو نفس سبب استبدال أحد التطبيقات الأصلية لـ anyref
بأنواع الواجهة. وقمنا بتطوير دراسات حالة توضح أن anyref
ليس ضروريًا ، ولا حتى مناسبًا تمامًا ، لدعم الوظائف متعددة الأشكال.
من ناحية أخرى ، لقد أظهرت أنه يمكن استخدام castable anyref
للتحايل على آليات التجريد الثابتة. إن خطة آلية التجريد التي أشرت إليها هي محاولة لإصلاح هذه المشكلة من خلال آليات التجريد الديناميكي. لكن هناك عددًا من المشكلات المتعلقة بآليات التجريد الديناميكي. على سبيل المثال ، لا يمكن تصدير نوع i31ref
كنوع تجريدي Handle
بدون المخاطرة بوحدات نمطية أخرى تستخدم anyref
والصب لتزوير مقابض (على سبيل المثال للقدرات). بدلاً من ذلك ، يتعين على المرء أن يقفز من خلال الأطواق والنفقات الإضافية التي ستكون غير ضرورية إذا قمنا بدلاً من ذلك فقط بالتأكد من التجريد الثابت القياسي.
أيضًا ، الآن (على ما أعتقد) فهمت بشكل أفضل كيف تنوي استخدام الأنواع الدقيقة ، أدرك أن نيتك لا تعالج أيًا من المشكلتين الرئيسيتين اللتين لفتت انتباهي إليهما باستخدام call_indirect
والتصنيف الفرعي:
call_indirect
(والذي أعتقد أنك قلته بالفعل صراحة)call_indirect
لاستخدام دالة مُصدَّرة بتوقيعها المحدد بدلاً من توقيعها المُصدَّر.لذا فهذه ليست مشكلة تافهة يجب حلها. لهذا السبب ، نظرًا لضيق الوقت ، أفضل التركيز على تقييم كيفية منحنا الوقت لحلها بشكل صحيح. لا أعتقد أنه من الضروري إجراء مناقشة أولاً حول ما إذا كان anyref
يستحق التخلص من التجريد الثابت. هذا هو نوع المناقشة الكبيرة التي كنت آمل في تجنبها من أجل عدم تأخير الأمور أكثر.
من ناحية أخرى ، لقد أثبتت أنه يمكن استخدام أي مرجع castable للتحايل على آليات التجريد الثابتة.
تجريد النوع الثابت غير كافٍ في لغة ذات قوالب كتابة ديناميكية. لأن التجريد الساكن يعتمد على البارامترية ، ويفكك ذلك. لا يوجد شيء جديد في ذلك ، فقد كُتبت أوراق حول هذا الموضوع. هناك حاجة إلى آليات تجريد أخرى في مثل هذا السياق.
محاولة التغلب على ذلك من خلال تقييد استخدام الأنواع المجردة يتعارض مع الغرض منها. ضع في اعتبارك حالة استخدام WASI. لا يهم ما إذا كان يتم تنفيذ وحدة WASI وأي نوع تصدره بواسطة المضيف أو في Wasm. إذا قمت بتقييد أنواع الملخصات التي يحددها المستخدم بشكل تعسفي ، فلن يكون تطبيق Wasm قابلاً للتبادل مع تطبيق المضيف بشكل عام.
- لا يساعد في إنشاء تصنيف فرعي للاحترام غير المباشر (والذي أعتقد أنك قلته بالفعل صراحة)
هاه؟ إنه جزء من قواعد التصنيف الفرعي ، وكذلك بالتعريف.
- لا يمنع استخدام 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
لا يزال بدون حل ، وإن كان ذلك مع بعض المناقشات المفيدة حول كيفية حلها ، لذلك أنا سأظل نترك القضية مفتوحة.
شكرا!
التعليق الأكثر فائدة
تجريد النوع الثابت غير كافٍ في لغة ذات قوالب كتابة ديناميكية. لأن التجريد الساكن يعتمد على البارامترية ، ويفكك ذلك. لا يوجد شيء جديد في ذلك ، فقد كُتبت أوراق حول هذا الموضوع. هناك حاجة إلى آليات تجريد أخرى في مثل هذا السياق.
محاولة التغلب على ذلك من خلال تقييد استخدام الأنواع المجردة يتعارض مع الغرض منها. ضع في اعتبارك حالة استخدام WASI. لا يهم ما إذا كان يتم تنفيذ وحدة WASI وأي نوع تصدره بواسطة المضيف أو في Wasm. إذا قمت بتقييد أنواع الملخصات التي يحددها المستخدم بشكل تعسفي ، فلن يكون تطبيق Wasm قابلاً للتبادل مع تطبيق المضيف بشكل عام.
هاه؟ إنه جزء من قواعد التصنيف الفرعي ، وكذلك بالتعريف.
أنا لم أقل ذلك. لقد قلت إن هذه المشكلة ليست مشكلة في call_indirect نفسها ، ولكنها مسألة اختيار آلية تجريد مناسبة للنوع للغة ذات قوالب.
جانبا ، لا يوجد سبب مقنع لتجميع OCaml (أو أي لغة مماثلة) يجب أن يتطلب إدخال أنواع المتغيرات. حتى لو كان ذلك أسرع قليلاً من الناحية النظرية (والذي أشك في أنه سيكون هو الحال في محركات الجيل الحالي ، على الأرجح العكس) ، فإن الأنواع المتغيرة تعد من المضاعفات المهمة التي لا ينبغي أن تكون ضرورية لـ MVP. أنا لا أشاركك تمامًا في شهيتك للتعقيد المبكر. ؛)
إعادة المساواة في الوظائف: هناك لغات ، مثل Haskell أو SML ، لا تدعم ذلك ، لذلك قد تستفيد مباشرة من المراجع الوظيفية. يرمي OCaml لتحقيق المساواة الهيكلية ولديه بشكل صريح سلوك محدد للتنفيذ لشخص مادي. يُترك مفتوحًا سواء كان ذلك يسمح دائمًا بإرجاع خطأ أو رمي للوظائف ، ولكن قد يكون أي منهما كافياً من الناحية العملية ، ويستحق الاستكشاف قبل الالتزام بتغليف إضافي مكلف.
[كتعليق ميتا ، سأكون ممتنًا حقًا إذا قللت من محاضرتك وربما فكرت في فكرة أن هذا العالم ، ربما ، مجموعة الأشخاص الأكفاء ليست فردية وأن آثار الأدمغة قد تم تطبيقها من قبل.]