Design: call_indirect versus abstraktion

Erstellt am 7. Mai 2020  ·  36Kommentare  ·  Quelle: WebAssembly/design

call_indirect war eine sehr nützliche Funktion für WebAssembly. Die Effizienz und das gute Verhalten der Anweisung beruht jedoch implizit auf der Einfachheit des Typensystems von wasm. Insbesondere hat jeder wasm-Wert genau einen (statischen) Typ, zu dem er gehört. Diese Eigenschaft vermeidet praktischerweise eine Reihe bekannter Probleme mit nicht typisierten Funktionsaufrufen in typisierten Sprachen. Aber jetzt, wo wasm über numerische Typen hinausgeht, ist es an einem Punkt angelangt, an dem wir diese Probleme verstehen und im Auge behalten müssen.

call_indirect funktioniert grundsätzlich durch den Vergleich der erwarteten Signatur des Anrufers mit der definierten Signatur des Angerufenen. Bei rein numerischen Typen hatte WebAssembly die Eigenschaft, dass diese Signaturen genau dann gleich waren, wenn ein direkter Aufruf der Funktion, auf die das entsprechende funcref verweist, eine Typprüfung durchgeführt hätte. Aber es gibt zwei Gründe, die bald nicht zutreffen werden:

  1. Bei der Untertypisierung würde ein direkter Aufruf funktionieren, solange die definierte Signatur der tatsächlichen Funktion eine "Untersignatur" der erwarteten Signatur ist, d. h. alle Eingabetypen sind Untertypen der Parametertypen der Funktion und alle Ausgabetypen sind Obertypen der Funktionstypen Ergebnistypen bzw. Dies bedeutet, dass eine Gleichheitsprüfung zwischen der erwarteten Signatur eines indirekten Aufrufs und der definierten Signatur der Funktion in einer Reihe von absolut sicheren Situationen einfangen würde, was für die Unterstützung von Sprachen mit starker Verwendung von Subtyping und indirekten Aufrufen problematisch sein könnte (wie in der Diskussion über Subtypisierung aufschieben). Es bedeutet auch, dass, wenn ein Modul absichtlich eine Funktion mit einer schwächeren Signatur exportiert, als die Funktion definiert wurde, call_indirect verwendet werden kann, um auf die Funktion mit ihrer privat definierten Signatur zuzugreifen und nicht nur mit ihrer schwächeren öffentlichen Signatur ( ein Problem, das gerade entdeckt wurde und daher noch nicht diskutiert wurde).
  2. Mit Typimporten kann ein Modul einen Typ exportieren, ohne die Definition dieses Typs zu exportieren, was eine Abstraktion bietet, auf die sich Systeme wie WASI stark verlassen wollen. Diese Abstraktion verhindert, dass andere Module zur Kompilierzeit von ihrer jeweiligen Definition abhängig sind. Aber zur Laufzeit wird der abstrakt exportierte Typ einfach durch seine Definition ersetzt. Dies ist zum Beispiel wichtig, damit call_indirect mit exportierten Funktionen ordnungsgemäß funktioniert, deren exportierte Signaturen auf diesen exportierten Typ verweisen. Wenn ein bösartiges Modul jedoch die Definition dieses exportierten Typs kennt, kann es call_indirect , um zwischen dem exportierten Typ und seiner geheimen Definition hin und her zu konvertieren, denn call_indirect vergleicht Signaturen nur zur Laufzeit, wenn die beiden Typen tatsächlich gleich sind . So kann ein bösartiges Modul call_indirect um auf Geheimnisse zuzugreifen, die vom exportierten Typ abstrahiert werden sollen, und kann call_indirect , um Werte des exportierten Typs zu fälschen, die sicherheitskritische Invarianten verletzen könnten, die nicht in die Definition des Typs selbst.

