Skip to content

Commit

Permalink
Project translation
Browse files Browse the repository at this point in the history
  • Loading branch information
Ragnar-F authored and github-actions[bot] committed May 6, 2024
1 parent a82ad21 commit e346df3
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 17 deletions.
28 changes: 28 additions & 0 deletions target/docs/ChangeLog.htm
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,34 @@ <h1>Änderungen und neue Features</h1>
<p><a href="v2-changes.htm">Änderungen von v1.1 bis v2.0</a> behandelt die Unterschiede zwischen v1.1 und v2.0.</p>
<p>Alle technischen Einzelheiten zu den Änderungen finden Sie auf <a href="https://github.com/AutoHotkey/AutoHotkey/tree/alpha">GitHub</a>.</p>

<h2 id="v2.0.14">2.0.14 - 6. Mai 2024</h2>
<p>Behoben: Das Fehlerdialogfenster reagiert nun auch auf Tastaturkurzbefehle, wenn der Text fokussiert ist.</p>
<p>Behoben: Die Breitenwerte von MonthCal W-<em>n</em> (Anzahl der Monate) werden nicht mehr von der DPI-Skalierung beeinflusst.</p>
<p>Behoben: Click gibt keinen Integer mehr zurück.</p>
<p>Behoben: <code><i>Taste</i>::try {</code> wird nicht mehr als Fehler erkannt.</p>
<p>Behoben: <code>:B0*O:XY::Z</code> erzeugt nun XYZ statt XZ (also statt Y zu unterdrücken).</p>
<p>Behoben: Send lässt ein vorheriges <code>{<i>Modifikator</i> Down}</code> wirksam, auch wenn die Taste physisch gedrückt gehalten wird.</p>
<p>Verbessert: Das Skript nimmt nun zuverlässiger den Fokus, wenn ein Kontextmenü angezeigt wird.</p>

<strong>Debugger-Verbesserungen</strong>
<p>Behoben: stdout/stderr-Pakete, die während der Verarbeitung eines anderen Befehls gesendet werden, korrumpieren nicht mehr die bevorstehende Antwort.</p>
<p>Behoben: <code>property_get -n &lt;exception&gt;.message</code> und ähnliches.</p>
<p>Behoben: Es werden keine korrumpierten Ergebnisse von property_get mehr erzeugt, wenn eine Eigenschaft ein temporäres Objekt mit einer Zeichenkette zurückgibt, wie z.B. <code>x.y.z</code>, wobei <code>y =&gt; {z:"a"}</code>.</p>
<p>Behoben: Es kommt nicht mehr zu Abstürzen, wenn ein asynchroner Befehl während der Verarbeitung eines anderen Befehls empfangen wird.</p>
<p>Behoben: Ausnahmen wurden nicht gelöscht, nachdem sie via property_set unterdrückt wurden.</p>
<p>Behoben: <code>property_get -c 0 -d 0</code> erlaubt nun globale Variablen, wie sie bereits von <code>-d 1</code> erlaubt werden.</p>
<p>Behoben: property_get bezifferte enumerierte Elemente falsch.</p>

<p>Verbessert: property_get unterstützt nun auch Eigenschafts-Getter mit einem Parameter (bisher wurde dies nur von der impliziten __Item-Eigenschaft unterstützt).</p>
<p>Verbessert: property_get unterstützt nun auch Eigenschaften von primitiven Werten. Der Wert muss nach wie vor in einer Variable enthalten sein oder von einer Eigenschaft zurückgegeben werden.</p>
<p>Verbessert: property_get erlaubt nun den Aufruf von Funktionen mit &lt;=1 Parametern.</p>
<p>Verbessert: property_get unterstützt nun Float-Schlüssel/Parameter.</p>

<p>Geändert: Der Debugger unterdrückt nun Ausnahmen bei der Auswertung von Eigenschaften.</p>
<p>Geändert: Der Debugger ignoriert nun Fehler, die durch __Enum ausgelöst werden (als keine Elemente behandeln).</p>
<p>Geändert: Die Pseudo-Eigenschaft &lt;enum&gt; erfordert nun __Enum. Dadurch wird verhindert, dass das Objekt selbst als Enumerator aufgerufen wird.</p>
<p>Kleine Optimierungen der Codegröße im Debugger.</p>

<h2 id="v2.0.13">2.0.13 - 20. April 2024</h2>
<p>Geändert: Die Hotkey-Funktion löst nun einen ValueError aus, wenn ihr Optionen-Parameter eine ungültige Option enthält.</p>
<p>Behoben: InputHook respektiert nun die +S-Option für Backspace, wenn es als "rückgängig machen" fungiert.</p>
Expand Down
8 changes: 5 additions & 3 deletions target/docs/Functions.htm
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ <h3 id="static-functions">Statische Funktionen</h3>
<p>Eine statische Funktion kann nicht auf andere verschachtelte Funktionen außerhalb ihres eigenen Körpers verweisen, es sei denn, diese sind explizit als statisch deklariert. Beachten Sie, dass eine nicht-statische verschachtelte Funktion (selbst wenn sie im <a href="#AssumeStatic">Assume-Static</a> ist) ein Closure werden kann, wenn sie einen Funktionsparameter referenziert.</p>

<h3 id="closures">Closures</h3>
<p>Ein <em>Closure</em> ist eine verschachtelte Funktion, die an einen Satz <em>freier Variablen</em> gebunden ist. Freie Variablen sind lokale Variablen der äußeren Funktion, die auch von verschachtelten Funktionen verwendet werden. Closures ermöglichen einer oder mehreren verschachtelten Funktionen, ihre Variablen mit der äußeren Funktion zu teilen, selbst nach Rückkehr der äußeren Funktion.</p>
<p>Ein <em>Closure</em> ist eine verschachtelte Funktion, die an einen Satz <em id="free-vars">freier Variablen</em> gebunden ist. Freie Variablen sind lokale Variablen der äußeren Funktion, die auch von verschachtelten Funktionen verwendet werden. Closures ermöglichen einer oder mehreren verschachtelten Funktionen, ihre Variablen mit der äußeren Funktion zu teilen, selbst nach Rückkehr der äußeren Funktion.</p>
<p>Um ein Closure zu erstellen, definieren Sie einfach eine verschachtelte Funktion, die auf die Variablen der äußeren Funktion verweist. Zum Beispiel:</p>
<pre>
Begrüßer_erstellen(f)
Expand Down Expand Up @@ -394,20 +394,22 @@ <h3 id="closures">Closures</h3>
</pre>
<p>Eine verschachtelte Funktion ist automatisch ein Closure, wenn sie alle nicht-statischen lokalen Variablen der äußeren Funktion erfasst. Die Variable, die zum Closure selbst gehört (z.B. <code>aktivieren</code>), ist ebenfalls eine nicht-statische lokale Variable, d.h. jede verschachtelte Funktion, die auf ein Closure verweist, ist automatisch ein Closure.</p>
<p>Jeder Aufruf der äußeren Funktion erzeugt neue Closures, die sich von allen vorherigen Aufrufen unterscheiden.</p>
<p id="circular-closure">Es wird davon abgeraten, eine Referenz zu einem Closure in eine der freien Variablen des Closure zu speichern, da dies einen <a href="Objects.htm#Circular_References">Zirkelbezug</a> erzeugt, der unterbrochen werden muss (z.B. durch Leeren der Variable), bevor das Closure freigegeben werden kann. Eine Closure kann jedoch bedenkenlos auf sich selbst und auf andere Closures über deren Originalvariablen verweisen, ohne einen Zirkelbezug zu erzeugen. Zum Beispiel:</p>
<p id="circular-closure">Es wird davon abgeraten, eine Referenz zu einem Closure in eine der freien Variablen der äußeren Funktion zu speichern, da dies einen <a href="Objects.htm#refs-problems">Referenzzyklus</a> erzeugt, der unterbrochen werden muss (z.B. durch Leeren der Variable), bevor das Closure freigegeben werden kann. Ein Closure kann jedoch bedenkenlos auf sich selbst und auf andere Closures über deren Originalvariablen verweisen, ohne einen problematischen Referenzzyklus zu erzeugen. Zum Beispiel:</p>
<pre>
timertest() {
x := "tack!"
tick() {
MsgBox x <em>; x macht dies zu einem Closure.</em>
SetTimer tick, 0 <em>; Originalvariable des Closure kann bedenkenlos verwendet werden.</em>
; SetTimer t, 0 <em>; Das Erfassen von t würde einen Zirkelbezug erzeugen.</em>
; SetTimer t, 0 <em>; Das Erfassen von t würde einen Referenzzyklus erzeugen.</em>
}
t := tick <em>; Das ist okay, da t oben nicht erfasst wird.</em>
SetTimer t, 1000
}
timertest()
</pre>
<p>Jedes Mal, wenn die äußere Funktion aufgerufen wird, werden alle ihre <a href="#free-vars">freien Variablen</a> als Gruppe im Speicher reserviert. Diese eine Gruppe freier Variablen ist mit allen Closures der Funktion verlinkt. Wenn die Originalvariable des Closure (<code>tick</code> im obigen Beispiel) von einem anderen Closure innerhalb derselben Funktion erfasst wird, ist ihre Lebensdauer an die Gruppe gebunden. Die Gruppe wird nur dann gelöscht, wenn es keine Referenzen auf eine ihrer Closures mehr gibt, außer denen in den Originalvariablen. Dadurch können sich Closures gegenseitig referenzieren, ohne einen <a href="Objects.htm#refs-problems">problematischen Referenzzyklus</a> zu verursachen.</p>
<p>Closures, die nicht von anderen Closures erfasst werden, können vor der Gruppe gelöscht werden. Alle freien Variablen innerhalb der Gruppe, einschließlich der erfassten Closures, können nicht gelöscht werden, solange ein solches Closure existiert.</p>

<h2 id="remarks">Return, Exit und allgemeine Bemerkungen</h2>
<p>Wenn die Ausführung die geschweifte Endklammer der Funktion vor einem <a href="lib/Return.htm">Return</a> erreicht, endet die Funktion und gibt einen leeren Wert (eine leere Zeichenkette) zurück. Ein leerer Wert wird auch zurückgegeben, wenn die Funktion den Parameter von <a href="lib/Return.htm">Return</a> explizit weglässt.</p>
Expand Down
20 changes: 10 additions & 10 deletions target/docs/Objects.htm
Original file line number Diff line number Diff line change
Expand Up @@ -549,33 +549,33 @@ <h4 id="refs-problems">Probleme mit der Referenzzählung</h4>
<p>Ein Zyklus ist häufig weniger offensichtlich und kann mehrere Objekte umfassen. <a href="lib/Gui.htm#ExRefCycle">RefZyklusGuiZeigen</a> zeigt zum Beispiel einen Zyklus, der Gui, MenuBar, Menu und Closures beinhaltet. Die Verwendung eines separaten Objekts zur Behandlung von GUI-Ereignissen ist ebenfalls anfällig für Zyklen, wenn das Handler-Objekt eine Referenz auf die GUI hat.</p>
<p>Nichtzyklische Referenzen auf ein Objekt können ebenfalls Probleme verursachen. Zum Beispiel bewirken Objekte, die von internen Funktionen wie SetTimer oder OnMessage abhängig sind, in der Regel, dass das Programm eine indirekte Referenz auf das Objekt hält. Dies würde verhindern, dass das Objekt gelöscht wird, was bedeutet, dass es __New und __Delete nicht verwenden kann, um den Timer oder die Meldungsüberwachung zu verwalten.</p>
<p>Im Folgenden werden einige Strategien vorgestellt, die zur Lösung der oben beschriebenen Probleme beitragen können.</p>
<p id="ref-avoid-cycles"><strong>Zyklen vermeiden</strong>: Wenn Referenzzyklen ein Problem darstellen, sollten sie nicht erstellt werden. Zum Beispiel würde entweder <code>parent.child</code> oder <code>child.parent</code> nicht gesetzt werden. Dies ist oft nicht praktikabel, da verwandte Objekte in irgendeiner Weise aufeinander verweisen müssen.</p>
<p id="ref-avoid-cycles"><strong>Zyklen vermeiden:</strong> Wenn Referenzzyklen ein Problem darstellen, sollten sie nicht erstellt werden. Zum Beispiel würde entweder <code>parent.child</code> oder <code>child.parent</code> nicht gesetzt werden. Dies ist oft nicht praktikabel, da verwandte Objekte in irgendeiner Weise aufeinander verweisen müssen.</p>
<p>Vermeiden Sie bei der Definition von Ereignishandlern für <a href="lib/GuiOnEvent.htm">OnEvent (Gui)</a>, die Quell-Gui in einer Closure- oder Bound-Funktion zu erfassen, und verwenden Sie stattdessen den Gui- oder Gui.Control-Parameter. Dasselbe gilt für <a href="lib/Menu.htm#Add">Add (Menu)</a> und den Menü-Parameter des Callbacks, aber natürlich kann ein Menüpunkt, der auf eine Gui verweisen muss, diesen Ansatz nicht verwenden.</p>
<p>In einigen Fällen kann das andere Objekt durch eine indirekte Methode abgerufen werden, die nicht auf einer gezählten Referenz beruht. Zum Beispiel können Sie eine HWND-Nummer speichern und <code>GuiFromHwnd(hwnd)</code> verwenden, um ein <a href="lib/Gui.htm">Gui</a>-Objekt abzurufen. Es ist nicht notwendig, eine Referenz aufrechtzuerhalten, um das Löschen zu verhindern, während das Fenster sichtbar ist, da die Gui dies selbst regelt.</p>
<p id="ref-break-cycles"><strong>Zyklen unterbrechen</strong>: Wenn das Skript die Referenzzählung vermeiden kann und stattdessen die Lebensdauer des Objekts direkt verwaltet, muss es den Zyklus nur unterbrechen, wenn die Objekte gelöscht werden sollen:</p>
<p id="ref-break-cycles"><strong>Zyklen unterbrechen:</strong> Wenn das Skript die Referenzzählung vermeiden kann und stattdessen die Lebensdauer des Objekts direkt verwaltet, muss es den Zyklus nur unterbrechen, wenn die Objekte gelöscht werden sollen:</p>
<pre>child.parent := unset <em>; parent: 1, child: 2</em>
child := unset <em>; parent: 1, child: 1</em>
parent := unset <em>; beide gelöscht</em></pre>
<p id="ref-dispose"><strong>Dispose</strong> (Entsorgen): __Delete wird genau dann aufgerufen, wenn die letzte Referenz freigegeben wird, so dass man sich eine einfache Zuweisung wie <code>meineGui := ""</code> als einen Bereinigungsschritt vorstellen kann, der das Löschen des Objekts auslöst. Manchmal wird dies explizit gemacht, wenn das Objekt nicht mehr benötigt wird, aber dies ist weder zuverlässig noch zeigt es wirklich die Absicht des Codes. Ein alternatives Muster besteht darin, eine Dispose- oder Destroy-Methode zu definieren, die die Ressourcen des Objekts freigibt, und sie so zu konzipieren, dass sie nichts tut, wenn sie ein zweites Mal aufgerufen wird. Sie kann dann zur Sicherheit auch von __Delete aus aufgerufen werden.</p>
<p>Ein Objekt, das diesem Muster folgt, muss dennoch alle Referenzzyklen unterbrechen, wenn es <em>entsorgt</em> wird, da sonst ein Teil des Speichers nicht freigegeben würde und __Delete für andere Objekte, die vom Objekt referenziert werden, nicht aufgerufen würde.</p>
<p>Zyklen, die durch die Ereignishandler eines Gui-Objekts, durch MenuBar oder durch ein Event-Sink-Objekt verursacht werden, werden automatisch "unterbrochen", wenn <a href="lib/Gui.htm#Destroy">Destroy</a> aufgerufen wird, da es diese Objekte freigibt. (Dies wird im <a href="lib/Gui.htm#ExRefCycle">RefZyklusGuiZeigen-Beispiel</a> gezeigt.) Allerdings würde dies keine Zyklen unterbrechen, die durch neu hinzugefügte Eigenschaften verursacht werden, da Destroy diese nicht löscht.</p>
<p>Ähnlich wie das Dispose-Muster hat <a href="lib/InputHook.htm">InputHook</a> eine Stop-Methode, die explizit aufgerufen werden muss und deshalb nicht auf __Delete angewiesen ist, um zu signalisieren, wann die Operation beendet werden soll. Während der Operation hält das Programm effektiv eine Referenz auf das Objekt, wodurch dessen Löschung verhindert wird, aber dies ist eher eine Stärke als eine Schwäche: Ereignisrückrufe können weiterhin aufgerufen werden und erhalten den InputHook als Parameter. Wenn die Operation beendet ist, wird die interne Referenz freigegeben und der InputHook gelöscht, wenn das Skript keine Referenz darauf hat.</p>
<p id="ref-ptr"><strong>Pointer</strong>: Das Speichern von beliebig vielen Pointerwerten hat keinen Einfluss auf die Referenzanzahl des Objekts, da ein Pointer nur ein Integer ist. Ein mit <a href="#ObjPtr">ObjPtr</a> abgerufener Pointer kann verwendet werden, um eine Referenz zu erzeugen, indem er an <a href="#ObjFromPtr">ObjFromPtrAddRef</a> übergeben wird. Die AddRef-Version der Funktion muss verwendet werden, da die Referenzanzahl dekrementiert wird, wenn die temporäre Referenz automatisch freigegeben wird.</p>
<p id="ref-ptr"><strong>Pointer:</strong> Das Speichern von beliebig vielen Pointerwerten hat keinen Einfluss auf die Referenzanzahl des Objekts, da ein Pointer nur ein Integer ist. Ein mit <a href="#ObjPtr">ObjPtr</a> abgerufener Pointer kann verwendet werden, um eine Referenz zu erzeugen, indem er an <a href="#ObjFromPtr">ObjFromPtrAddRef</a> übergeben wird. Die AddRef-Version der Funktion muss verwendet werden, da die Referenzanzahl dekrementiert wird, wenn die temporäre Referenz automatisch freigegeben wird.</p>
<p>Nehmen wir zum Beispiel an, dass ein Objekt einige Eigenschaften jede Sekunde aktualisieren muss. Ein Timer hält eine Referenz auf die Rückruffunktion, die das Objekt als gebundenen Parameter hat. Normalerweise würde dies verhindern, dass das Objekt gelöscht wird, bevor der Timer gelöscht wird. Das Speichern eines Pointers anstelle einer Referenz ermöglicht das Löschen des Objekts unabhängig vom Timer, so dass es automatisch von __New und __Delete verwaltet werden kann.</p>
<pre>a := EineKlasse()
Sleep 5500 <em>; Den Timer 5 Mal laufen lassen.</em>
a := ""
Sleep 3500 <em>; Exit temporär verhindern, um den Stop des Timers zu zeigen.</em>

class EineKlasse {
__New() {
__New() {
<em>; Das Closure muss gespeichert werden, damit der Timer später
; gelöscht werden kann. Jedes Mal, wenn die Methode aufgerufen
; werden muss, wird eine gezählte Referenz synthetisiert.</em>
this.Timer := (p =&gt; ObjFromPtrAddRef(p).Update()).Bind(ObjPtr(this))
SetTimer this.Timer, 1000
}
__Delete() {
__Delete() {
SetTimer this.Timer, 0
<em>; Wenn dieses Objekt wirklich gelöscht wird, werden alle Eigen-
; schaften gelöscht und die folgende __Delete-Methode aufgerufen.
Expand All @@ -585,23 +585,23 @@ <h4 id="refs-problems">Probleme mit der Referenzzählung</h4>
<em>; Dies soll nur zeigen, dass der Timer läuft.
; Theoretisch könnte diese Klasse auch einen anderen Zweck haben.</em>
count := 0
Update() =&gt; ToolTip(++this.count)
Update() =&gt; ToolTip(++this.count)
}</pre>
<p>Ein Nachteil dieses Ansatzes ist, dass der Pointer nicht direkt als Objekt verwendbar ist und weder von <a href="lib/Type.htm">Type</a> noch vom <a href="AHKL_DBGPClients.htm">Debugger</a> als solches erkannt wird. Das Skript muss absolut sicher sein, dass der Pointer nach dem Löschen des Objekts nicht mehr verwendet wird, da dies ungültig ist und das Ergebnis undefiniert wäre.</p>
<p>Wenn die Pointerreferenz an mehreren Stellen benötigt wird, kann es sinnvoll sein, sie zu kapseln. Zum Beispiel würde <code>b := ObjFromPtrAddRef.Bind(ObjPtr(this))</code> eine <a href="misc/Functor.htm#BoundFunc">BoundFunc</a> erzeugen, die aufgerufen werden kann (<code>b()</code>), um die Referenz abzurufen, während <code>((this, p) =&gt; ObjFromPtrAddRef(p)).Bind(ObjPtr(this))</code> als Eigenschafts-Getter verwendet werden kann (die Eigenschaft würde eine Referenz zurückgeben).</p>
<p id="ref-uncounted"><strong>Ungezählte Referenzen</strong>: Wenn sich die Referenzanzahl des Objekts auf eine Referenz bezieht, sprechen wir von einer <em>gezählten Referenz</em>, andernfalls von einer <em>ungezählten Referenz</em>. Letzteres soll es dem Skript ermöglichen, eine Referenz zu speichern, die das Löschen des Objekts nicht verhindert.</p>
<p id="ref-uncounted"><strong>Ungezählte Referenzen:</strong> Wenn sich die Referenzanzahl des Objekts auf eine Referenz bezieht, sprechen wir von einer <em>gezählten Referenz</em>, andernfalls von einer <em>ungezählten Referenz</em>. Letzteres soll es dem Skript ermöglichen, eine Referenz zu speichern, die das Löschen des Objekts nicht verhindert.</p>
<p class="note"><strong>Hinweis:</strong> Hier geht es darum, wie sich die Referenzanzahl des Objekts gemäß Skriptlogik zu einer bestimmten Referenz verhält, nicht um die Art der Referenz selbst. Das Programm wird weiterhin versuchen, die Referenz automatisch zu einem bestimmten Zeitpunkt freizugeben, daher sind die Begriffe <em>schwache Referenz</em> und <em>starke Referenz</em> unpassend.</p>
<p>Eine gezählte Referenz kann in eine ungezählte Referenz umgewandelt werden, indem die Referenzanzahl des Objekts einfach dekrementiert wird. Dies <strong>muss</strong> rückgängig gemacht werden, bevor die Referenz freigegeben wird, was wiederum geschehen <strong>muss</strong>, bevor das Objekt gelöscht wird. Da der Zweck einer ungezählten Referenz darin besteht, die Löschung des Objekts zu ermöglichen, ohne zuerst die Referenz manuell ungesetzt zu machen, muss die Anzahl in der Regel innerhalb der eigenen <a href="#Custom_NewDelete">__Delete</a>-Methode des Objekts korrigiert werden.</p>
<p>Eine gezählte Referenz kann in eine ungezählte Referenz umgewandelt werden, indem die Referenzanzahl des Objekts einfach dekrementiert wird. Dies <u>muss</u> rückgängig gemacht werden, bevor die Referenz freigegeben wird, was wiederum geschehen <u>muss</u>, bevor das Objekt gelöscht wird. Da der Zweck einer ungezählten Referenz darin besteht, die Löschung des Objekts zu ermöglichen, ohne zuerst die Referenz manuell ungesetzt zu machen, muss die Anzahl in der Regel innerhalb der eigenen <a href="#Custom_NewDelete">__Delete</a>-Methode des Objekts korrigiert werden.</p>
<p>Zum Beispiel können __New und __Delete aus dem vorherigen Beispiel durch die folgenden ersetzt werden.</p>
<pre> __New() {
<pre> __New() {
<em>; Die BoundFunc muss gespeichert werden, damit der Timer später
; gelöscht werden kann.</em>
SetTimer this.Timer := this.Update.Bind(this), 1000
<em>; Referenzanzahl dekrementieren, um das von Bind erfolgte AddRef
; zu kompensieren.</em>
ObjRelease(ObjPtr(this))
}
__Delete() {
__Delete() {
<em>; Referenzanzahl inkrementieren, damit die Referenz innerhalb der
; BoundFunc sicher freigegeben werden kann.</em>
ObjPtrAddRef(this)
Expand Down
Loading

0 comments on commit e346df3

Please sign in to comment.