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