In beiden oben genannten Situationen kann call_indirect verwendet werden, um die Abstraktion der exportierten Signatur eines Moduls zu umgehen. Wie ich bereits erwähnt habe, war dies bisher kein Problem, da wasm nur numerische Typen hatte. Und ursprünglich dachte ich, dass durch das Aufschieben der Subtypisierung auch alle Bedenken bezüglich call_indirect effektiv aufgeschoben wurden. Aber was mir vor kurzem klar wurde, ist, dass der "neue" Typ (in https://github.com/WebAssembly/reference-types/pull/87) durch das Entfernen von Subtyping als externref wird für einen abstrakten Typimport. Wenn die Leute es tatsächlich so haben möchten, müssen wir leider die obige Interaktion zwischen call_indirect und Typimporten berücksichtigen.

Nun gibt es viele Möglichkeiten, die oben genannten Probleme mit call_indirect anzugehen, aber jeder hat seine Kompromisse und der Gestaltungsraum ist einfach viel zu groß, um schnell eine Entscheidung treffen zu können. Ich schlage also nicht vor , dass wir dieses Problem hier und jetzt lösen. Die Entscheidung, die im Moment getroffen werden muss, ist vielmehr, ob man Zeit gewinnt, um das Problem in Bezug auf externref richtig zu lösen. Insbesondere dann , wenn wir jetzt beschränkt call_indirect und func.ref auf nur geben Prüfung , wenn die zugehörige Signatur vollständig numerisch ist, dann dienen wir alle der Kern-wasm Anwendungsfälle von indirekten Anrufen und bei der gleichzeitig Raum für alle möglichen Lösungen für die oben genannten Probleme lassen. Ich weiß jedoch nicht, ob diese Einschränkung praktisch ist, sowohl im Hinblick auf den Implementierungsaufwand als auch darauf, ob sie die Anwendungen von externref behindert, auf die die Leute warten. Die Alternative besteht darin, call_indirect und func.ref unverändert zu lassen. Es ist nur möglich, dass dies je nach Lösung, zu der wir kommen, externref möglicherweise nicht wie ein echter Typimport instanziierbar ist und/oder dass externref (ironischerweise) nicht in der Lage sein, beliebige Supertypen zu haben (z. B. möglicherweise kein Untertyp von anyref wenn wir uns schließlich entscheiden, anyref hinzuzufügen).

Ich spreche für mich allein, beide Optionen halte ich für überschaubar. Obwohl ich eine Präferenz habe, dränge ich die Entscheidung, in die eine oder andere Richtung zu gehen, nicht stark, und ich glaube, dass Sie alle besseren Zugang zu den Informationen haben, die für eine fundierte Entscheidung erforderlich sind. Ich wollte nur, dass Sie alle wissen, dass eine Entscheidung ansteht, und gleichzeitig mit call_indirect Bewusstsein für das übergreifende Thema schaffen. Wenn Sie eine ausführlichere Erläuterung dieses Problems als die obige Zusammenfassung wünschen, lesen Sie bitte Folgendes.

call_indirect versus Abstraktion im Detail

Ich verwende die Notation call_indirect[ti*->to*](func, args) , wobei [ti*] -> [to*] die erwartete Signatur der Funktion ist, func einfach ein Funcref ist (eher eine Funcref-Tabelle und ein Index) und args sind die to* Werte, die an die Funktion übergeben werden. In ähnlicher Weise verwende ich call($foo, args) für einen direkten Aufruf der Funktion mit dem Index $foo die Argumente args übergibt.

Nehmen wir nun an, $foo ist der Index einer Funktion mit deklarierten Eingabetypen ti* und Ausgabetypen to* . Sie könnten erwarten, dass call_indirect[ti*->to*](ref.func($foo), args) call($foo, args) . Tatsächlich ist das aktuell der Fall. Aber es ist nicht klar, ob wir dieses Verhalten beibehalten können.

call_indirect und Subtyping

Ein Beispiel für ein potenzielles Problem tauchte in der Diskussion über die Subtypisierung auf. Angenommen, Folgendes:

  • tsub ist ein Untertyp von tsuper
  • Modulinstanz IA exportiert eine Funktion $fsub , die mit dem Typ [] -> [tsub] defined definiert wurde
  • Modul MB importiert eine Funktion $fsuper Typ [] -> [tsuper]
  • Modulinstanz IB ist Modul-MB, das mit IAs $fsub als $fsuper instanziiert ist (was vernünftig ist – auch wenn es jetzt nicht möglich ist, geht es in diesem Problem um potenzielle bevorstehende Probleme)

Überlegen Sie nun, was passieren soll, wenn IB call_indirect[ -> tsuper](ref.func($fsuper)) ausführt. Hier sind die beiden Ergebnisse, die am plausibelsten erscheinen:

  1. Der Aufruf ist erfolgreich, da die erwartete Signatur und die definierte Signatur kompatibel sind.
  2. Der Anruf wird abgefangen, weil die beiden Signaturen unterschiedlich sind.

Wenn wir Ergebnis 1 wählen würden, müssen wir feststellen, dass wir wahrscheinlich eine von zwei Techniken anwenden müssen, um dies zu ermöglichen:

  1. Lassen Sie bei importierten Funktionen call_indirect mit der Importsignatur und nicht mit der Definitionssignatur vergleichen.
  2. Führen Sie eine Laufzeitprüfung zu mindestens linearer Zeit auf Subtyp-Kompatibilität der erwarteten Signatur und der Definitionssignatur durch.

Wenn Sie Technik 1 bevorzugen, stellen Sie fest, dass es nicht funktioniert, wenn wir typisierte Funktionsreferenzen (mit Varianten-Untertypisierung) hinzufügen. Das heißt, func.ref($fsub) wird ein ref ([] -> [tsub]) und auch ein ref ([] -> [tsuper]) , und dennoch wird Technik 1 nicht ausreichen, um call_indirect[ -> super](ref.func($fsub)) vom Einfangen abzuhalten. Dies bedeutet, dass Ergebnis 1 wahrscheinlich Technik 2 erfordert, was Auswirkungen auf die Leistung hat.

Betrachten wir also Ergebnis 2 etwas genauer. Die Implementierungstechnik hier besteht darin, zu prüfen, ob die erwartete Signatur von call_indirect in IB gleich der Signatur der Definition von $fsub in IA ist. Auf den ersten Blick scheint der größte Nachteil dieser Technik darin zu bestehen, dass sie eine Reihe von Aufrufen abfängt, die sicher ausgeführt werden können. Ein weiterer Nachteil ist jedoch, dass es möglicherweise ein Sicherheitsleck für IA einführt.

Um zu sehen , wie, wechseln wir auf unser Beispiel ein wenig und nehmen wir an, dass, obwohl Beispiel IA intern definiert $fsub haben , geben Sie [] -> [tsub] , Beispiel IA exportiert es nur mit Typ [] -> [tsuper] . Mit der Technik für Ergebnis 2 kann Instanz IB (böswillig) call_indirect[ -> tsub]($fsuper) ausführen und der Aufruf wird erfolgreich sein. Das heißt, IB kann call_indirect , um die Einengung zu umgehen, die IA an der Signatur seiner Funktion vorgenommen hat. Das bedeutet bestenfalls, dass IB von einem Aspekt von IA abhängig ist, der nicht durch die Unterschrift von IA garantiert wird. Schlimmstenfalls kann IB dies verwenden, um auf interne Zustände zuzugreifen, die IA möglicherweise absichtlich verheimlicht hat.

call_indirect und Typimporte

Nun wollen wir beiseite legen Subtypisierung und Typ Importe berücksichtigen. Der Einfachheit halber werde ich über Typimporte sprechen und nicht nur über Referenztypimporte, aber dieses Detail ist belanglos. Nehmen Sie für das laufende Beispiel hier Folgendes an:

  • Modulinstanz IC definiert einen Typ capability und exportiert den Typ, aber nicht seine Definition als $handle
  • Modulinstanz IC exportiert eine Funktion $do_stuff , die mit dem Typ [capability] -> [] aber mit dem Typ [$handle] -> [] exportiert wurde
  • Modul MD importiert einen Typ $extern und eine Funktion $run mit dem Typ [$extern] -> []
  • Modulinstanz-ID ist Modul-MD, die mit IAs exportierten $handle als $extern und mit IAs exportierten $do_stuff als $run instanziiert wurde

In diesem Beispiel werden zwei Module eingerichtet, bei denen ein Modul die Werte des anderen Moduls verarbeitet, ohne zu wissen oder wissen zu dürfen, was diese Werte sind. Dieses Muster ist beispielsweise die geplante Grundlage für die Interaktion mit WASI.

Nehmen wir nun an, die Instanz-ID hat es geschafft, einen Wert e vom Typ $extern und führt call_indirect[$extern -> ](ref.func($run), e) . Hier sind die beiden Ergebnisse, die am plausibelsten erscheinen:

  1. Der Aufruf ist erfolgreich, da die erwartete Signatur und die definierte Signatur kompatibel sind.
  2. Der Anruf wird abgefangen, weil die beiden Signaturen unterschiedlich sind.

Ergebnis 2 macht call_indirect mit importierten Typen ziemlich nutzlos. Beachten Sie also für Ergebnis 1, dass der Eingabetyp $extern nicht der definierte Eingabetyp von $do_stuff (der stattdessen capability ), also müssten wir wahrscheinlich einen von zwei Techniken, um diese Lücke zu schließen:

  1. Lassen Sie bei importierten Funktionen call_indirect mit der Importsignatur und nicht mit der Definitionssignatur vergleichen.
  2. Beachten Sie, dass zur Laufzeit der Typ $extern in der Instanz-ID capability .

Wenn Sie Technik 1 bevorzugen, stellen Sie fest, dass es wieder nicht funktioniert, wenn wir typisierte Funktionsreferenzen hinzufügen. (Der grundlegende Grund ist der gleiche wie beim Subtyping, aber es würde noch mehr Text brauchen, um das Analoge hier zu veranschaulichen.)

Damit bleiben wir bei Technik 2. Leider stellt dies erneut ein potenzielles Sicherheitsproblem dar. Um den Grund zu sehen, nehmen wir an, dass ID bösartig ist und an den Inhalt von $handle gelangen möchte, den IC geheim gehalten hat. Angenommen, ID hat eine gute Vermutung, was $handle wirklich darstellt, nämlich capability . ID kann die Identitätsfunktion $id_capability vom Typ [capability] -> [capability] . Bei einem Wert e vom Typ $extern kann ID dann call_indirect[$extern -> capability](ref.func($id_capability), e) ausführen. Mit Technik 2 wird dieser indirekte Aufruf erfolgreich sein, da $extern capability zur Laufzeit darstellt und ID die rohen capability zurückbekommt, die e darstellt. In ähnlicher Weise kann ID bei einem Wert c vom Typ capability call_indirect[capability -> $extern](ref.func($id_capability), c) ausführen, um c in ein $extern zu fälschen.

Abschluss

Hoffentlich habe ich deutlich gemacht, dass in call_indirect eine Reihe von bedeutenden bevorstehenden Leistungs-, Semantik- und/oder Sicherheits-/Abstraktionsproblemen auftreten – Probleme, die WebAssembly bisher glücklicherweise vermieden hat. Da call_indirect Teil der zentralen WebAssembly ist, überschneiden sich diese Probleme leider mit einer Reihe von Vorschlägen, die in Arbeit sind. Im Moment denke ich , es wäre am besten auf dem dringendsten solchen Vorschlag zu konzentrieren, Referenztypen, wo wir brauchen , um zu entscheiden , ob oder nicht beschränken call_indirect und func.ref nur numerische Typen für jetzt – eine Einschränkung, die wir möglicherweise lockern können, je nachdem, wie wir letztendlich die übergreifenden Probleme mit call_indirect lösen.

(Entschuldigung für den langen Beitrag. Ich habe mein Bestes gegeben, um die komplexen Interaktionen von modulübergreifenden Funktionen zur Kompilierung-Zeit-Typisierung-trifft-Laufzeit-Typisierung zu erklären und die Bedeutung dieser Interaktionen so prägnant wie möglich zu demonstrieren.)

Hilfreichster Kommentar

Auf der anderen Seite haben Sie gezeigt, dass umsetzbare Anyref verwendet werden kann, um statische Abstraktionsmechanismen zu umgehen.

Die statische Typabstraktion ist in einer Sprache mit dynamischen Typumwandlungen unzureichend. Weil statische Abstraktion auf Parametrizität beruht und Casts diese brechen. Daran ist nichts Neues, es wurden Papiere darüber geschrieben. In einem solchen Kontext werden andere Abstraktionsmechanismen benötigt.

Der Versuch, dies zu umgehen, indem die Verwendung abstrakter Typen eingeschränkt wird, verfehlt ihren Zweck. Betrachten Sie den WASI-Anwendungsfall. Es sollte keine Rolle spielen, ob ein WASI-Modul und ein beliebiger Typ, den es exportiert, vom Host oder in Wasm implementiert wird. Wenn Sie benutzerdefinierte abstrakte Typen willkürlich einschränken, wäre eine Wasm-Implementierung nicht mehr mit einer Host-Implementierung im Allgemeinen austauschbar.

  1. Es trägt nicht dazu bei, dass call_indirect die Subtypisierung respektiert (was Sie meiner Meinung nach bereits explizit gesagt haben).

Hä? Es ist Teil der Subtyping-Regeln, was es per Definition auch tut.

  1. Es verhindert nicht, dass call_indirect verwendet wird, um eine exportierte Funktion mit ihrer definierten Signatur anstelle ihrer exportierten Signatur zu verwenden.

Ich habe nicht gesagt, dass es so ist. Ich sagte, dass dies kein Problem mit call_indirect selbst ist, sondern eine Frage der Auswahl eines geeigneten Typabstraktionsmechanismus für eine Sprache mit Casts.

Abgesehen davon gibt es keinen zwingenden Grund, warum das Kompilieren von OCaml (oder einer ähnlichen Sprache) die Einführung von Variantentypen erfordern sollte. Auch wenn das theoretisch etwas schneller sein könnte (was ich bei Motoren der aktuellen Generation bezweifle, eher im Gegenteil), sind Variantentypen eine erhebliche Komplikation, die für den MVP nicht notwendig sein sollte. Ich teile Ihren Appetit auf verfrühte Komplexität nicht ganz. ;)

Gleichheit bei Funktionen: Es gibt Sprachen wie Haskell oder SML, die dies nicht unterstützen und daher direkt von func refs profitieren könnten. OCaml wirft für strukturelle Gleichheit und hat explizit implementierungsdefiniertes Verhalten für physisches. Es bleibt offen, ob dies immer die Rückgabe von false oder das Werfen von Funktionen ermöglicht, aber beides könnte in der Praxis ausreichen und es lohnt sich, es zu erkunden, bevor Sie sich auf kostspielige zusätzliche Umhüllungen festlegen.

[Als Meta-Kommentar würde ich mich sehr freuen, wenn Sie Ihre Vorlesungen abschwächen und vielleicht die Idee in Betracht ziehen, dass dies eine Welt ist, in der die Menge kompetenter Leute vielleicht nicht einzeln ist und dass Spuren von Gehirnen gelegentlich zuvor verwendet wurden.]

Alle 36 Kommentare

Danke für diese ausführliche Beschreibung, Ross! Ich habe eine kleine Frage: Im Abschnitt " call_indirect und Typimporte" schreiben Sie,

