Rust: var-Schlüsselwort nur für veränderliche Locals

Erstellt am 20. Juni 2012  ·  35Kommentare  ·  Quelle: rust-lang/rust

Ausgabe 1273 schlug let mut für veränderliche lokale Felder und mut für veränderliche Felder vor. let mut ist ausführlicher als ein einzelnes Schlüsselwort und unterbricht auch die Spaltenausrichtung. Die Leute mochten die Idee von var für veränderliche Felddeklarationen zu Recht nicht. Aber ich denke, niemand hat die Idee vorgeschlagen, var für veränderliche lokale Deklarationen und mut für veränderliche Felddeklarationen zu verwenden:

let x = 7; // declaration of immutable variable x
var y = 7; // declaration of mutable variable y
type point = { mut x: int, mut y: int }; // declaration of mutable record type

Dave

I-nominated

Alle 35 Kommentare

Ich muss gestehen, ich dachte zuerst, dass wir das gleiche Schlüsselwort für veränderliche Variablen und veränderliche Felder verwenden sollten, aber var liest sich ziemlich gut (obwohl ich let mut nicht mag)

Ich denke, es ist ein Merkmal, dass das Deklarieren einer veränderlichen Variablen etwas umständlicher ist als eine unveränderliche. Ich kann sehen, dass Programmierer nur "var" verwenden, um "konsistent" zu sein oder weil "var" mächtiger wäre (müssen Sie es nicht ändern, wenn Sie sich später für eine Mutation entscheiden). Dann haben Sie am Ende insgesamt weniger lesbaren Code.

