Ruby-сеттеры - созданные с помощью (c)attr_accessor
или вручную - кажутся единственными методами, которым требуется квалификация self.
при доступе внутри самого класса. Это, кажется, оставляет Ruby один в мире языков:
- Все методы нуждаются в
self
/ this
(как в Perl, и я думаю, что Javascript)
- Методы не требуются
self
/ this
is (C #, Java)
- Нужны только сеттеры
self
/ this
(Ruby?)
Лучшее сравнение - C # против Ruby, потому что оба языка поддерживают методы доступа, которые синтаксически работают так же, как переменные экземпляра класса: foo.x = y
, y = foo.x
. C # называет их свойствами.
Вот простой пример; та же программа на Ruby, затем 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
уберите self.qwerty =()
, и он потерпит неудачу (Ruby 1.8.6 в Linux и OS X). Сейчас 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();
}
}
Вопрос: это правда? Есть ли другие случаи, кроме сеттеров, где необходимо «я»? То есть, есть ли другие случаи, когда метод Ruby не может быть вызван без self?
Есть, конечно, много случаев, когда self становится необходимым. Это не уникально для Ruby, просто чтобы прояснить:
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
}
}
Та же неоднозначность разрешается таким же образом. Но пока тонко, я спрашиваю о случае, когда
- Для метода определено и
- Нет определена локальная переменная, а
мы встречаемся
qwerty = 4
что неоднозначно - это вызов метода или присвоение новой локальной переменной?
@ Майк Стоун
Привет! Я понимаю и ценю ваши замечания и ваши
пример был великолепен. Поверь мне, когда я скажу, что если у меня достаточно репутации,
Я бы проголосовал за ваш ответ. Тем не менее, мы все еще не согласны:
- по вопросу семантики и
- по центральному факту
Сначала я утверждаю, что не без иронии мы ведем семантическую дискуссию о
значение слова «двусмысленность».
Когда дело доходит до синтаксического анализа и семантики языка программирования (предмет
этого вопроса), конечно, вы бы признали широкий спектр понятий
«Двусмысленности». Давайте просто примем несколько случайных обозначений:
- неоднозначность: лексическая неоднозначность (лекс должен «смотреть в будущее»)
- Неоднозначность: грамматическая неоднозначность (yacc должен отложить до анализа дерева разбора)
- AMBIGUOUS: двусмысленность, зная все в момент исполнения
(и между 2-3 тоже есть мусор). Все эти категории разрешены
собирать больше контекстной информации, искать все больше и больше в глобальном масштабе. Итак, когда вы
говорят,
"qwerty = 4" является НЕПРАВИЛЬНЫМ в C #
когда переменная не определена ...
Я не могу не согласиться. Но в то же время я говорю
"qwerty = 4" не однозначно в рубине
(как оно существует сейчас)
"qwerty = 4" является неоднозначным в C #
И мы еще не противоречим друг другу. Наконец, вот где мы на самом деле
не согласен: любой рубин может или не может быть реализован без дальнейшего
языковые конструкции такие, что
Для "qwerty = 4" ruby UNAMBIGOUSLY
вызывает существующий сеттер, если
локальная переменная не определена
Вы говорите нет. Я говорю да; мог существовать другой рубин, который ведет себя так же, как
ток во всех отношениях, кроме"qwerty = 4" определяет новый
переменная, когда нет сеттера и нет локального, он вызывает сеттер, если один
существует, и он присваивает локальный, если таковой существует. Я полностью согласен с тем, что я
может быть не так. На самом деле, причина, по которой я могу ошибаться, была бы интересна.
Позвольте мне объяснить.
Представьте, что вы пишете новый ОО-язык с методами доступа
как экземпляры vars (например, ruby & C #). Вы, вероятно, начали бы с
концептуальные грамматики что-то вроде:
var = expr // assignment
method = expr // setter method invocation
Но парсер-компилятор (даже не среда выполнения) будет рвать, потому что даже после
всеВвод вводится в заблуждение, нет способа узнать, какая грамматика уместна.
Вы столкнулись с тем, что классический выбор. Я не могу быть уверен в деталях, но
в основном ruby делает это:
var = expr // assignment (new or existing)
// method = expr, disallow setter method invocation without .
, поэтому он не однозначен, а C # делает это:
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
Для C # 'позже' все еще находится во время компиляции.
Я уверен, что ruby мог бы сделать то же самое, но «позже» должно быть во время выполнения, потому что
как указывает Бен, вы не знаете, пока не будет выполнено утверждение, в каком случае
применяется.
Мой вопрос никогда не предназначался для обозначения "действительно ли мне нужно" я "?" или что
потенциальной двусмысленности избегают? Скорее я хотел знать, почему это было
конкретный выбор сделан? Может быть, это не производительность. Может быть, он только что получил работу
сделано, или было сочтено наилучшим всегда разрешать 1-локальной строке переопределять
метод (довольно редкий случай) ...
Но я вроде бы предполагаю, что наиболее динамичным языком может быть тот, который
откладывает это решение дольше всего и выбирает семантику на основе наиболее контекстуального
Информация: так что если у вас нет локального и вы определили установщик, он будет использовать установщик. не
вот почему нам нравится ruby, smalltalk, objc, потому что вызов метода решается во время выполнения,
предлагая максимальную выразительность?