Wenn Sie Technik 1 bevorzugen, stellen Sie fest, dass es wieder nicht funktioniert, wenn wir typisierte Funktionsreferenzen hinzufügen.

Unterliegt dies auch dem Vorbehalt aus dem vorherigen Abschnitt, dass das Problem nur auftritt, wenn wir den typisierten Funktionsreferenzen Varianten-Untertypisierung hinzufügen?

Es ist nicht. Alle Probleme im Abschnitt für die Untertypisierung sind unabhängig von Typimporten, und alle Probleme im Abschnitt für Typimporte sind unabhängig von der Untertypisierung. Bezüglich des speziellen Problems, nach dem Sie fragen, sollten Sie bedenken, dass ein Wert vom Typ ref ([] -> [capability]) von einer exportierten Funktion als Wert vom Typ ref ([] -> [$handle]) , der dann in a umgewandelt werden kann funcref und indirekt aufgerufen. Anders als bei der exportierten Funktion, diese Änderung-in-Perspektive des Wertes geschieht zur Laufzeit statt Verbindung Zeit, so dass wir es durch einen Vergleich mit dem Import Signatur nicht lösen können , da die Funktionsreferenz wurde nie selbst importiert.

module instance IC defines a type capability and exports the type but not its definition as $handle
Wie wird das funktionieren? Es muss etwas geben, das capability und $handle damit IC weiß, wie man damit umgeht?
Auch basierend auf https://github.com/WebAssembly/proposal-type-imports/blob/master/proposals/type-imports/Overview.md#exports sind importierte Typen komplett abstrakt. Selbst wenn $capability exportiert wird, ist es abstrakt. Vielleicht verstehe ich etwas falsch.

Ähnliche Frage für den Export für module instance IC exports a function $do_stuff that was defined with type [capability] -> [] but exported with type [$handle] -> [] .

Ich kann mir vorstellen, dass dafür eine Art von Subtyping-Relation verwendet wird, zB wenn $capability <: $handle , dann können wir export $capability as $handle . Aber am Anfang dieses Abschnitts wurde erwähnt, dass man die Subtypisierung beiseite legt, also lege ich das beiseite... Aber ich habe auch ein bisschen mehr darüber nachgedacht:
Wenn: $capability <: $handle , können wir export $capability as $handle , aber export ([$capability] -> []) as ([$handle] -> []) sollte "fehlschlagen", da Funktionen im Argument kontravariant sind.

Bei Typexporten gibt ein Modul eine Signatur an, z. B. type $handle; func $do_stuff_export : [$handle] -> [] , und instanziiert dann die Signatur, z. B. type $handle := capability; func $do_stuff_export := $do_stuff . (Ignorieren Sie die spezifische Syntax vollständig.) Der Typ-Checker prüft dann: "Ist der Export func $do_stuff_export := $do_stuff in diesem Modul gültig, wenn $handle capability in diesem Modul repräsentiert?". Da der Typ von $do_stuff [capability] -> [] , stimmt seine Signatur genau mit der von $do_stuff_export überein, nachdem $handle mit capability instanziiert wurde Prüfung gelingt. (Hier gibt es keine Untertypisierung, sondern nur eine Variablensubstitution.)

Beachten Sie jedoch, dass die Signatur selbst nichts über $handle aussagt. Das bedeutet, dass alle anderen $handle als abstrakten Typ behandeln sollen. Das heißt, die Signatur abstrahiert absichtlich Details der Implementierung des Moduls, und alle anderen sollen diese Abstraktion respektieren. Der Zweck dieser Ausgabe ist zu veranschaulichen, dass call_indirect verwendet werden kann, um diese Abstraktion zu umgehen.

Das klärt das Problem hoffentlich ein wenig!

Danke, das klärt die Dinge. Ich habe eine Frage zum Subtyping-Abschnitt (sorry, dass ich herumspringe):

Ich verfolge das Szenario, in dem wir möchten, dass die IB-Ausführung von call_indirect[ -> tsuper](ref.func($fsuper)) erfolgreich ist, indem call_indirect "mit der Importsignatur und nicht mit der Definitionssignatur verglichen wird."

Und Sie haben hinzugefügt, dass wir (wegen der typisierten Funktionsreferenzen) auch brauchen

  1. Führen Sie eine Laufzeitprüfung zu mindestens linearer Zeit auf Subtyp-Kompatibilität der erwarteten Signatur und der Definitionssignatur durch.

Sollte dies Kompatibilität zwischen "erwarteter Signatur und der Importsignatur " sein? Da wir davon ausgehen, dass wir call_indirect veranlasst haben, die Importsignatur mit der erwarteten Signatur zu vergleichen.

Wenn die Kompatibilität zwischen erwartet und importiert wird, sollte call_indirect[ -> tsub]($fsuper) fehlschlagen.

Die Techniken 1 und 2 werden als zwei orthogonale Wege angegeben, um diesen indirekten Aufruf zum Laufen zu bringen. Leider ist Technik 1 mit typisierten Funktionsreferenzen nicht kompatibel und Technik 2 ist wahrscheinlich zu teuer. Beides scheint also wahrscheinlich nicht zu funktionieren. Daher betrachtet der Rest des Abschnitts, was passiert, wenn wir keines davon verwenden und einfach beim einfachen Gleichheitsvergleich zwischen der erwarteten und der definierten Signatur bleiben. Entschuldigung für die Verwirrung; Da ich keine geplante Semantik habe, muss ich drei mögliche Semantiken diskutieren.

Achten Sie darauf, nicht zu viele Schlüsse zu ziehen. ;)

Meine Annahme ist, dass call_indirect so schnell bleiben sollte wie heute und daher immer nur einen Typäquivalenztest erfordern, egal wie viel Subtyping wir der Sprache hinzufügen. Gleichzeitig muss die Laufzeitprüfung mit dem statischen Typsystem kohärent sein, dh die Subtypisierungsbeziehung respektieren.

Nun, diese scheinbar widersprüchlichen Anforderungen lassen sich relativ leicht in Einklang bringen, solange wir sicherstellen, dass die mit call_indirect verwendbaren Typen immer an den Blättern der Subtyphierarchie stehen.

Eine etablierte Methode, dies zu erzwingen, besteht darin, den Begriff _exakter_ Typen in das Typsystem einzuführen. Ein exakter Typ hat keine Untertypen, nur Supertypen, und wir hätten (exact T) <: T .

Damit können wir verlangen, dass der Zieltyp bei call_indirect ein exakter Typ ist. Darüber hinaus ist der Funktionstyp selbst natürlich bereits der genaue Typ dieser Funktion.

Ein Modul könnte auch beim Funktionsimport genaue Typen verlangen, wenn es sicherstellen wollte, dass es nur mit Funktionen instanziiert werden kann, die einer beabsichtigten Laufzeitprüfung erfolgreich sind.

Das ist alles, was benötigt wird, um sicherzustellen, dass die aktuelle Implementierungstechnik eines einfachen Zeigervergleichs auf kanonisierte Funktionstypen gültig bleibt. Es ist unabhängig davon, welche anderen Untertypisierungen es gibt oder wie ausgefallen wir die Funktionsuntertypisierung machen. (FWIW, ich habe dies vor einiger Zeit mit Luke besprochen und geplant, eine PR zu erstellen, aber sie wurde aufgrund ausstehender Änderungen an der Subtyping-Geschichte und dem Vorschlag, zu dem sich jetzt bewegt, blockiert.)

(Ein Nachteil ist, dass die Verfeinerung einer Funktionsdefinition zu einem Untertyp im Allgemeinen keine abwärtskompatible Änderung mehr ist, zumindest nicht, wenn der genaue Typ irgendwo verwendet wurde. Aber dieser Nachteil ist unter unseren Einschränkungen unvermeidlich, unabhängig davon, wie wir genau erzwingen Sie.)

Ein paar nebenbei:

Die Alternative besteht darin, call_indirect und func.ref unverändert zu lassen.

AFAICS, es ist nicht möglich, ref.func für Funktionen zu verbieten, die Referenztypen beinhalten. Das würde viele Anwendungsfälle ernsthaft lahmlegen, dh alles, was erstklassige Funktionen betrifft, die auf externref (Callbacks, Hooks usw.).

Es ist nur möglich, dass dies bedeutet, dass externref je nach Lösung nicht instanziierbar ist wie ein echter Typimport, und/oder dass externref (ironischerweise) keine Supertypen haben kann (zB möglicherweise nicht in der Lage sein, ein Untertyp von anyref zu sein, wenn wir uns schließlich dazu entschließen, anyref hinzuzufügen).

Können Sie näher erläutern? Ich sehe die Verbindung nicht.

Achten Sie darauf, nicht zu viele Schlüsse zu ziehen. ;)

Ich bin mir nicht sicher, auf welche Schlussfolgerung Sie sich beziehen. Meine erklärte Schlussfolgerung ist, dass es eine Reihe von Problemen mit call_indirect , die wir beachten müssen und für die wir mit der Planung beginnen sollten. Sie scheinen anzudeuten, dass diese Probleme belanglos sind, weil Sie eine Lösung im Sinn haben. Aber diese Lösung wurde von der CG weder überprüft noch akzeptiert, und wir sollten sie nicht planen, bis dies der Fall ist. Ich habe ausdrücklich darum gebeten, keine Lösungen zu diskutieren, weil es eine Weile dauern wird, sie zu bewerten und zu vergleichen, und wir müssen Entscheidungen treffen, bevor wir Zeit haben, diese Bewertungen und Vergleiche richtig durchzuführen. Aber um zu verhindern, dass die Leute den Eindruck bekommen, dass dieses Problem gelöst ist, und damit die dringende Entscheidung zu vermeiden, werde ich mir eine Sekunde Zeit nehmen, um Ihre Lösung schnell zu besprechen.