Nicht zu suggerieren, dass Rust eine ernsthafte Sprache für Bondage und Disziplin sein sollte, aber ein sanfter Schubs in die richtige Richtung ist meiner Meinung nach moralisch vertretbar (dh die Regel wäre "für sicheren Code sollten die sichereren Konstrukte weniger laut sein als die mächtigeren, aber" leichter zu vermasselnde Konstrukte").

Einerseits gefällt mir das, da es die visuelle Mehrdeutigkeit aus dieser Form entfernen würde:

let mut x = 4,
    y = 8;  // is y mutable or not?

Aber ich neige dazu, auf Sylvans Seite zu stehen. Das Deklarieren von Mutables muss nicht unbedingt _hässlich_ sein, aber ich denke, es macht Sinn, wenn sie etwas weniger bequem zu erstellen sind als unveränderliche, wenn auch nur mit einem einzigen Tastendruck. Das aktivierende Schlüsselwort muss auch unverwechselbar sein, und (IMO) var wird zu häufig als generisches Schlüsselwort für die Deklaration von Variablen verwendet, um spezifisch Veränderlichkeit in einer Sprache zu vermitteln, die sich standardmäßig auf Unveränderlichkeit rühmt. Und denken Sie an die armen C#-Programmierer, für die var unser let !

Ich mag immer noch die Idee, let mut durch ein einzelnes Schlüsselwort zu ersetzen, um das obige Code-Snippet zu behandeln, aber gibt es einen Grund, ein neues Schlüsselwort einzuführen, wenn mut selbst ausreichen würde, wie pro der ursprüngliche Vorschlag in #1273?

@pcwalton wies auf ein Problem bei der mut : Es gibt eine Mehrdeutigkeit bei Datensatzliteralen und Blockausdrücken, deren Auflösung einen willkürlichen Lookahead erfordert.

{ mut x: int ...

Literal aufzeichnen oder mit lokaler Variable blockieren?

Ich konnte viele Programmierer sehen, die gerade gelernt haben, dass var Variablen in Rust deklariert und let überhaupt nicht verwendet. Schließlich deklarieren Sie mit var lokale Variablen in Sprachen wie JavaScript. Ich bin geneigt zu denken, dass dies eine gute Sache an diesem Vorschlag ist.

Ich habe gestern gehört, dass jemand darauf hingewiesen hat, dass jetzt let und var die gleiche Länge hätten, was für die Ausrichtung gut wäre.

Ich bin etwas gleichgültig, aber ich bevorzuge var , weil es kürzer ist. Veränderlichkeit ärgerlich zu machen ist kein wünschenswertes Ziel, wie ich es sehe. (Tatsächlich denke ich, dass die Rolle einer Programmiersprache nicht darin bestehen sollte, etwas nervig zu machen – nur _klar_, was nicht dasselbe ist.)

Obwohl ich immer noch vorsichtig bin, let und var zusammen zu verwenden (genau wie Javascript, aber 100% anders), wäre es viel weniger problematisch, wenn es einen Lint-Pass gäbe, um Variablen zu erkennen die als veränderlich deklariert, aber nie wirklich mutiert sind.

Es ist geplant, die Veränderlichkeit zu einem Teil des Typs zu machen. Beeinflusst das die Einheimischen und macht dies irrelevant?

Wie wäre es mit:

val x = ... // immutable (val-ue)
var y = ... // mutable (var-iable)

Wie in Scala.

Ich denke, @brson hat Recht und dieses Problem verschwindet, sobald wir mut in einen Typ verschieben, dh Sie erhalten let x = mut 10;

Dieses Thema vorerst schließen; öffne wieder, wenn du denkst, dass ich falsch liege!

Ich bin mir da nicht sicher. Ich mag die Idee, Mut in den Typus zu integrieren, aber ich weiß nicht, ob das ein "fertiger Deal" ist - es kann eine bleibende Seltsamkeit darin geben. Jedenfalls habe ich nie daran gedacht, dass man let x = mut 5 schreiben könnte, ich bin immer davon ausgegangen, dass man genauso wie heute let mut x = 5 schreiben würde; die "Veränderlichkeit" des Variablentyps würde sich aus der Art und Weise ergeben, wie sie deklariert wurde, nicht aus dem ihr zugewiesenen Wert.

Anderenfalls würde das bedeuten, dass y veränderbar ist, wenn Sie ein Array x vom Typ [mut int] und let y = x[0] schreiben? Oder so? Das scheint unerwünscht.

@Dretch Ich liebe val / var nicht, weil sie nicht unterschiedlich genug sind, obwohl der Scala-Präzedenzfall schön ist.

Ich teile die Besorgnis von @eholk , dass Leute lernen, standardmäßig var . So wie es jetzt funktioniert, neige ich dazu, alles als unveränderlich zu deklarieren, dann erinnert mich der Compiler daran, dass es veränderbar sein sollte, und tippe dann mut . Dies ist wohl ein gutes Verhalten, zu dem Sie bei einer Aufteilung von var/let weniger geneigt wären – die Eingabe von var und let ist genauso schwierig, aber Sie können nicht einmal let mut eingeben let .

Aber ich habe keine Vorliebe und schätze es, wenn ich Funktionen vollständig aus Anweisungen zusammensetzen kann, die mit dreistelligen Schlüsselwörtern beginnen.

@nikomatsakis Insbesondere macht es für mich Sinn, dass die Regeln zur

Ich bin geneigt, @pcwalton zuzustimmen, dass wir Programmierer nicht für die Verwendung einer veränderlichen Bindung bestrafen sollten, wenn sie dies wollen. Was die Besorgnis angeht, dass Leute unnötigerweise var , könnten wir eine optionale Warnung hinzufügen, die sich beschwert, wenn eine var Bindung einzeln zugewiesen wird. Aber ich denke auch, dass wir in Rustc und der Standardbibliothek Präzedenzfälle für guten Stil setzen können.

Dave

Ist es wirklich so schlimm, wenn Programmierer alle ihre Variablen für veränderlich erklären? Es scheint nicht das Ende der Welt zu sein, wenn wir eine Gruppe von Rust-Programmierern haben, die nur denken, dass var ist, wie Sie Variablen deklarieren, und eine andere Gruppe, die versteht, die meiste Zeit let und var bei Bedarf. Als erste Rust-Programmierer können wir den Präzedenzfall dafür schaffen, let und var korrekt zu verwenden.

IMHO geht es bei gutem Syntax-Design nicht nur darum, "alles" bequem zu machen, was Sie jemals tun möchten, sondern darum, die Leute sanft auf den "glatten Weg" der Semantik und der Designziele der Sprache zu bringen.

Zum Beispiel würden Sie wahrscheinlich keine spezielle syntaktische Unterstützung für verknüpfte Listen in Rust (a la Haskell) hinzufügen, da eines der grundlegenden Prinzipien von Rust darin besteht, effizient zu sein, und die allgegenwärtige Verwendung von verknüpften Listen wird diesem Prinzip widersprechen. Aus dem gleichen Grund sollte die gemeinsame Nutzung veränderlicher Daten zwischen Threads wahrscheinlich nicht allzu bequem sein (da sichere Parallelität ein weiteres Prinzip ist), noch sollte es sehr bequem sein, ein beliebiges int in einen Zeiger umzuwandeln (da die Speichersicherheit ein großes Prinzip ist).

Um nicht zu sagen, dass es unmöglich sein sollte, all diese Dinge zu tun, wohlgemerkt, nur verhältnismäßig umständlich, damit aus der Syntax klar wird, wie Rust idiomatisch geschrieben wird.

Veränderliche (lokale) Variablen sind nicht annähernd so schlimm wie diese, aber wenn Rust aus Korrektheits- und Wartungsgründen tatsächlich unveränderliche Daten bevorzugt (etwas, dem ich persönlich zustimme), sollte die Syntax idealerweise einen leichten Schubs in diese Richtung geben. Sogar ein einziges zusätzliches Zeichen oder ein zusätzliches Modifikatorsiegel oder was auch immer würde ausreichen, um zu verdeutlichen, dass "let" weniger kompliziert ist als "let mut" oder "let!" oder was auch immer, und muss daher die bevorzugte Standardeinstellung sein, die Sie versuchen sollten, wenn Sie die Variable nicht wirklich brauchen, um änderbar zu sein.

@ssylvan Oh, ich verstehe diesen Punkt, es ist nur eine Frage des Grades und der Abwägung der Kompromisse. Wir fördern bereits die Unveränderlichkeit von Datenstrukturen, und die Förderung von unveränderlichen Lokalen der IMO ist weniger wichtig als unveränderliche Felder. (Zumal IINM, dass wir veränderlichen Einheimischen nicht erlauben, bei Heap-Closings zu entkommen.) Und der Verlust der Möglichkeit, zwischen let und var umzugestalten, ohne die Spaltenanzahl zu ändern, überwiegt den Vorteil von Förderung unveränderlicher Einheimischer. Schwer zu quantifizieren, also denke ich, es ist nur mein Gefühl.

Dave

Nun, in diesem Fall würde zumindest "let foo = mut bar" oder "let foo := bar" im Gegensatz zu "let mut foo = bar" die erste Token-Reihenfolge bilden. Vermutlich hat der Variablenname eine variable Länge, daher ist es nicht so wichtig, zusätzliche Modifikatoren für den Rest der Anweisung zu vermeiden.

Oh, hey, ich bin ein bisschen zu der Idee von := .

Dave

Beim zweiten Nachdenken ist Pascal dauerhaft uncool. Ich nehme es zurück. :)

Dave

Außerdem verhindert let foo := bar etwas:

let mut foo;
foo = bar;

Ich habe dieses Muster manchmal als nützlich empfunden, obwohl es anscheinend immer eine andere Möglichkeit gibt, dasselbe Muster zu schreiben.

@eholk Ich glaube nicht, dass es das verhindert. Aber ich denke immer noch, dass es für Programmierer aus fast jeder Mainstream-Sprache zu seltsam aussehen wird.

Dave

In Bezug auf := verwendet Go es, um eine typinferentielle Zuweisung anzuzeigen (obwohl es noch nicht ganz eine Mainstream-Sprache ist). Aber ich kann auf den ersten Blick Schwierigkeiten bei der Unterscheidung zwischen den beiden Formen erkennen:

let foo = "hello";
let foo := "hell";

brsons Argument für die aktuelle Syntax (dh dass die veränderliche Deklaration zuerst die unveränderliche Deklaration erfordert) ist überzeugend. Es ist total toll, wenn Programmiersprachen rechthaberisch sind, solange sie keine Idioten sind. :)

