Считается, что знаки повышают выразительность языка программирования, поскольку делают текст программы более лаконичным. С этим трудно не согласиться, но есть
и обратная сторона. По сравнению с обычными словами знаки требуют дополнительных умственных усилий при их осмыслении человеком.
Далее подробно рассмотрены факторы, влияющие на трудоёмкость осмысления знаков, а именно:
-
проговариваемый знак или разделительный;
-
относительное расположение знака;
-
нагруженность знака и его расположения;
-
таблица приоритетов операций, обозначаемых знаками;
-
очевидность и стандартность знака.
Эти факторы лежат в основе правил для отсеивания неудачных вариантов при выработке системы знаков в языках программирования. Правила сформулированы в конце. Они используются в том числе при разработке семейства языков Артель.
Цена лаконичности знаков
Начать размышления имеет смысл с базовых операций и их обозначений в нескольких языках программирования.
C#/Java Oberon-07 Pascal Артель
= := := =
== = = ==
!= # <> !=
&& & and и
|| OR or или
! ~ not не
5/6 3/6 2/6 2/6
По этой таблице можно заметить, что первый столбец воспринимается сложнее по сравнению с остальными. Сложность коррелирует с дробями, указанными внизу таблицы. Это удельное число знаков, которые не присущи школьной литературе и математике (либо имеют там
совершенно иной смысл).
Чтобы понять трудоёмкость осмысления знаков, стоит кратко коснуться самого процесса осмысления текста человеком. Этот процесс представляет собой внутренний монолог – человек мысленно проговаривает слова для построения смыслов в собственном воображении.
Необходимость мысленно проговаривать слова текста, вероятно, связана с тем, что речь предшествует письменности. Человек сначала учится распознавать окружающую речь и говорить, и лишь затем писать и читать. Соответственно читаемые слова и знаки человек осмысливает через более базовый аппарат – речевой.
В речи человека есть слова, но нет знаков. Для проговаривания увиденного знака приходится сначала искать соответствующее знаку слово. Если нет слова, то нет понимания. Поэтому даже матёрый профессионал вынужден осмысливать знаки &&, ||, ! через проговаривание их в уме в виде слов и, или, не. Новичку же для начала нужно натренировать свой
а && б а и б
а || б а или б
!а не а
Попутно новичку приходится ломать все свои представления о том, где обычно пишут восклицательный знак. Ведь и в литературе, и в математике восклицательный знак принято
записывать после чего-то, а не до. Однако не забывать при этом, что всё-таки восклицательный знак может быть записан и после чего-то, придавая уже совсем другой смысл.
!а
а!
!(а || б)
ф!(а || б)
И тут возникает закономерная мысль. А стоит ли эта ломка того, чтобы сокращать слово из двух букв не до одного знака !?.. И зачем нагружать
Можно, конечно, рассуждать о том, что по сравнению со словами, знаки позволяют также экономить на пробелах. Но осмысливать длинные непрерывные последовательности букв и знаков человеку крайне тяжело.
!(а.выкл||а.сбой&&а.резервирование)
Поэтому на практике пробелы всё же оставляют. И тогда оказывается, что разница в лаконичности между знаками и словами в логических выражениях практически
отсутствует.
!(а.выкл || а.сбой && а.резервирование)
не(а.выкл или а.сбой и а.резервирование)
По сути, более лаконичным по сравнению со словами можно назвать лишь тривиальный случай записи с восклицательным знаком, когда отрицаемое им не содержит пробелов. Но зачем дополнительная лаконичность в тривиальных случаях?
если !вкл тогда ...
если не(вкл) тогда ...
Выше затронут фактор пробелов. Они сильнейшим образом влияют на восприятие текста человеком. В античности все слова записывали слитно без пробелов. Читать было тяжело, поэтому слова начали разделять средними точками, а позднее просто пробелами.
PERASPERAADASTRA
PER·ASPERA·AD·ASTRA
PER ASPERA AD ASTRA
С развитием естественных языков начали появляться и другие разделительные знаки, например, знаки пунктуации. Они использовались для управления интонацией при чтении
вслух: паузы, восклицания, вопросы и т.д. При чтении про себя эти знаки помогают легче распознавать структуру текста и акценты. Такие знаки не требуют обязательного проговаривания в виде слов при чтении.
. , ; : ! ? !? ...
А проговариваемые знаки появились позднее разделительных как средство повышения лаконичности и выразительности в науках, например, в арифметике.
а = б + в а равно б плюс в
Проговариваемые знаки требуют больше умственных усилий для осмысления, чем разделительные. Это стоит учитывать при выборе знаков для языка программирования.
Число[] [] проговаривается как «массив»
[]Число [] проговаривается как «массив»
Массив<Число> < и > являются разделительными
На умственные усилия влияет также расположение знака относительно того, к чему он применяется. Расположение бывает правостороннее, левостороннее, внутреннее,
открывающее и закрывающее. Все эти разновидности расположений применяются и в школьной литературе, и в математике, и в программировании.
Привет! правостороннее
#программирование левостороннее
@пользователь левостороннее
-а левостороннее
а - б внутреннее
человек-амфибия внутреннее
(фрагмент текста) пара: открывающее, закрывающее
"Текст в кавычках" и открывающее и закрывающее
м[...] правосторонне-открывающее
Опираясь на опыт чтения самых разнообразных текстов со всевозможными комбинациями расположения знаков, можно заметить следующее:
-
правостороннее, открывающее и закрывающее расположение наиболее распространённое, поэтому его осмысливать легче всего;
-
внутреннее расположение менее распространено, поэтому осмысливать его уже тяжелее;
-
левостороннее расположение наименее распространено, поэтому осмысливать его тяжелее всего;
Если знак располагается так, как это не принято в школьной литературе и математике, то это существенно увеличивает умственные усилия по осмыслению.
!вкл!
?название
?объект?.код
!объект!.код
[]Число
Число[]
Затруднение в таких случаях связано с тем, что
Один и тот же знак может предполагать сразу несколько расположений. И каждое расположение может иметь несколько разных смыслов в зависимости от контекста. Поэтому один и тот же знак может быть нагружен многими смыслами, порой вообще не связанными между собой.
Число 1.234,5 меньше числа 5.432,1.
если а + б = 0, то б = -а
В примере выше знак точки в самом конце расположен справа и означает окончание предложения, а в числах он расположен внутри и означает разделение частей числа. А знак равно расположен между переменными и нагружен как вопросительным (сравнительным), так и утвердительным смыслом.
Нагруженность знака многочисленными расположениями и смыслами существенно увеличивает трудоёмкость осмысления. По этой причине следует с осторожностью относится к идее вводить левостороннее расположение знака в дополнение к правостороннему, когда знаков перестаёт хватать.
а?
?а
Цена неочевидности приоритетов
Отдельного внимания заслуживают левостороннее и внутреннее расположение знака.
!а
а || б
а && б
Их осмысление требует кроме всего прочего ещё и поиска границ того, на что знак воздействует. В языках программирования в таких ситуациях в дело вступает таблица приоритетов операций, которые этими знаками обозначаются. Именно эта таблица определяет границу того, на что знак воздействует.
!а!.б! || в == г
Точный смысл:
(!(а!.б!)) || (в == г)
Процесс осмысления:
(!а!.б! || в == г отсекаем правостороннюю форму
(!(а!.б! || в == г начинаем поиск правой границы
(!(а)!.б! || в == г
(!(а!).б! || в == г
(!(а!.)б! || в == г
(!(а!.б)! || в == г
(!(а!.б!) || в == г упёрлись в меньший приоритет
...
(!(а!.б!)) || (в == г) похоже это именно оно
...
(!(а!.б! || в == г) не похоже на правду
Для сравнения:
не(а!.б!) или в == г
Ситуация усугубляется тем, что из-за обилия знаков и слов в современных языках программирования их таблицы приоритетов такие огромные, что их никто не знает и даже не пытается запоминать. Для примера, одна из самых простых таблиц приоритетов среди современных промышленных языков:
Постфиксные ++ --
Унарные ++ -- + - ~ !
Умножение * / %
Сложение + -
Сдвиги << >> >>>
Отношения < > <= >= instanceof
Сравнения == !=
Бинарное «и» &
Бинарное «искл» ^
Бинарное «или» |
Логическое «и» &&
Логическое «или» ||
Тернарные ? :
Присваивания = += -= *= /= %= &= ^= |= <<= >>= >>>=
Со временем, натренировав свой
перестаёт чувствовать всю их сложность. Вроде бы как и нет проблемы.
Но это только до тех пор, пока профессионал не столкнётся в каком-то другом языке с новыми знаками, их новым качеством или другой таблицей приоритетов. Например, с левосторонним расположением знака вопроса, который в таком виде встречается крайне редко.
?а!.б! || в == г "?" работает также как "!" или нет?
Если профессионалу приходится иметь дело одновременно с тремя и более языками программирования, то постоянно переключать в голове знаки и таблицы приоритетов
становится проблематично. И чтобы избавиться от сомнений, ему становится проще явно обозначать границы и приоритеты с помощью круглых скобок и пробелов. Чтобы действовать наверняка и без всяких сюрпризов.
(?(а!.б!)) || (в == г)
Таким образом, сложность осмысления левостороннего и внутреннего расположения знака напрямую зависит от сложности таблицы приоритетов операций. И каждый такой случай, тем более незнакомый и непривычный, является испытанием и для новичков, и для профессионалов. А поскольку зачастую такой знак нагружен многими смыслами, то сложность начинает зашкаливать.
А вот правостороннее расположение считывается легко, поскольку порядок применения знака просто соответствует порядку его записи в тексте.
Всё это свидетельствует о принципиальной важности количества знаков в языке и важности размера таблицы приоритетов. Таблица приоритетов это не просто справочник. Это та незримая работа, которую
Польза стандартных знаков
Трудоёмкость осмысления знака зависит также от его стандартности. Это единое понимание знака в рамках того или иного сообщества людей. Можно условно выделить очевидные, стандартные профессиональные и нестандартные знаки.
Очевидные знаки человек осваивает через школьную литературу и математику. И они постоянно на виду в повседневной жизни. Поэтому они наиболее понятны самому широкому кругу людей. Вот список очевидных знаков, которые в программировании удобно использовать со смыслом, близким к литературному или математическому:
Проговариваемые:
= равно (теперь равно, изменить на)
+ плюс
- минус
* умножить на
/ поделить на
< меньше
<= меньше либо равно
> больше
>= больше либо равно
-> превращается в
=> следовательно
Разделительные:
, разделитель перечисляемых элементов
; разделитель самостоятельных фраз
" начало и конец обособленного текста
() начало и конец подчинённого фрагмента
Стандартные профессиональные знаки не являются очевидными для обычного человека, но широко используются в программировании и имеют одинаковое расположение и смысл в подавляющем большинстве наиболее популярных языков программирования (с заданной областью применения и целевой аудиторией).
Проговариваемые:
== равно
!= не равно
+= увеличить на
-= уменьшить на
*= приумножить (в N раз)
/= сократить (в N раз)
% взять остаток от деления на
! не (отрицание, левостороннее расположение)
Разделительные:
. уточнение имени
: указание типа данных
[] начало и конец списка ключей или элементов
{} начало и конец блока
// комментарий
экранирование
Нестандартные знаки используются в своём конкретном смысле лишь в ограниченном количестве языков программирования. Поэтому они понятны в основном тем, кто постоянно имеет с ними дело по роду своей деятельности.
?: !! ..< &<< &>> &* ~= и др.
С очевидными знаками сталкиваются все образованные люди по мере изучения школьной литературы и математики. Но изучение остальных знаков, будь они стандартные профессиональные или нестандартные, должно иметь некоторую целесообразность.
Зачем новичку тренировать свой
Учимся:
а := б
если а = б & в # г тогда ...
Переучиваемся:
а = б
если а == б && в != г тогда ...
От детей постоянно звучит веский аргумент, что изучаемый ими в школе язык программирования «не настоящий и не пригодится в жизни». Честно говоря, на это сложно что-то возразить, даже если вы, как и автор этой статьи, душой тяготеете к какому-нибудь «ненастоящему» языку и считаете первый вид записи в примере выше более элегантным. Но с реальностью тоже приходится считаться.
Парадоксальным образом стандартность знака может быть более важна для профессионала, чем для новичка. Ведь если профессионал вынужден иметь дело одновременно с несколькими языками, то при частом переключении между ними легко запутаться и в знаках, и в смыслах. Знак становится не просто нагружен, а перегружен всевозможными смыслами.
~a логическое или битовое?
~"а" маркер? или есть понятие отрицания текста?
?a что бы это могло значить...
И самый матёрый полиглот, и закоренелый фанат, и крепкий середнячок превращается в растерянного новичка, когда видит в языке программирования знак, который раньше не видел или подзабыл со временем, или который до сего момента значил для него нечто другое. О
новичках, середнячках, фанатах и полиглотах подробнее в здесь.
Тут важно заметить, что когда-то все знаки были нестандартными, включая арифметические. И стандартными они стали лишь со временем. А однажды могут и перестать ими быть, если практика выявит в них изъяны. Поэтому порой не нужно стесняться подвергать сомнению даже самые стандартные знаки.
Например, можно подумать над тем, чтобы отказаться от стандартных знаков << и >> для обозначения битовых сдвигов. Такие знаки осложняют использование одиночных знаков < и > в качестве угловых скобок, например, при обозначения параметров в шаблонах типов
Массив<Число>. Ведь при наличии угловых скобок знак >> перестаёт быть однозначной лексемой.
Массив<Массив<Число>> >> или же > и ещё раз >
Это одна из причин, по которой знаки битовых операций отсутствуют в списке стандартных выше.
Правила отсеивания знаков
Создание языка программирования и выработка его системы знаков – процесс творческий. А продуктивный творческий процесс нуждается хотя бы в минимальных правилах.
С учётом всего вышесказанного о трудоёмкости осмысления знаков, правила отсеивания неудачных вариантов могут выглядеть так:
-
знак не подходит, если он в таком же качестве применяется менее, чем в {А}% самых популярных языков;
-
знак не уместен, если его расположение чуждо школьной литературе и математике;
-
знак не нужен, если программист видит обозначаемое им понятие в тексте программы
реже одного раза в {Б} дней; -
знак не целесообразен, если существует полное или сокращённое слово длиной до {В} букв включительно;
-
но знак может быть исключением из правил, если в языке программирования не более {Г} таких исключений.
Путём подстановки нужных значений А-Б-В-Г можно ограничить себя определёнными рамками.
Например, формула 70-365-3-1 фиксирует, что в языке допустимы лишь очевидные и стандартные знаки с таким же смыслом как минимум в 70% наиболее популярных языков,
нужные программисту не реже одного раза в 365 дней и не имеющие подходящего полного/сокращённого слова длиной до 3 букв включительно, но с правом на 1 исключение из всех этих правил.
Формулы 70-900-4-3 и 70-100-3-0 используются в языках семейства Артель.
Сами формулы можно использовать не только как ограничительные рамки при выработке системы знаков, но и как способ оценки уже существующих систем знаков.
Справочник
Полный список формальных характеристик знака:
Очевидный : да/нет
Стандартный : да/нет
Нестандартный : да/нет
Проговариваемый : да/нет
Разделительный : да/нет
Расположение правостороннее : да/нет
Расположение внутреннее : да/нет
Расположение левостороннее : да/нет
Расположение открывающее : да/нет
Расположение закрывающее : да/нет
Вариативность расположения : от 1 до 7
Чуждость расположения : от 1 до 6
Нагрузка : целое число
Нагрузка расположения : целое число
В расчётах и анализе каждое расположение знака с каждым конкретным смыслом для заданного контекста рассматривается как отдельный знак.
Дополнительные определения:
-
вариативность расположения – это количество возможных расположений знака без учёта смысловой нагрузки;
-
чуждость расположения – это количество возможных расположений знака, которые не встречаются в школьной литературе и математике;
-
нагрузка знака – это количество смыслов, которые может иметь знак в зависимости от расположения и контекста;
-
нагрузка расположения – это количество смыслов, которые может иметь одно конкретное расположение знака в зависимости от контекста.
Автор: ychetyrko