Eine etablierte Methode, dies zu erzwingen, besteht darin, den Begriff der exakten Typen in das Typsystem einzuführen.

Exakte Typen sind kaum eine etablierte Lösung. Wenn überhaupt, haben exakte Typen Probleme festgestellt, an deren Lösung ihre Befürworter noch arbeiten. Interessanterweise ist hier ein Thread, in dem das TypeScript-Team ursprünglich gesehen hat, wie genaue Typen des von Ihnen vorgeschlagenen Formulars einige Probleme lösen könnten, aber dann haben sie schließlich [realisiert](https://github.com/microsoft/TypeScript/issues/12936 #issuecomment-284590083), dass genaue Typen mehr Probleme mit sich brachten, als sie lösten. (Anmerkung für den Kontext: Diese Diskussion wurde durch die exakten Objekttypen von Flow

Als Beispiel dafür, wie sich diese Art von Problemen auf WebAssembly auswirken könnten, nehmen wir an, wir hätten die Subtypisierung nicht verschoben. Der Typ von ref.null wäre exact nullref mit genauen Typen. Aber exact nullref wäre kein Untertyp von exact anyref . Tatsächlich würden gemäß der üblichen Semantik exakter Typen wahrscheinlich keine Werte zu exact anyref da wahrscheinlich kein Wert genau anyref zur Laufzeit hat. Dies würde call_indirect für anyref s völlig unbrauchbar machen.

Jetzt haben Sie vielleicht eine andere Version von genauen Typen im Sinn, aber es würde eine Weile dauern, um zu überprüfen, ob diese andere Version die vielen offenen Probleme mit genauen Typen irgendwie behebt. Mein Punkt hier ist also nicht, diese Lösung zu verwerfen, sondern anzuerkennen, dass dies nicht offensichtlich die Lösung ist, und keine Entscheidungen mit dieser Erwartung zu treffen.

Können Sie näher erläutern? Ich sehe die Verbindung nicht.

Sie beziehen sich auf einen langen Satz. Auf welchen Teil davon soll ich näher eingehen? Eine Vermutung ist, dass Sie möglicherweise das Gesamtproblem mit call_indirect und Typimporten übersehen. Ihr Vorschlag für genaue Typen behebt nur Probleme mit der Untertypisierung, aber wir haben oben festgestellt, dass call_indirect auch ohne Untertypisierung Probleme hat.

Das würde viele Anwendungsfälle ernsthaft lahmlegen, dh alles, was erstklassige Funktionen betrifft, die auf externref operieren (Callbacks, Hooks usw.).

Ja, das ist etwas, über das ich gehofft hatte, mehr Informationen zu erhalten. Meines Wissens ist der Hauptanwendungsfall von call_indirect die Unterstützung von C/C++-Funktionszeigern und virtuellen C++-Methoden. Ich verstehe auch, dass dieser Anwendungsfall derzeit auf numerische Signaturen beschränkt ist. Ich kenne mehr Einsatzmöglichkeiten von call_indirect , aber wie ich schon erwähnte ich eine vorübergehende Einschränkung darauf hindeutet, so was zählt , ist , was die aktuellen Anwendungen von sind call_indirect . Angesichts der Tatsache, dass call_indirect immer noch eine Tabelle und einen Index erfordert und nicht nur ein funcref , scheint es nicht besonders gut für die Unterstützung von Rückrufen geeignet zu sein. Ich wusste nicht, ob das daran lag, dass es derzeit nicht für diesen Zweck verwendet wird.

Sie kennen die Codebasen, die auf diese Funktion abzielen, viel besser als ich. Wenn Sie also alle echten Programme kennen, die diese Funktionalität jetzt benötigen, wäre es sehr hilfreich, hier ein paar Beispiele für die benötigten Nutzungsmuster bereitzustellen. Diese Beispiele sind nicht nur nützlich, um herauszufinden, ob wir diese Funktionalität jetzt unterstützen müssen, sondern auch, wenn die Funktionalität jetzt benötigt wird.

@RossTate :

Wenn überhaupt, haben exakte Typen Probleme festgestellt, an deren Lösung ihre Befürworter noch arbeiten. Interessanterweise ist hier ein Thread, in dem das TypeScript-Team ursprünglich gesehen hat, wie exakte Typen des von Ihnen vorgeschlagenen Formulars einige Probleme lösen könnten, aber dann erkannten sie schließlich, dass exakte Typen mehr Probleme mit sich brachten, als sie lösten. (Anmerkung für den Kontext: Diese Diskussion wurde durch die exakten Objekttypen von Flow angeregt, die eigentlich keine Form von exakten Typen (im theoretischen Sinne) sind, sondern stattdessen einfach das Objektanalog der Präfix-Subtypisierung verbieten.) Ich könnte mir vorstellen, dass wir diesen Thread wiederholen Hier.

Die Klammern sind hier der Schlüssel. Ich bin mir nicht sicher, was genau sie in diesem Thread im Sinn haben, aber es scheint nicht dasselbe zu sein. Andernfalls würden Aussagen wie "es wird angenommen, dass ein Typ T & U immer T zuweisbar ist, aber das schlägt fehl, wenn T ein exakter Typ ist" keinen Sinn machen (dies ist nicht scheitert nicht, weil T & U ungültig oder unten wäre). Bei den anderen Fragen geht es hauptsächlich um Pragmatik, dh wo würde ein Programmierer sie verwenden wollen (für Objekte), die in unserem Fall nicht zutreffen.

Waren exakte Typen für Low-Level-Schriftsysteme nicht sogar in einigen Ihrer eigenen Arbeiten eine entscheidende Zutat?

Als Beispiel dafür, wie sich diese Art von Problemen auf WebAssembly auswirken könnten, nehmen wir an, wir hätten die Subtypisierung nicht verschoben. Der Typ von ref.null wäre mit exakten Typen exakt nullref. Aber exakte Nullref wäre kein Untertyp von exakter Anyref.

Keine Meinungsverschiedenheit hier. Das Fehlen von Untertypen ist der Zweck von exakten Typen.

Tatsächlich würden gemäß der üblichen Semantik exakter Typen wahrscheinlich keine Werte zu exakt anyref gehören, da wahrscheinlich der Laufzeittyp eines Werts genau anyref ist.

Richtig, die Kombination (exact anyref) ist kein nützlicher Typ, da der einzige Zweck von anyref darin besteht, ein Supertyp zu sein. Aber warum ist das ein Problem?

Dies würde call_indirect für Anyrefs völlig unbrauchbar machen.

Sind Sie sicher, dass Sie jetzt die Level nicht verwechseln? Ein Funktionstyp (exact (func ... -> anyref)) ist vollkommen nützlich. Es ist einfach nicht kompatibel mit einem Typ, sagen wir (func ... -> (ref $T)) . Das heißt, exact verhindert die nicht-triviale Subtypisierung von Funktionstypen. Aber das ist der springende Punkt!

Vielleicht verwechselst du (exact (func ... -> anyref)) mit (func ... -> exact anyref) ? Dies sind nicht verwandte Typen.

Ihr Vorschlag für genaue Typen behebt nur Probleme mit der Untertypisierung, aber wir haben oben festgestellt, dass call_indirect auch ohne Untertypisierung Probleme hat.

Sie gehen irgendwie davon aus, dass Sie einen Typ ohne seine Definition exportieren können, um einen abstrakten Datentyp zu definieren. Dieser Ansatz funktioniert offensichtlich nicht in Gegenwart dynamischer Typumwandlungen (call_indirect oder anderweitig). Deshalb sage ich immer wieder, dass wir eine Typabstraktion im Newtype-Stil brauchen, nicht eine Typabstraktion im ML-Stil.

Mein Verständnis ist, dass der primäre Anwendungsfall von call_indirect darin besteht, C/C++-Funktionszeiger zu unterstützen

Ja, aber das ist nicht der einzige Anwendungsfall von ref.func , auf den ich mich bezog, weil Sie ihn in Ihre vorgeschlagene Einschränkung aufgenommen haben (vielleicht unnötig?). Insbesondere wird es call_ref , das keine Typprüfungen beinhaltet.

Sie gehen irgendwie davon aus, dass Sie einen Typ ohne seine Definition exportieren können, um einen abstrakten Datentyp zu definieren. Dieser Ansatz funktioniert offensichtlich nicht in Gegenwart dynamischer Typumwandlungen (call_indirect oder anderweitig). Deshalb sage ich immer wieder, dass wir eine Typabstraktion im Newtype-Stil brauchen, nicht eine Typabstraktion im ML-Stil.

Okay, Sie scheinen also zuzustimmen, dass genaue Typen nichts tun, um das Problem mit call_indirect und Typimport zu beheben. Aber Sie sagen auch, dass es keinen Sinn macht, dieses Problem anzugehen, da es aufgrund von Laufzeit-Casts sowieso ein Problem sein wird. Es gibt eine einfache Möglichkeit, dieses Problem zu vermeiden: Erlauben Sie Benutzern nicht, Laufzeitumwandlungen für abstrakte Typen durchzuführen (es sei denn, der abstrakte Typ sagt ausdrücklich, dass er umsetzbar ist). Schließlich ist es ein undurchsichtiger Typ, daher sollten wir nicht davon ausgehen können, dass er die für einen Guss erforderliche Struktur aufweist. Selbst wenn also die Möglichkeit besteht, dass exakte Typen das Subtyping-Problem lösen, ist es verfrüht, die andere Hälfte des Problems zu ignorieren.

Wie gesagt, jede Lösung hat Kompromisse. Sie scheinen davon auszugehen, dass Ihre Lösung nur die Kompromisse aufweist, die Sie selbst identifiziert haben, und Sie scheinen davon auszugehen, dass die CG Ihre Lösung anderen vorziehen würde. Auch ich habe eine mögliche Lösung für dieses Problem. Es garantiert zeitkonstante Kontrollen, basiert auf einer Technologie, die bereits in virtuellen Maschinen verwendet wird, adressiert alle Probleme hier (glaube ich), erfordert keine neuen Typen und fügt WebAssembly mit bekannten Anwendungen sogar zusätzliche Funktionen hinzu. Ich gehe jedoch nicht davon aus, dass es so funktioniert, wie ich es erwarte, und dass ich einige Mängel nicht übersehen habe, weil Sie und andere keine Gelegenheit hatten, es zu überprüfen. Ich gehe auch nicht davon aus, dass die CG ihre Kompromisse denen alternativer Optionen vorziehen würde. Stattdessen versuche ich herauszufinden, was wir tun können, um uns Zeit zu geben, die Optionen zu analysieren, damit die CG und nicht nur ich derjenige sein kann, der eine fundierte Entscheidung zu diesem Querschnittsthema trifft.

Insbesondere wird es call_ref , das keine Typprüfungen beinhaltet.

Das Schlüsselwort in Ihrem Satz ist Wille . Ich bin mir voll bewusst , dass es Anwendungen von call_indirect mit nicht-numerischen Typen , dass die Menschen wollen unterstützt haben. Und ich erwarte , dass wir mit einem Design kommen wird , dass Träger , die Funktionalität und die Adressen der oben genannten Probleme. Aber wie gesagt, idealerweise haben wir etwas Zeit, um dieses Design zu entwickeln, damit wir nicht schnell ein Feature mit übergreifenden Auswirkungen ausliefern, bevor wir diese Auswirkungen untersucht haben. Meine Frage ist also, ob es jetzt große Programme gibt, die diese Funktionalität benötigen. Wenn ja, brauchen Sie keine Hypothesen aufzustellen; Zeigen Sie einfach auf einige und veranschaulichen Sie, wie sie sich derzeit auf diese Funktionalität verlassen.

Sie gehen irgendwie davon aus, dass Sie einen Typ ohne seine Definition exportieren können, um einen abstrakten Datentyp zu definieren. Dieser Ansatz funktioniert offensichtlich nicht in Gegenwart dynamischer Typumwandlungen (call_indirect oder anderweitig). Deshalb sage ich immer wieder, dass wir eine Typabstraktion im Newtype-Stil brauchen, nicht eine Typabstraktion im ML-Stil.

Das scheint mir ein grundsätzliches Problem zu sein. Ist die Gewährleistung der Vertraulichkeit der Definitionen exportierter Typen ein Ziel des Vorschlags für Typenimporte? Ich entnehme diesem Thread, dass @rossberg denkt, dass es derzeit kein Ziel ist. Lassen Sie uns diese Frage diskutieren und uns darauf einigen, bevor wir Lösungen diskutieren, damit wir alle von den gleichen Annahmen aus arbeiten können.

@RossTate :

Okay, Sie scheinen also zuzustimmen, dass genaue Typen nichts tun, um das Problem mit call_indirect und type import zu beheben.

Ja, wenn Sie damit die Frage meinen, wie man ein Feature zum Definieren abstrakter Datentypen hinzufügt. Es gibt eine Reihe von Möglichkeiten, wie die Typabstraktion konsistent funktionieren kann, aber eine solche Funktion wird noch weiter entfernt.

Das Schlüsselwort in Ihrem Satz ist Wille. Ich bin mir bewusst, dass es Anwendungen von call_indirect mit nicht-numerischen Typen gibt, die die Leute gerne unterstützt haben.

Die Anweisung call_ref befindet sich im Vorschlag der Funktion ref, also ziemlich nahe, auf jeden Fall vor jedem möglichen Mechanismus des abstrakten Datentyps. Schlagen Sie vor, dass wir es bis dahin auf Eis legen?

@tlively :

Ist die Gewährleistung der Vertraulichkeit der Definitionen exportierter Typen ein Ziel des Vorschlags für Typenimporte? Ich entnehme diesem Thread, dass @rossberg denkt, dass es derzeit kein Ziel ist.

Es ist ein Ziel, aber ein Mechanismus für abstrakte Datentypen ist eine separate Funktion. Und ein solcher Mechanismus muss so gestaltet sein, dass er die Gestaltung der Einfuhren nicht beeinflusst. Wenn dies der Fall wäre, würden wir es sehr falsch machen – die Abstraktion muss an der Definitionsstelle sichergestellt werden, nicht an der Verwendungsstelle. Glücklicherweise ist dies jedoch kein Hexenwerk, und der Designraum ist ziemlich gut ausgebaut.

Danke @rossberg , das macht Sinn. Das Hinzufügen von Abstraktionsprimitiven in einem Folgevorschlag nach Typimporten und -exporten klingt für mich gut, aber es wäre großartig, wenn wir die Details dazu aufschreiben könnten, wie wir dies bald irgendwo tun wollen. Der Entwurf von Typimporten und -exporten schränkt den Entwurf von abstrakten Typimporten und -exporten ein und informiert ihn. Daher ist es wichtig, dass wir eine gute Vorstellung davon haben, wie die Abstraktion im weiteren Verlauf funktionieren wird, bevor wir den ursprünglichen Entwurf abschließen.

Können Sie nicht nur diesen Plan detailliert beschreiben, da dieses Problem mit call_indirect zeigt, dass es dringende Entscheidungen beeinflusst )? Sie sind undurchsichtig, so dass die Suggestion der gängigen Praxis abstrakter Typen zu entsprechen scheint.

