On Tue, 18 May 2021 at 23:00, Andrei Klimov andrei_AT_klimov.net <[email protected]> wrote: > > После семинара между двумя Александрами (Гусевым и Коноваловым) возникла > переписка с ограничеснной рассылкой только тем, кто был на семинаре. Я > захотел встрять и посылаю письмо в refal@botik c надеждой, что это обсуждение > будет интересно всем. Также я указал в BCC тех, кто был на семинаре, но на > нашу рассылку не подписан, и еще некоторых коллег. > .............................................
То, что написано ниже, к Рефалу не относится, по крайней мере непосредственно, а было вызвано разговором о ссылках, и, более конкретно, указанием на первичность понятия ссылки и на то, что ссылка — вовсе не машинный адрес. Руки зачесались и не смог устоять :) Итак, вспомнилось несколько вещей. Во-первых то, что в (функциональном) языке Erlang имеется как раз тип абстрактных ссылок — reference: https://erlang.org/doc/reference_manual/data_types.html#reference. Эти значения порождаются особой функцией и каждое из них отличается от остальных. Что характерно, вопреки их имени, они не могут ссылаться ни на что, а существуют сами по себе. Или же можно считать, что любое такое значение только на себя и ссылается. Насколько я понял, развиваемое Andrew Pitt понятие ссылки, про которое рассказал Андрей Климов, ближе всего к этому reference в языке Erlang. Фундаментальность ссылок осознавалась и хорошо видна в определении языка Algol 68, в котором, однако, ссылки строго типизированные. Определение переменной, например int i, закрепляет за именем i тип ref int, т.е. ссылка на целое (а не просто целое). В действительности, int i является сокращённой формой более подробного определения ref int i = loc int, где loc — генератор (локальных в данном блоке) ссылок, порождающий в данном случае ссылку на целое. Имя же i после этого привязывается неотделимым образом к ссылке. Если нужно в одной команде определить переменную и задать значение, на которое она ссылается, то пишут int i := <целочисленное выражение>, что в более подробном виде есть ref int i = loc int := <целочисленное выражение>. И вообще, любое отдельное присваивание i := ... заменяет то, на что ссылается i (или задаёт его, если до того i ни на что не ссылалось). С другой стороны, написав int j = <целочисленное выражение>, за именем j закрепляется тип int (а не ref int) и j становится обозначением соответствующего значения. Заметим, что и здесь, и выше = является не присваиванием, а отождествлением имени со значением. Поскольку тип j не ссылочный, то j не есть переменная, не может ссылаться ни на что, и в частности применение присваивания := к j невозможно. К тому же, на обозначаемое j значение нельзя ссылаться каким-нибудь косвенным образом: его можно только цитировать через имя j. А что собой представляют ссылки (указатели) в «самом ссылочном» языке C? На мой взгляд, словом «указатель» или «ссылка» в C обозначается несколько очень разных понятий: а) ссылка на значение переменной; б) ссылка на начальный или другой элемент массива; в) ссылка на динамически отведённый кусок памяти; г) ссылка на функцию. Свойства этих четырёх видов указателей разные. К а) не имеет смысла применять никакие операции кроме разыменования (хотя язык этого не запрещает). К б), помимо разыменования, применима так называемая адрессная арифметика. Ссылки вида в) имеют тип void* (стрелка в пустоту). Такие ссылки, тем не менее, магически превращаются в ссылки на любой конкретный тип значения. Ввиду всего этого, в) можно считать чуть замаскированным машинным адресом, тогда как а) и б) являются вполне абстрактными ссылками — ничто не требует видеть за ними машинные адреса. Что касается случая г), от него вообще мало пользы. Чем практически (а не формально) отличается тип ссылки на функцию от типа этой же функции? Как мне кажется, смешивание разных понятий под общим именем «ссылка»/«указатель» в C способствует в немалой степени путанице в понимании природы ссылок вообще. Вспомним и о BCPL, где указатели примерно такие как в C, но бестиповые. Этот язык вообще бестиповый, так что указатель — это значение переменной лишь с точки зрения некоторых операций. То же значение для других операций — целое число или что-то ещё. Наконец, кроме ссылок в более-менее прямом смысле, в разных языках программирования имеются другие формы косвенного обращения. В C++, например, такими являются так называемые итераторы. По применяемым над ними действиям они похожи на указатели, но вместе с тем снабжены специфическими для них, и при этом весьма существенными свойствами. Имеется ещё и понятие reference, которое не указатель (и, конечно, не итератор) — как, например, в int & i. Кажется, переводится как «синоним». Примечательно, что сложно даже навести терминологический порядок в таком языке. Скажем, можно постулировать, что имеются разные виды ссылок: указатели (и на самом деле, как уже писал выше, одних их уже несколько видов!), итераторы и синонимы. И не дай бог после этого сказать, что именем i, после присваивания i = 4, ссылаемся на значение 4. В алголе-то может и ссылаемся, а в C++ — нет, так как имя i ссылкой не является. Т.е. нужно ещё избегать неформального использования глагола «ссылаться». В других языках программирования — свои сложности со ссылками, но сами ссылки, в явной или неявной форме, имеются везде. Полагаю, что это разнообразие в понимании ссылок, и много ещё, нужно иметь ввиду, если идти к построению общей теории ссылок.
