Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vorschlag: Defer #102

Open
bafto opened this issue Nov 23, 2024 · 0 comments
Open

Vorschlag: Defer #102

bafto opened this issue Nov 23, 2024 · 0 comments
Labels
Typ: Neues Feature Neues Feature

Comments

@bafto
Copy link
Member

bafto commented Nov 23, 2024

Motivation

Die Notwendigkeit "Cleanup"-Code am Ende einer Funktion (oder eines scopes) auszuführen ist ein häufiges Problem.
Ein Beispiel.

Die Funktion foo gibt einen Text zurück, macht:
    Die Datei d ist noch nicht offen.
    Öffne d mit dem Pfad "foo.txt" zum Lesen.
    
    [Arbeite mit der datei d]
    Wenn Bedingung, dann:
        Melde den Fehler "Fehler 1".
        Schließe d.
        Gib "" zurück.
        
    [Mehr arbeit]
    Wenn Bedingung, dann:
        Melde den Fehler "Fehler 2".
        Schließe d.
        Gib "" zurück.
        
    [Noch mehr arbeit]
    Schließe d.
    Gib "ergebnis" zurück.
Und kann so benutzt werden:
    "foo"

In solchem Code kann man sehr einfach vergessen Schließe d aufzurufen (oder jeglichen anderen Cleanup Code).
Es wäre praktisch, solchen Code automatisch vor jedem "return" ausführen zu können.

Beispiele aus anderen Sprachen

Manche Sprachen haben für solche Fälle das defer keyword.
Beispiel in Zig (scope defer):

fn foo() void {
    const memory = try allocator.alloc(u8, 100);
    defer allocator.free(memory);
    {
        const more_memory = try allocator.alloc(u8, 200);
        defer {
            std.debug.print("de-allocating in scope");
            allocator.free(more_memory);
        }
    }
}

Beispiel in Go (func defer):

func foo() {
    f, _ := os.Open("foo.txt")
    defer f.Close()
    
    {
        defer fmt.Println("I am printed second");
    }
    fmt.Println("I am printed first");
}

Wie man sieht werden defers in Zig am Ende des scopes und in Go am Ende der Funktion ausgeführt.

Feature Vorschlag für DDP

Function und Scope defer erscheinen mir beide Sinnvoll, je nach Use-Case. Da DDP sich sowieso nicht scheut neue Syntax einzubauen schlage ich vor beide Varianten (und eine dritte) einzubinden:

Die Funktion foo gibt einen Text zurück, macht:
    Die Datei d ist noch nicht offen.
    Öffne d mit dem Pfad "foo.txt" zum Lesen.
    Am Ende der Funktion:
        Schließe d.
    
    Für jede Zahl i von 1 bis 3, mache:
        Am Ende des Namensbereichs:
            Schreibe i auf eine Zeile.
        Schreibe "Gleich kommt i!" auf eine Zeile.
    
    [Arbeite mit der datei d]
    Wenn Bedingung, dann:
        Melde den Fehler "Fehler 1".
        Gib "" zurück.
        
    [Mehr arbeit]
    Wenn Bedingung, dann:
        Melde den Fehler "Fehler 2".
        Gib "" zurück.
        
    [Noch mehr arbeit]
    Gib "ergebnis" zurück.
Und kann so benutzt werden:
    "foo"
    
Am Ende des Programms:
    Schreibe "Alles erledigt!".
foo.

Diese "defers" kann man natürlich auch so abkürzen (für einzelne Statements):

Schreibe "Rückgabe" am Ende der Funktion.
Schreibe "Namensbereich zuende" am Ende des Namensbereichs.
Schreibe "Programm zuende" am Ende des Programms.

Das Schlüsselwort Namensbereich war nur die erste Idee, mir ist gerade nichts besseres eingefallen. Gerne Vorschläge einbringen!

Ob wir wirklich alle 3 Varianten brauchen ist auch nicht wichtig. Z.b. "Am Ende des Programms" wird vermutlich nur sehr selten benutzt werden, da es dasselbe wie ein globales "Am Ende des Namensbereiches ist" ist, bloß dass es auch innerhalb einer Funktion aufgerufen werden kann. Ich dachte es wäre aber netter Syntax-Zucker für manche Edge-Cases.

@bafto bafto added the Typ: Neues Feature Neues Feature label Nov 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Typ: Neues Feature Neues Feature
Projects
None yet
Development

No branches or pull requests

1 participant