@tlively , ja, stimmte zu. Plus verschiedene andere Dinge, die ich für eine Weile aufschreiben wollte. Werde ich tun, wenn ich alle Folgen von #69 durchgearbeitet habe. ;)

@RossTate , da dies abstrakte Datentypen mit

@rossberg Können Sie klarstellen, was dieser zentrale Anwendungsfall ist, den Sie im Sinn haben? Meine beste Vermutung bei der Interpretation Ihres Beispiels ist trivial lösbar, aber vielleicht meinen Sie etwas anderes.

@RossTate , betrachten polymorphe Funktionen. Abgesehen von Wasm-Generika sollte es möglich sein, sie beim Kompilieren mit Up/Down-Casts von anyref mit Werten vom abstrakten Typ wie alle anderen zu verwenden, ohne dass sie extra in andere Objekte gewickelt werden müssen. Im Allgemeinen möchten Sie in der Lage sein, Werte des abstrakten Typs wie alle anderen zu behandeln.

Okay, betrachten wir polymorphe Funktionen und nehmen wir an, der importierte Typ ist Handle :

  1. Java hat polymorphe Funktionen. Seine polymorphen Funktionen erwarten, dass alle Werte (Java-Referenz) Objekte sind. Insbesondere müssen sie über eine V-Tabelle verfügen. Ein Java-Modul, das Handle verwendet, wird wahrscheinlich eine Java-Klasse CHandle angeben, die möglicherweise Schnittstellen implementiert. Die Instanzen dieser Klasse haben ein Member (auf Wasm-Ebene) vom Typ Handle und eine V-Tabelle, die Funktionszeiger auf die Implementierungen verschiedener Klassen- und Schnittstellenmethoden bereitstellt. Wenn es einer polymorphen Funktion auf Oberflächenebene übergeben wird, die auf Wasm-Ebene nur eine Funktion für Objekte ist, kann das Modul den gleichen Mechanismus verwenden, den es für das Umwandeln in andere Klassen verwendet, um in CHandle .
  2. OCaml hat polymorphe Funktionen. Seine polymorphen Funktionen erwarten, dass alle OCaml-Werte physikalische Gleichheit unterstützen. Da wasm über die Typsicherheit von OCaml keine Schlüsse ziehen kann, werden seine polymorphen Funktionen wahrscheinlich auch starken Gebrauch von Casts machen müssen. Eine spezielle Gussstruktur würde dies wahrscheinlich effizienter machen. Aus einem dieser Gründe würde ein OCaml-Modul wahrscheinlich einen algebraischen Datentyp oder Datensatztyp THandle angeben, der in diese Normen passt und einen (wasm-level) Member vom Typ Handle . Seine polymorphen Funktionen würden dann OCaml-Werte in THandle umwandeln, genau wie in jeden anderen algebraischen Datentyp oder Datensatztyp.

Mit anderen Worten, da Module auf Normen für die Darstellung von Werten auf Oberflächenebene angewiesen sind, um Dinge wie polymorphe Funktionen zu implementieren, und abstrakte importierte Typen wie Handle diese Normen nicht erfüllen, ist das Umschließen von Werten unvermeidlich. Dies ist der gleiche Grund, warum eine der ursprünglichen Anwendungen für anyref durch Schnittstellentypen ersetzt wurde. Und wir haben Fallstudien entwickelt anyref weder notwendig noch gut geeignet ist, um polymorphe Funktionen zu unterstützen.

Andererseits haben Sie gezeigt, dass mit Castable anyref statische Abstraktionsmechanismen umgangen werden können. Der Abstraktionsmechanismus-Plan, auf den Sie anspielten, ist ein Versuch, dieses Problem durch dynamische Abstraktionsmechanismen zu beheben. Es gibt jedoch eine Reihe von Problemen mit dynamischen Abstraktionsmechanismen. Zum Beispiel kann man Ihren i31ref Typ nicht als seinen abstrakten Handle Typ exportieren, ohne dass andere Module anyref und in Forge-Handles (zB in Fähigkeiten) umwandeln. Stattdessen muss man durch zusätzliche Reifen und Overheads springen, die unnötig wären, wenn wir stattdessen nur die standardmäßige statische Abstraktion sicherstellen würden.