Kein Interesse an = vs. := . Meist im Gegensatz zu val , var und Variationen davon; es ist einfach nicht _offensichtlich_, dass es die Veränderlichkeit kontrolliert. Ich meine, ich werde nicht angewidert aufhören, wenn wir eine davon adoptieren, aber ich denke, dass "die Gedächtnisstütze erklären zu müssen" ein schlechtes Zeichen ist. Ich bin mehr-ok mit:

  • Lassen Sie den Typ es diktieren.
  • Lassen Sie mut allein als lokaler Deklarator arbeiten und verlangen Sie, dass der Parser die Übergabe an die Record-Syntax gegenüber der lokalen Deklaration um ein zusätzliches Token verzögert; es ist immer noch LL(1), fügt nur einen zusätzlichen Zwischen-Grammatik-Zustand hinzu, kein zusätzliches Zurückverfolgen (beide Wege vorwärts sind gültig).
  • Lassen Sie es als let mut .

Der Hauptgrund, "zufällige" veränderliche Locals zu vermeiden, besteht darin, dass wir die Umgebungserfassung eingeführt haben, sodass sie zu einer Form von Fernaktionen werden, sowie zu Gefahren für eine Vielzahl von Analysen wie Kreditaufnahmen.

(Alle lets waren anfangs veränderbar, aber wir hatten auch keine Umgebungserfassung, nur Bindung. Jetzt haben wir keine Bindung, nur env-Erfassung. Tomayto, tomahto.)

