Есть ли цель или польза в запрете повторного связывания переменных без сигилов?
В попытке лучше понять переменные без сигил и как они отличаются от $
я обнаружил, что в отличие от переменных $
переменные с сигилами, переменные без сигилов не могут быть восстановлены после инициализации:
my $a = 42;
my $b := $a;
$b := 42; # No exception generated
my \c := $a;
c := 42; # OUTPUT: «Cannot use bind operator with this left-hand side»
Это по замыслу? Если да, то есть ли цель или выгода запретить повторное связывание переменных без сигилов, когда $
переменные с сигилом не запрещены?
2 ответа
Да, это, конечно, дизайн, и - как и большинство вещей в дизайне Perl (6) - это так по нескольким причинам.
Прежде чем обсуждать синтаксис символов без символов, стоит немного вспомнить некоторые роли, которые сигилы играют в языке. Они включают:
- Синтаксическая неоднозначность (вы можете вызывать переменную как угодно, даже если есть ключевое слово с таким именем)
- Удобочитаемость (данные в программе выдаются благодаря символу)
- Определение семантики присваивания (в Perl 6 присвоение означает "копировать в", таким образом
my @a = @b
означает итерацию@b
и положить каждую вещь в это в@a
Таким образом, любые будущие назначения@b
не повлияет@a
) - Ограничение того, что можно связать там (только
Positional
вещи для@
, например) - В случае с
$
контролируя то, что будет считаться одним предметом - В случае
@
на параметр подписи, вызывая входящийSeq
быть кэшированным
Таким образом, каждый символ содержит набор полезных поведений по умолчанию для данных, которые следует рассматривать как отдельный элемент ($
), что-то, чтобы индексировать в позиционно (@
) что-то для индексации с помощью ключа (%
) и то, что можно назвать (&
). Каждый из них, как в контексте назначения, низкоуровневого связывания, так и связывания подписи, несет обычно желательную семантику для данных такого типа.
Это хорошо, пока кто-то не захочет написать код, который будет полиморфным для всех этих поведений, или не будет придерживаться какого-либо поведения сигилов. Более ранние итерации дизайна языка Perl 6 имели что-то вроде sub foo($x is parcel) { }
, где is parcel
вещь фактически означала "не навязывать никакой семантики сигил-й", за исключением того, что это было довольно запутанным, потому что вещь имела $
сигил, но был исключен из семантики. Было понято, что если бы поведение сигил не применялось, то было бы лучше, если бы оно выглядело по-другому (принцип дизайна "разные вещи должны выглядеть по-разному", который также неоднократно проявляется в Perl). Самый очевидный способ выглядеть по-другому - это не иметь сигилу.
Однако по синтаксическим соображениям в сигнатуре нужно было что-то использовать для устранения неоднозначности имени, вводимого из типа (поскольку сигнатура (Foo)
соответствовать по типу Foo
но игнорируйте значение, которое уже было поддержано и полезно, и мы не хотели потерять это). \
был выбран, чтобы играть эту роль, получая sub foo(\x) { }
, который затем позволил использование x
внутри подпрограммы.
Насколько я помню, разрешив эту форму в случае my
пришел чуть позже, хотя я не совсем уверен в этом. Одна из важных вещей о том, что символ без знака не фиксирует поведение, состоит в том, что он также не фиксирует поведение присваивания, таким образом, =
он немного более поздний (где это возможно, компилятор рассматривает сигил и выдает совсем другой код для $
/&
а также @
/%
задания). Конечно, если символ связан со значением, тогда никакое присвоение невозможно.
Это оставляет вопрос обязательного поведения. Было решено сделать символ без сигилы формой синтаксиса "статического одиночного назначения", как объяснено в одном из других ответов. Для этого были разные причины, в том числе:
- Помощь в сохранении свойства читабельности "данных выделяется" для сигил, по крайней мере, следя за тем, чтобы все, что должно быть (немедленно) изменяемым, все еще содержало сигилу
- Также улучшается читаемость программы благодаря наличию формы, которая позволяет читателю узнать, что символ никогда не будет возвращен к новому значению, так что можно эффективно считать его постоянным в пределах области видимости. Это согласуется с тем, что легко объявить реальным
constant
без сигил - Осторожно поощряйте более функциональный стиль (возможно, заставляя тех, кто решит, что они ненавидят сигилы, возвращать остальным нам код, который, по крайней мере, более читабелен другим способом, чем предлагают сигилы:-))
Наконец, я отмечу, что я нахожу термин "переменная без сигил" немного вводящим в заблуждение, потому что в нем нет ничего переменного. Это синтаксис для введения символа, который инициализируется привязанным к определенной вещи и всегда будет в течение (лексического) времени жизни этого символа. Лучший способ думать о них, вероятно, считать их отличными от переменных - которые подразумевают хранение - и вместо этого просто рассматривать их как способ присвоения имени значению.
Переменные без сигилов имеют семантику одиночного статического присваивания.
Преимущества возможности оптимизации
Цитирование из раздела "Преимущества" вышеупомянутой связанной страницы SSA:
Основная полезность SSA заключается в том, что он одновременно упрощает и улучшает результаты различных оптимизаций компилятора, упрощая свойства переменных. Например, рассмотрим этот кусок кода:
y := 1
y := 2
x := y
Люди могут видеть, что первое назначение не является необходимым, и что ценность
y
используется в третьей строке происходит от второго назначенияy
, Чтобы определить это, программа должна выполнить анализ достигнутого определения. Но если программа в форме SSA, оба из них являются немедленными:
y1 := 1
y2 := 2
x1 := y2
Алгоритмы оптимизации компилятора, которые либо включены, либо сильно улучшены с помощью SSA, включают [длинный список доступных оптимизаций].
Таким образом, в принципе, при написании кода с использованием переменных без сигилов вы предоставляете компилятору больше возможностей для оптимизации.
Преимущества человеческого мышления
В целом, в P6 вещи, которые меняются, имеют сигилу и наоборот, а вещи, которые не имеют, не делают, и наоборот. С этой точки зрения имеет смысл запретить повторное связывание.
(По этой причине я склонен считать, что привязка переменной без сигил к контейнеру, как я показал в своем комментарии к вашему вопросу, особенно привязка к Scalar
контейнер, это сомнительная практика.)