Und jetzt, da ich (glaube ich) besser verstehe, wie Sie exakte Typen verwenden möchten, ist mir klar, dass Ihre Absicht keines der beiden Hauptprobleme anspricht, auf die ich mit call_indirect und Subtyping aufmerksam gemacht habe:

  1. Es hilft nicht, dass call_indirect Subtyping respektiert (was Sie, glaube ich, bereits explizit gesagt haben)
  2. Es verhindert nicht, dass call_indirect verwendet wird, um eine exportierte Funktion mit ihrer definierten Signatur anstelle ihrer exportierten Signatur zu verwenden.

Dies ist also kein triviales Problem zu lösen. Aus diesem Grund würde ich mich angesichts der Zeitbeschränkungen lieber darauf konzentrieren, zu evaluieren, wie wir uns Zeit geben können, um das Problem richtig zu lösen. Ich denke nicht, dass es notwendig sein sollte, zuerst darüber zu diskutieren, ob es sich lohnt, die statische Abstraktion für anyref wegzulassen. Das ist die Art von großer Diskussion, die ich vermeiden wollte, um die Dinge nicht weiter hinauszuzögern.

Auf der anderen Seite haben Sie gezeigt, dass umsetzbare Anyref verwendet werden kann, um statische Abstraktionsmechanismen zu umgehen.

Die statische Typabstraktion ist in einer Sprache mit dynamischen Typumwandlungen unzureichend. Weil statische Abstraktion auf Parametrizität beruht und Casts diese brechen. Daran ist nichts Neues, es wurden Papiere darüber geschrieben. In einem solchen Kontext werden andere Abstraktionsmechanismen benötigt.

Der Versuch, dies zu umgehen, indem die Verwendung abstrakter Typen eingeschränkt wird, verfehlt ihren Zweck. Betrachten Sie den WASI-Anwendungsfall. Es sollte keine Rolle spielen, ob ein WASI-Modul und ein beliebiger Typ, den es exportiert, vom Host oder in Wasm implementiert wird. Wenn Sie benutzerdefinierte abstrakte Typen willkürlich einschränken, wäre eine Wasm-Implementierung nicht mehr mit einer Host-Implementierung im Allgemeinen austauschbar.

  1. Es trägt nicht dazu bei, dass call_indirect die Subtypisierung respektiert (was Sie meiner Meinung nach bereits explizit gesagt haben).

Hä? Es ist Teil der Subtyping-Regeln, was es per Definition auch tut.

  1. Es verhindert nicht, dass call_indirect verwendet wird, um eine exportierte Funktion mit ihrer definierten Signatur anstelle ihrer exportierten Signatur zu verwenden.

Ich habe nicht gesagt, dass es so ist. Ich sagte, dass dies kein Problem mit call_indirect selbst ist, sondern eine Frage der Auswahl eines geeigneten Typabstraktionsmechanismus für eine Sprache mit Casts.

Abgesehen davon gibt es keinen zwingenden Grund, warum das Kompilieren von OCaml (oder einer ähnlichen Sprache) die Einführung von Variantentypen erfordern sollte. Auch wenn das theoretisch etwas schneller sein könnte (was ich bei Motoren der aktuellen Generation bezweifle, eher im Gegenteil), sind Variantentypen eine erhebliche Komplikation, die für den MVP nicht notwendig sein sollte. Ich teile Ihren Appetit auf verfrühte Komplexität nicht ganz. ;)

Gleichheit bei Funktionen: Es gibt Sprachen wie Haskell oder SML, die dies nicht unterstützen und daher direkt von func refs profitieren könnten. OCaml wirft für strukturelle Gleichheit und hat explizit implementierungsdefiniertes Verhalten für physisches. Es bleibt offen, ob dies immer die Rückgabe von false oder das Werfen von Funktionen ermöglicht, aber beides könnte in der Praxis ausreichen und es lohnt sich, es zu erkunden, bevor Sie sich auf kostspielige zusätzliche Umhüllungen festlegen.

[Als Meta-Kommentar würde ich mich sehr freuen, wenn Sie Ihre Vorlesungen abschwächen und vielleicht die Idee in Betracht ziehen, dass dies eine Welt ist, in der die Menge kompetenter Leute vielleicht nicht einzeln ist und dass Spuren von Gehirnen gelegentlich zuvor verwendet wurden.]

Als Meta-Kommentar würde ich mich sehr freuen, wenn du deine Vorlesungen etwas abschwächen würdest

Gehört.

und vielleicht die Idee in Betracht gezogen, dass dies eine Welt ist, in der die Menge der kompetenten Leute vielleicht nicht Singleton ist und dass Spuren von Gehirnen gelegentlich früher verwendet wurden.

Mein Rat hier basiert auf der Beratung mit mehreren Experten.

Die statische Typabstraktion ist in einer Sprache mit dynamischen Typumwandlungen unzureichend. Weil statische Abstraktion auf Parametrizität beruht und Casts diese brechen. Daran ist nichts Neues, es wurden Papiere darüber geschrieben. In einem solchen Kontext werden andere Abstraktionsmechanismen benötigt.

Zu diesen Experten, die ich konsultiert habe, gehören Autoren einiger dieser Veröffentlichungen.

Um nun zu überprüfen, ob ich ihre Ratschläge richtig zusammengefasst habe, habe ich gerade einem anderen Autor einiger dieser Artikel eine E-Mail geschickt, einen, den ich noch nie zuvor mit diesem Thema besprochen habe. Hier ist, was ich gefragt habe:

Angenommen, ich habe eine polymorphe Funktion f(...). Meine typisierte Sprache hat (subsumptive) Subtyping und explizites Casting. Bei einer Typumwandlung von t1 nach t2 wird jedoch nur überprüft, ob t2 ein Untertyp von t1 ist. Angenommen, Typvariablen wie X haben standardmäßig keine Untertypen oder Supertypen (außer sich selbst natürlich). Würden Sie erwarten, dass f bezüglich X relational parametrisch ist?

Hier war ihre Antwort:

Ja, ich denke, dies wäre parametrisch, da die einzige Möglichkeit darin besteht, Umwandlungen auf X zu schreiben, die einer Identitätsfunktion entsprechen, die bereits relational parametrisch ist.

Dies entspricht meinem Rat. Nun, dies ist natürlich eine Vereinfachung des vorliegenden Problems, aber wir haben uns bemüht, das Problem genauer auf WebAssembly zu untersuchen, und bis jetzt hat unsere Untersuchung ergeben, dass diese Erwartung sogar auf der Ebene von WebAssembly weiterhin besteht außer call_indirect , daher dieses Problem.

Beachten Sie, dass die Theoreme, auf die Sie sich beziehen, für Sprachen gelten, in denen alle Werte umsetzbar sind. Aus dieser Beobachtung entstand die Idee, die Gießbarkeit einzuschränken.

Betrachten Sie den WASI-Anwendungsfall.

Ich verstehe deine Behauptungen nicht. Wir haben den WASI-Anwendungsfall betrachtet. Bei uns binde ich mehrere Experten für Sicherheit und sogar speziell für fähigkeitsbasierte Sicherheit ein.

Als Meta-Kommentar würde ich es wirklich begrüßen, wenn ich mich nicht an die Behörde oder an die CG wenden müsste, um meine Vorschläge zu hören. Ich schlug vor, dass das Einschränken von Besetzungen es ermöglichen würde, statische Parametrizität auch bei Vorhandensein von Besetzungen sicherzustellen. Sie haben diesen Vorschlag sofort ignoriert und sich auf frühere Papiere berufen, um diese Entlassung zu rechtfertigen. Als ich jedoch einem Autor dieser Papiere denselben Vorschlag machte, kamen sie sofort zu dem gleichen Ergebnis wie ich und wie Sie es hätten haben können. Zuvor hatte ich vorgeschlagen, dass die Bewertung möglicher Lösungen ein langer Prozess sein würde. Sie ignorierten diesen Vorschlag und bestanden darauf, dass Sie (allein) das Problem gelöst hätten, und zogen uns beide in dieses lange Gespräch. Es ist extrem schwierig, Fortschritte zu machen und nicht frustriert zu werden, wenn die eigenen Vorschläge immer wieder so beiläufig abgetan werden. (Ich sollte klarstellen, dass ich Ihren Vorschlag hier nicht als mögliche Lösung abtun möchte; ich versuche zu zeigen, dass dies nicht die einzige Lösung ist und daher neben verschiedenen anderen bewertet werden sollte.)

Ich denke, es ist wichtig und zeitgemäß, ein detailliertes Design festzunageln und zu prüfen, das die in dieser Ausgabe aufgeworfenen Bedenken anspricht: Ich glaube nicht, dass abstrakte Typen als weiter entferntes Merkmal betrachtet werden sollten; WASI braucht sie jetzt-ish.

Ich hoffe auch, dass exact + newtype die Bedenken ausräumen können, aber ich stimme zu, dass wir die Farm zu diesem Zeitpunkt nicht einfach auf diese Vermutung wetten können, indem wir uns vorzeitig auf ein Design festlegen, wenn Wir versenden (in Kürze) Referenztypen. Wir brauchen Zeit, um eine angemessene Diskussion darüber zu führen.

Davon abgesehen sehe ich keine Gefahr darin, externref in call_indirect Signaturen im Vorschlag für Referenztypen zuzulassen. Ja, wenn ein Modul einen externref Wert exportiert (als const global oder als Rückgabe von einer Funktion ...), haben wir noch nicht festgenagelt, ob wir diesen externref downcasten können. Aber call_indirect ist kein Downcasting eines externref ; es ist ein Downcasting von funcref , und externref hat keine andere Rolle als i32 bei der Prüfung call_indirect sehe ich daher nicht, wie wir uns auf eine neue Designentscheidung festlegen, zu der wir uns noch nicht im MVP verpflichtet haben .