Ich glaube, dass veränderliche Werte jetzt nicht implizit erfasst werden können.

@graydon hat

  • implizite "durch-Kopie"-Erfassung von veränderlichen Variablen in einem fn@
  • Verstehen, welche Daten veränderlich sind und was nicht für die Ausleihe

Es stellt sich heraus, dass letzteres nicht mehr relevant ist. Die Verwendung von veränderlichen/unveränderlichen Variablen war in der Praxis zu grob, daher hatborgck die Idee, eine Variable "vorübergehend" auszuleihen - eine veränderliche Variable kann mit einem unveränderlichen ptr ausgeliehen werden, solange die Variable nicht geändert wird, während der Zeiger in ist Umfang.

Wir könnten vielleicht einfach die Idee von veränderlichen/unveränderlichen Einheimischen entfernen und zur alten Regel zurückkehren – alles ist veränderbar. Wir könnten dann Warnungen ausgeben, wenn eine Variable, die implizit in eine Closure kopiert wird, geändert wird, nachdem die Closure erstellt wurde.

Es gibt noch eine dritte Motivation: Unveränderliche Variablen sind leichter nachvollziehbar. Wenn alles veränderbar ist, müssen Sie die gesamte Funktion durchsuchen, um zu sehen, welche Werte eine Variable während ihrer Lebensdauer haben könnte. Jede Variable hat potenziell einen komplizierten Datenfluss (insbesondere mit Schleifen, Verzweigungen, veränderlichen Funktionsparametern usw.) und es ist schwer zu sehen, was vor sich geht, ohne jede Anweisung sorgfältig zu analysieren. Wenn Sie nur ein oder zwei Mutables in einer Funktion haben, handelt es sich um eine Art "Kennzeichen", damit Sie beim Lesen von Code mit Hem vorsichtiger sind.

@Dretch Ich mag auch den Scala-Stil mit den Schlüsselwörtern "val" und "var".

Ich mag es, wie die aktuelle Syntax dazu führt, dass veränderliche Elemente wie ein wunder Daumen herausragen; es erleichtert das Scannen des Codes. val und var scheinen sich in dieser Hinsicht optisch zu ähnlich zu sein. Was nicht heißen soll, dass Mutables unbedingt auffallen müssen, aber die visuelle Unterscheidung von Schlüsselwörtern ist ein wichtiger Aspekt der Benutzerfreundlichkeit.

Ich verstehe, dass veränderliche Felder vom Rost entfernt werden. Bedeutet das, dass mut anstelle von let mut da die Mehrdeutigkeit von Datensatz/Variable im Block verschwinden würde?

Ich glaube auch, dass strukturelle Datensätze gehen, was die Mehrdeutigkeit beseitigt, selbst wenn veränderliche Felder verbleiben.

@Dretch es ist wahr, dass veränderliche Felder auf dem Weg sind und strukturelle Datensätze bereits verschwunden sind.

Das Problem ist mir größtenteils gleichgültig, obwohl ich darauf hinweisen möchte, dass es _möglich_ sinnvoll ist, dass mut ein eigenständiges Deklarationsschlüsselwort ist (wie Dretch vorschlägt), im Falle des Einfrierens/Auftauens . Vergleichen Sie heute:

let foo = 1;  // immutable
/* 10,000 lines of code here */
let mut foo = foo;  // we're making foo mutable, totally understandable
/* 10,000 lines of code here */
let foo = foo;  // potential wtf

Mit dem Vorschlag:

let foo = 1;  // immutable
/* 10,000 lines of code here */
mut foo = foo;  // a mutable foo, no problems here
/* 10,000 lines of code here */
let foo = foo;  // slightly less of a potential for wtf, since we officially have two declaration forms

Obwohl ich auch das Gefühl habe, dass dies den Rustismus "Abwesenheit von Mut impliziert Unveränderlichkeit" weniger konsistent machen würde, weil wir immer noch let foo = 1; anstatt nur foo = 1; schreiben würden (die letztere Form ist offensichtlich für Deklaration unerwünscht).

Kotlin verwendet auch val und var .

Ich glaube nicht, dass wir diese Änderung vornehmen werden, aber ich werde für Meilenstein 1 nominieren, der klar definiert ist, damit wir ihn vereinbaren können.

Konsens besteht darin, dies nicht zu tun, da dies nicht mit dem Verschieben von Mut zu Pattern-Bindungen kompatibel ist. Schließen.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen