Ruby-Setter - ob von (c)attr_accessor
oder manuell erstellt - scheinen die einzigen Methoden zu sein, die self.
beim Zugriff innerhalb der Klasse selbst qualifiziert werden müssen. Dies scheint Ruby allein in die Welt der Sprachen zu bringen:
- Alle Methoden benötigen
self
/this
(wie Perl und ich denke Javascript) - Keine Methoden erfordern
self
/this
ist (C #, Java) - Nur Setter brauchen
self
/this
(Ruby?)
Der beste Vergleich ist C # mit Ruby, da beide Sprachen Zugriffsmethoden unterstützen, die syntaktisch genau wie Klasseninstanzvariablen funktionieren: foo.x = y
, y = foo.x
. C # nennt sie Eigenschaften.
Hier ist ein einfaches Beispiel; das gleiche Programm in Ruby dann C #:
class A
def qwerty; @q; end # manual getter
def qwerty=(value); @q = value; end # manual setter, but attr_accessor is same
def asdf; self.qwerty = 4; end # "self." is necessary in ruby?
def xxx; asdf; end # we can invoke nonsetters w/o "self."
def dump; puts "qwerty = #{qwerty}"; end
end
a = A.new
a.xxx
a.dump
Nehmen Sie das weg self.qwerty =()
und es schlägt fehl (Ruby 1.8.6 unter Linux & OS X). Jetzt C #:
using System;
public class A {
public A() {}
int q;
public int qwerty {
get { return q; }
set { q = value; }
}
public void asdf() { qwerty = 4; } // C# setters work w/o "this."
public void xxx() { asdf(); } // are just like other methods
public void dump() { Console.WriteLine("qwerty = {0}", qwerty); }
}
public class Test {
public static void Main() {
A a = new A();
a.xxx();
a.dump();
}
}
Frage: Ist das wahr? Gibt es neben Setzern noch andere Gelegenheiten, bei denen Selbst notwendig ist? Gibt es andere Fälle, in denen eine Ruby-Methode nicht ohne Selbst aufgerufen werden kann ?
Sicherlich gibt es viele Fälle , in denen selbst wird notwendig. Dies gilt nicht nur für Ruby, um ganz klar zu sein:
using System;
public class A {
public A() {}
public int test { get { return 4; }}
public int useVariable() {
int test = 5;
return test;
}
public int useMethod() {
int test = 5;
return this.test;
}
}
public class Test {
public static void Main() {
A a = new A();
Console.WriteLine("{0}", a.useVariable()); // prints 5
Console.WriteLine("{0}", a.useMethod()); // prints 4
}
}
Dieselbe Mehrdeutigkeit wird auf dieselbe Weise gelöst. Aber während ich subtil bin, frage ich nach dem Fall, wo
- Ein Verfahren ist definiert worden, und
- Es wurde keine lokale Variable definiert, und
wir begegnen
qwerty = 4
Was ist mehrdeutig - ist dies ein Methodenaufruf oder eine neue lokale Variablenzuweisung?
@ Mike Stone
Hallo! Ich verstehe und schätze die Punkte, die Sie gemacht haben, und Ihr Beispiel war großartig. Glauben Sie mir, wenn ich sage, wenn ich genug Ruf hätte, würde ich Ihre Antwort abstimmen. Wir sind uns jedoch nicht einig:
- auf eine Frage der Semantik, und
- auf einen zentralen Punkt der Tatsache
Zuerst behaupte ich, nicht ohne Ironie, wir führen eine semantische Debatte über die Bedeutung von "Mehrdeutigkeit".
Wenn es um die Analyse und Programmiersprachen-Semantik geht (das Thema dieser Frage), würden Sie sicherlich ein breites Spektrum des Begriffs "Mehrdeutigkeit" zugeben. Nehmen wir einfach eine zufällige Notation an:
- mehrdeutig: lexikalische Mehrdeutigkeit (Lex muss nach vorne schauen)
- Mehrdeutig: grammatikalische Mehrdeutigkeit (yacc muss sich der Analyse des Analysebaums unterziehen)
- AMBIGUOUS: Mehrdeutigkeit, die im Moment der Ausführung alles weiß
(und es gibt auch Müll zwischen 2-3). Alle diese Kategorien werden aufgelöst, indem mehr Kontextinformationen gesammelt werden, die immer globaler aussehen. Also, wenn du sagst,
"qwerty = 4" ist in C # UNAMBIGUOUS, wenn keine Variable definiert ist ...
Ich konnte nicht mehr zustimmen. Aber aus dem gleichen Grund sage ich
"qwerty = 4" ist in Rubin nicht mehrdeutig (wie es jetzt existiert)
"qwerty = 4" ist in C # mehrdeutig
Und wir widersprechen uns noch nicht. Schließlich sind wir uns hier nicht einig: Entweder könnte Ruby ohne weitere Sprachkonstrukte implementiert werden oder nicht, so dass
Für "qwerty = 4" ruft ruby UNAMBIGUOUSLY einen vorhandenen Setter auf, wenn
keine lokale Variable definiert ist
Du sagst nein. Ich sage ja; Es könnte ein anderer Ruby existieren, der sich in jeder Hinsicht genau wie der Strom verhält, außer dass "qwerty = 4" eine neue Variable definiert, wenn kein Setter und kein lokaler vorhanden ist. Er ruft den Setter auf, falls einer vorhanden ist, und weist ihn dem lokalen zu, wenn einer vorhanden ist. Ich akzeptiere voll und ganz, dass ich falsch liegen könnte. In der Tat wäre ein Grund, warum ich falsch liegen könnte, interessant.
Lassen Sie mich erklären.
Stellen Sie sich vor, Sie schreiben eine neue OO-Sprache mit Zugriffsmethoden, die wie Instanzvariablen aussehen (wie Ruby & C #). Sie würden wahrscheinlich mit konzeptionellen Grammatiken beginnen wie:
var = expr // assignment
method = expr // setter method invocation
Aber der Parser-Compiler (nicht einmal die Laufzeit) wird kotzen, denn selbst nachdem alle Eingaben bearbeitet wurden, gibt es keine Möglichkeit zu wissen, welche Grammatik relevant ist. Sie stehen vor einer klassischen Wahl. Ich kann mir der Details nicht sicher sein, aber im Grunde macht Ruby das:
var = expr // assignment (new or existing)
// method = expr, disallow setter method invocation without .
Deshalb ist es nicht eindeutig, während und C # dies tut:
symbol = expr // push 'symbol=' onto parse tree and decide later
// if local variable is def'd somewhere in scope: assignment
// else if a setter is def'd in scope: invocation
Für C # befindet sich "später" noch zur Kompilierungszeit.
Ich bin sicher, Ruby könnte das Gleiche tun, aber "später" müsste zur Laufzeit sein, denn wie Ben betont, weiß man erst, wenn die Anweisung ausgeführt wird, welcher Fall zutrifft.
Meine Frage sollte niemals bedeuten: "Brauche ich wirklich das 'Selbst'?" oder "Welche potenzielle Mehrdeutigkeit wird vermieden?" Ich wollte eher wissen, warum diese besondere Wahl getroffen wurde. Vielleicht ist es keine Leistung. Vielleicht hat es gerade die Arbeit erledigt, oder es wurde als das Beste angesehen, einem 1-Liner-Einheimischen immer zu erlauben, eine Methode zu überschreiben (eine ziemlich seltene Fallanforderung) ...
Aber ich schlage vor, dass die dynamischste Sprache diejenige sein könnte, die diese Entscheidung am längsten aufschiebt, und wählt die Semantik basierend auf den kontextuellsten Informationen: Wenn Sie also keine lokale Sprache haben und einen Setter definiert haben, wird der Setter verwendet . Ist das nicht der Grund, warum wir Ruby, Smalltalk, Objc mögen, weil der Methodenaufruf zur Laufzeit entschieden wird und maximale Ausdruckskraft bietet?
$this->
beim Zugriff auf Instanzvariablen. Das stolpert mich die ganze Zeit.Antworten:
Das Wichtigste dabei ist, dass Ruby-Methoden zu jedem Zeitpunkt (un) definiert werden können. Um die Mehrdeutigkeit intelligent aufzulösen, müsste für jede Zuweisung Code ausgeführt werden, um zu überprüfen, ob zu diesem Zeitpunkt eine Methode mit dem zugewiesenen Namen vorhanden ist der Zuordnung.
quelle
x=5
Angeben eine lokale Variable instanziiert wird,x
die jeden vorhandenen Setter überschreibtself.x=
. Um diese Unklarheit zux=
self.x=
Nun, ich denke, der Grund dafür ist, dass dies nicht
qwerty = 4
eindeutig ist - definieren Sie eine neue Variable namensqwerty
oder rufen Sie den Setter auf? Ruby löst diese Mehrdeutigkeit, indem es sagt, dass eine neue Variable erstellt wird, daherself.
ist die erforderlich.Hier ist ein weiterer Fall, in dem Sie benötigen
self.
:class A def test 4 end def use_variable test = 5 test end def use_method test = 5 self.test end end a = A.new a.use_variable # returns 5 a.use_method # returns 4
Wie Sie sehen können, ist der Zugriff auf nicht
test
eindeutig, daherself.
ist der Zugriff erforderlich.Aus diesem Grund ist das C # -Beispiel eigentlich kein guter Vergleich, da Sie Variablen auf eine Weise definieren, die für die Verwendung des Setters eindeutig ist. Wenn Sie in C # eine Variable definiert hätten, die denselben Namen wie der Accessor hat, müssten Sie Anrufe an den Accessor
this.
genau wie im Fall Ruby qualifizieren.quelle
Denn sonst wäre es unmöglich, innerhalb von Methoden überhaupt lokale Variablen zu setzen.
variable = some_value
ist nicht eindeutig. Zum Beispiel:class ExampleClass attr_reader :last_set def method_missing(name, *args) if name.to_s =~ /=$/ @last_set = args.first else super end end def some_method some_variable = 5 # Set a local variable? Or call method_missing? puts some_variable end end
Wenn
self
nicht für Setter erforderlich,some_method
würde erhöhenNameError: undefined local variable or method 'some_variable'
. Wie es ist, funktioniert die Methode wie beabsichtigt:example = ExampleClass.new example.blah = 'Some text' example.last_set #=> "Some text" example.some_method # prints "5" example.last_set #=> "Some text"
quelle
self.
.