Wenn keine Gefahr besteht, könnten wir diese intensive Diskussion vielleicht auf eine weniger intensive Diskussion im Type Imports-Vorschlag reduzieren (wo ich immer noch denke, dass wir eine angemessene Unterstützung für abstrakte Typen aufnehmen sollten)?

Sicher. Ich denke, es ist eine gute Idee zu prüfen, ob eine Gefahr besteht oder nicht.

Was WASI betrifft, so ist das Design immer noch sehr im Fluss, aber eine Option, die immer noch praktikabel erscheint, besteht darin, etwas wie i31ref für seine "Handles" zu verwenden, beispielsweise weil es keine dynamische Speicherzuweisung erfordert. WASI kann sich für andere Optionen entscheiden, aber der Punkt weiß derzeit niemand, und es wäre schön, wenn Entscheidungen, die jetzt getroffen werden, solche Entscheidungen auf der ganzen Linie nicht beeinflussen.

Derzeit ist externref der einzige verfügbare abstrakte Typ, und daher würde ein WASI-basierter Host externref mit i31ref (oder was auch immer WASI-"Handles" sind) instanziieren. Aber mein Verständnis ist, dass WASI seine Implementierung so weit wie möglich in WebAssembly verlagern möchte, um hostabhängigen Code zu reduzieren. Um dies zu erleichtern, möchten WASI-Systeme möglicherweise externref wie jeden anderen Typimport behandeln und ihn mit dem abstrakt exportierten WASI-Typ Handle instanziieren. Aber wenn Handle i31ref , dann kann die obige Implementierung von call_indirect benötigt wird, damit es über Modulgrenzen hinweg funktioniert, auch verwendet werden, um Benutzer Handles über externref fälschen zu lassen

Eine meiner Fragen, von der ich jetzt merke, dass sie in meinem ursprünglichen Beitrag nicht klar formuliert wurde, lautet: Wollen die Leute, dass externref instanziierbar ist, genau wie andere abstrakte Importe?

Eine meiner Fragen, von der ich jetzt merke, dass sie in meinem ursprünglichen Beitrag nicht klar formuliert wurde, ist, dass die Leute wollen, dass externref instanziierbar ist, genau wie andere Importe abstrakter Typen?

Danke, dass Sie diese Frage explizit gestellt haben. FWIW, ich habe nie verstanden, dass externref innerhalb eines WebAssembly-Moduls instanziierbar ist. Das impliziert die Beteiligung des Hosts an der Virtualisierung, wenn WASI externref als Handles verwenden möchte, aber das scheint mir in Ordnung zu sein, oder scheint zumindest eine trennbare Diskussion zu sein.

Hmm, mal sehen, ob ich das klären kann. Ich vermute, Sie sind bereits mit einigen der folgenden Dinge an Bord, aber es ist einfacher für mich, ganz von vorne anzufangen.

Aus der Sicht eines wasm-Moduls bedeutet externref keine Host-Referenz. Es ist nur ein undurchsichtiger Typ, von dem das Modul nichts weiß. Vielmehr sind es die Konventionen um externref , die es als Host-Referenz interpretieren. Zum Beispiel würden die Konventionen eines Moduls, das externref um mit dem DOM zu interagieren, in den Funktionen ersichtlich, die externref , die das Modul importiert, wie parentNode : [externref] -> [externref] und childNode : [externref, i32] -> [externref] . Die Umgebung des Moduls, z. B. der Host selbst, gibt tatsächlich die Interpretation von externref als Hostreferenzen und stellt Implementierungen der importierten Methoden bereit, die diese Interpretation bestätigen.

Allerdings ist die Umgebung des Moduls nicht sein muß der Host und externref muss nicht Host - Referenzen sein. Die Umgebung könnte ein weiteres Modul sein, das Funktionalität für einen Typ bereitstellt, der wie Hostreferenzen aussieht, die die erwarteten Konventionen aufweisen. Nehmen wir an, Modul E ist die Umgebung von Modul M, und dieses Modul M importiert parentNode und childNode wie oben. Nehmen wir an, E möchte das Modul M verwenden, möchte aber den Zugriff von M auf das DOM einschränken, beispielsweise weil E nur begrenztes Vertrauen in M ​​hat oder weil E alle Fehler, die M haben könnte, begrenzen möchte und weiß, dass die Bedürfnisse von M diese Einschränkungen nicht überschreiten sollten. Was E tun könnte, ist M mit "MonitoredRef" als externref M zu instanziieren. Nehmen wir an, E möchte insbesondere M DOM-Knoten geben, aber sicherstellen, dass M im DOM-Baum nicht weiter nach oben wandert. Dann könnte die MonitoredRef von E speziell ref (struct externref externref) , wobei das zweite externref (aus der Perspektive von E) der DOM-Knoten ist, auf dem M operiert, aber der erste externref ist ein Vorfahre von dieser Knoten, an dem M nicht vorbeigehen darf. E könnte dann parentNode M instanziieren, so dass es irrt, wenn diese beiden Referenzen gleich sind. E selbst würde seine eigenen parentNode und childNode Funktionen importieren, wodurch E effektiv zu einem Laufzeitmonitor von DOM-Interaktionen wird.

Hoffentlich war das konkret genug, um das richtige Bild zu zeichnen, aber nicht zu konkret, um sich in Details zu verlieren. Es gibt offensichtlich eine Reihe solcher Muster. Ich denke, eine andere Möglichkeit, die Frage zu formulieren, ist, wollen wir, dass externref immer nur exakte Host-Referenzen darstellt?

Der einzige Teil, der für mich fragwürdig klingt, ist "was E tun könnte, ist M mit "MonitoredRef" als externref M instanziieren." Ich habe nicht den Eindruck, dass es Pläne gibt, abstrahierende Dinge in anderen Modulen als externref erscheinen zu lassen. Mein Verständnis ist, dass externref kein Abstraktionswerkzeug ist.

Ich kenne auch keine derartigen Pläne; Ich weiß nur nicht, ob jemand die Option in Betracht gezogen hat. Das heißt, sollte externref ein "primitiver" Typ sein, zB wie i32 , oder ein "instanziierbarer" Typ, zB wie importierte Typen?

In meinem ursprünglichen Beitrag habe ich angedeutet, dass beide Wege machbar sind. Der Kompromiss bei der "primitiven" Interpretation besteht darin, dass externref wesentlich weniger nützlich/zusammensetzbar ist als importierte Typen, da letztere die Anwendungsfälle von externref sowie die obigen Muster unterstützen. Als solches scheint "primitives" externref wahrscheinlich zu einem Überbleibsel zu werden – es existiert nur aus Gründen der Abwärtskompatibilität. Aber das scheint nicht besonders problematisch zu sein, sondern nur ein Ärgernis. Das größte Problem, das ich sehen kann, ist, dass, genau wie das Wohlverhalten von call_indirect bei numerischen Typen funktioniert, weil sie keine Supertypen haben, das Wohlverhalten von call_indirect abhängig von externref enden kann

Ah hah, ja, das erklärt den Unterschied im Verständnis: Ich stimme @tlively zu, dass externref nicht abstrakt ist und es keine Vorstellung gibt, " externref mit einem Typ zu instanziieren", und ich Ich denke, wir können uns in der Zukunft ziemlich sicher fühlen. (Da externref ein primitiver Typ ist, im Gegensatz zu einem explizit deklarierten Typparameter, ist nicht klar, wie man ihn auf Modulbasis instanziieren könnte.)

In Abwesenheit von downcasts, macht diese Tatsache wasm nahezu nutzlos für die Implementierung / virtualisieren WASI APIs, weshalb der Plan für WASI , um den Übergang wurde von i32 Griffen direkt an Typ Import (und warum eingereicht I - Typ-Importe /#6 , b/c wir brauchen noch ein bisschen mehr).

Da externref ein primitiver Typ ist, im Gegensatz zu einem explizit deklarierten Typparameter, ist nicht klar, wie man ihn auf Modulbasis instanziieren könnte.

Wenn wir Typimporte hinzufügen, können wir Module ohne Typimporte mit externref so behandeln, als hätten wir import type externref oben. Alles würde genauso eine Typprüfung durchführen, da externref Gegensatz zu anderen primitiven Typen keine zugehörigen primitiven Operationen hat (außer einem Standardwert). Aber mit diesem impliziten Import können wir jetzt Dinge wie Virtualisierung, Sandboxing und Laufzeitüberwachung durchführen.

Aber bevor wir weiter hin und her gehen, denke ich, dass es hilfreich wäre, abzuschätzen, ob wir bei etwas alle auf dem gleichen Stand sind. Lassen Sie mich wissen, ob Sie der folgenden Aussage zustimmen oder nicht zustimmen und warum: "Sobald Typimporte verfügbar sind, haben Module keinen Grund, externref und sind besser wiederverwendbar/zusammensetzbar, wenn sie stattdessen einen Typimport verwenden."

Lassen Sie mich wissen, ob Sie der folgenden Aussage zustimmen oder nicht, und warum: "Sobald Typimporte verfügbar sind, haben Module keinen Grund, externref und sind besser wiederverwendbar/zusammensetzbar, wenn sie stattdessen einen Typimport verwenden."

Dieser Aussage stimme ich abstrakt zu. In der Praxis denke ich, dass externref in Webkontexten üblich bleibt, um auf externe JS-Objekte zu verweisen, da zum Zeitpunkt der Instanziierung keine zusätzliche Konfiguration erforderlich ist. Aber das ist nur eine Vorhersage, und es würde mir nichts ausmachen, wenn ich mich als falsch herausstellen würde und alle schließlich auf Typimporte umsteigen. Der Wert von externref besteht darin, dass wir es früher haben können, als wir reichere Mechanismen wie Typimporte haben können. Ich würde externref lieber einfach halten und sehen, dass es nicht mehr verwendet wird, als es später umständlich zu etwas Mächtigerem zu machen, wenn es elegantere Alternativen gibt.

@tlively ,

FWIW, ich habe externref nie als innerhalb eines WebAssembly-Moduls instanziierbar verstanden.

Richtig, die Idee ist, dass externref der "primitive" Typ von Fremdzeigern ist. Um die Implementierungsdetails eines Referenztyps zu abstrahieren, benötigen Sie etwas anderes: so etwas wie anyref oder einen Typimport.

@lukewagner , ich wäre an der Erweiterung des Umfangs des Vorschlags für

@RossTate :

Zu diesen Experten, die ich konsultiert habe, gehören Autoren einiger dieser Veröffentlichungen.

Exzellent. Dann nehme ich an, dass Sie bemerkt haben, dass Sie wirklich der Autor einiger dieser Artikel sind, falls Sie nach mehr Autorität suchen. :)

Hier ist, was ich gefragt habe:

Angenommen, ich habe eine polymorphe Funktion f(...). Meine typisierte Sprache hat (subsumptive) Subtyping und explizites Casting. Bei einer Typumwandlung von t1 nach t2 wird jedoch nur überprüft, ob t2 ein Untertyp von t1 ist. Angenommen, Typvariablen wie X haben standardmäßig keine Untertypen oder Supertypen (außer sich selbst natürlich). Würden Sie erwarten, dass f bezüglich X relational parametrisch ist?

Seufzen. Ich würde die gleiche Antwort auf diese spezielle Frage geben. Aber diese Frage beinhaltet mehrere spezifische Annahmen, zB über die Natur von Casts und über eine eher ungewöhnliche Unterscheidung zwischen begrenzter und unbegrenzter Quantifizierung, die in keiner Programmiersprache selten existiert. Und ich vermute, das hat einen Grund.

Als ich sagte, "statische Typabstraktion ist unzureichend", meinte ich nicht, dass es _technisch_ nicht möglich ist (natürlich ist es das), aber dass es _praktisch_ nicht angemessen ist. In der Praxis möchten Sie keine Verzweigung zwischen Typabstraktion und Untertypisierung/Umformbarkeit (oder zwischen parametrischen und nicht-parametrischen Typen), da dies die auf Umwandlungen basierende Komposition künstlich unterbrechen würde.

Ich verstehe deine Behauptungen nicht.

Wenn Sie einen Wert vom abstrakten Typ erhalten, möchten Sie vielleicht trotzdem seinen genauen Typ vergessen, z. Vielleicht möchten Sie dies aus dem gleichen Grund wie bei jedem anderen Referenztyp tun. Die Typabstraktion sollte bestimmten Verwendungsmustern, die mit regulären Typen derselben Art gültig sind, nicht in die Quere kommen.

Ihre Antwort scheint zu sein: Also, packen Sie alles in Hilfstypen an den jeweiligen Verwendungsstellen ein, zB in Varianten. Dies könnte jedoch einen erheblichen Aufwand für das Einwickeln/Auspacken bedeuten, es erfordert komplexere Typsystemmerkmale und ist komplizierter zu verwenden.

Ich denke, einige unserer Meinungsverschiedenheiten laufen darauf hinaus: ob das MVP Vereinigungen von Referenztypen unterstützen sollte oder ob es die Einführung und Codierung mit expliziten Variantentypen erfordern sollte. Im Guten wie im Schlechten sind Unions eine natürliche Ergänzung zur Heap-Schnittstelle typischer Engines, und sie sind heute einfach und kostengünstig zu unterstützen. Nicht so sehr Varianten, sondern ein viel forschungsintensiverer Ansatz, der wahrscheinlich zusätzlichen Overhead und eine weniger vorhersehbare Leistung verursachen würde, zumindest bei bestehenden Motoren. Und ich sage das als Typsystem-Person, das unter anderen Umständen Varianten gegenüber Vereinigungen bevorzugt, wie zum Beispiel bei benutzerorientierten Sprachen. ;)

Als Meta-Kommentar würde ich es wirklich begrüßen, wenn ich mich nicht an die Behörde oder an die CG wenden müsste, um meine Vorschläge zu hören.

Darf ich freundlicherweise vorschlagen, dass Gespräche über verschiedene Vorschläge besser funktionieren könnten, wenn sie von den jeweiligen Verfechtern über Dinge, die nicht klar sind, _befragt__ werden, z eine Antwort und auf der Grundlage dieser Annahmen breite Behauptungen und Vorschläge machen?

Exzellent. Dann nehme ich an, dass Sie bemerkt haben, dass Sie wirklich der Autor einiger dieser Artikel sind, falls Sie nach mehr Autorität suchen. :)

Ja, was es äußerst problematisch macht, wenn Sie behaupten, dass es Papiere gibt, in denen behauptet wird, dass mein Vorschlag nicht funktioniert, obwohl Sie wissen, dass mein Vorschlag speziell die Bedingungen behandelt, unter denen diese Behauptungen aufgestellt wurden.

In der Praxis möchten Sie keine Verzweigung zwischen Typabstraktion und Untertypisierung/Umformbarkeit (oder zwischen parametrischen und nicht-parametrischen Typen), da dies die auf Umwandlungen basierende Komposition künstlich unterbrechen würde.

Dies ist eine Meinung, keine Tatsache (was es für uns völlig vernünftig macht, anderer Meinung zu sein). Ich würde sagen, dass es keine sprachunabhängigen industrietypisierten Assemblersprachen für mehrsprachige Systeme gibt, und daher ist es unmöglich, Aussagen über die Praxis zu machen. Dies ist etwas, das eine gründliche (getrennte) Diskussion verdient. Für diese Diskussion wäre es hilfreich, wenn Sie zunächst einige detaillierte Fallstudien vorlegen, damit die CG die Kompromisse vergleichen kann.

Darf ich freundlicherweise vorschlagen, dass Gespräche über verschiedene Vorschläge besser funktionieren könnten, wenn man die jeweiligen Verfechter nach Dingen fragt, die nicht klar sind, z eine Antwort und auf der Grundlage dieser Annahmen breite Behauptungen und Vorschläge machen?

WebAssembly/Proposal-Type-Imports#4, WebAssembly/Proposal-Type-Imports#6 und WebAssembly/Proposal-Type-Imports#7 fragten im Wesentlichen nach weiteren Einzelheiten zu diesem Plan. Der letzte Punkt weist das Problem auf GC hin, aber WebAssembly/gc#86 weist darauf hin, dass der aktuelle GC-Vorschlag tatsächlich keine dynamischen Abstraktionsmechanismen unterstützt.

Auf der Metaebene wurden wir gebeten, diese Diskussion beiseite zu legen und uns auf das vorliegende Thema zu konzentrieren. Ich fand die Antwort von @tlively auf meine Frage sehr hilfreich. Ich bin eigentlich sehr daran interessiert, Ihre Gedanken zu dieser Frage zu erfahren.

@RossTate :

Ich fand die Antwort von @tlively auf meine Frage sehr hilfreich. Ich bin eigentlich sehr daran interessiert, Ihre Gedanken zu dieser Frage zu erfahren.

Hm, ich dachte ich hätte es oben schon kommentiert. Oder meinst du was anderes?

Nö. Ich dachte, dass dieser Kommentar möglicherweise eine Zustimmung zu seiner Antwort bedeutet, aber ich wollte es zuerst bestätigen. Vielen Dank!

@lukewagner , was

Ich stimme dem obigen zu, dass externref für immer ein primitiver Typ sein wird und nicht rückwirkend als Typparameter neu interpretiert wird. Ich denke, in Anbetracht dessen sind Referenztypen so wie sie sind gut zu gehen.

Ich würde gerne das Angebot von @rossberg annehmen, den Umfang des Type Imports-Vorschlags so zu erweitern, dass

Fantastisch. Dann sind wir alle auf der gleichen Seite (und ich denke auch, dass @tlively eine schöne Zusammenfassung der damit verbundenen Kompromisse und der

externref wird also nicht instanziierbar sein, und Module, die nach dieser zusätzlichen Flexibilität von Typimporten suchen, werden bei der Veröffentlichung der Funktion voraussichtlich in Typimporte umgewandelt. Mir fällt ein, dass wir, um diesen Übergang reibungslos zu gestalten, es wahrscheinlich so machen müssen, dass (einige?) Typimporte standardmäßig mit externref instanziiert werden, wenn keine Instanziierung bereitgestellt wird.

Und ich möchte auch das Angebot wahrnehmen, den Umfang von Type Imports zu erweitern. Viele der wichtigsten Anwendungen des Typimports benötigen Abstraktion, daher scheint es mir naheliegend, dass Abstraktion Teil dieses Vorschlags ist.

In der Zwischenzeit ist, obwohl wir die dringende Frage zu externref angesprochen haben, was allgemeiner mit call_indirect zu tun ist, immer noch ungelöst, wenn auch mit einigen nützlichen Diskussionen darüber, wie es gelöst werden könnte Werde das Thema noch offen lassen.

Vielen Dank!

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

chicoxyzzy picture chicoxyzzy  ·  5Kommentare

mfateev picture mfateev  ·  5Kommentare

thysultan picture thysultan  ·  4Kommentare

jfbastien picture jfbastien  ·  6Kommentare

frehberg picture frehberg  ·  6Kommentare