Вдруг вы не знали, но в языке, на котором вы пишите, вы можете использовать _
в числах. Например, следующий код на PHP:
<?php
print(1_00);
print(100);
Выведет 100100
(проверить онлайн). Этот синтаксический сахар появился в Ada в 1980 году, и он имел переменный успех последние 40 лет. Но за последний год его добавили в javascript, PHP, Go, Scala и даже консервативный Erlang. Я не могу объяснить, что послужило всплеском популярности, поэтому в статье просто опишу историю разделителей в цифрах.
19 68 Algol
На заре программирования не особенно заморачивались с пробелами, а поэтому в Algol в именах переменных и цифрах можно было вставлять пробел. Например, a 1 st var
— корректное название переменной, и синоним a1stvar
. Код:
BEGIN
INT a 1 st var = 1 234 567;
REAL a 2 nd var = 3 . 1 4159 26 5 359;
print((a1stvar, newline, a2ndvar))
END
Выведет (проверить):
+1234567
+3.14159265359000e +0
Я не смог найти более ранние версии интерпретатора, но очевидно, так вели себя и предыдущие версии Algol. Также, пишут, что FORTRAN до версии 77 года вел себя аналогично.
UPD: В фортране пробелы в числах и именах можно использовать до сих пор (в режиме fixed-form source files). Но fixed-form source files депрекейтед в стандарте 2018 года.
19_80 Ada
Похоже, что впервые использовать подчеркивание как разделитель в цифрах придумали в 1980 году в Ada. Кроме этого, в Ada можно было указывать числа в системах с любым основанием от 2 до 16. 11
в пятеричной системе (6
в десятеричной) можно было записать 5#11#
. Что в свою очередь позволяло делать, такие неочевидные вещи, как I: Float := 3#0.1#
— переменная со значением 1/3 (одна треть):
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
procedure hello is
I: Float := 3#0.1#;
J: Float := 1_00.0;
begin
Put(I);
Put(J);
end hello;
Выведет 3.33333E-01 1.00000E+02
(онлайн).
19_85 Caml
19_87 Perl
Позже, похоже независимо друг от друга, подчеркивание появилось в Caml и Perl. Perl стал первым языком, где (по непонятой мне причине) можно использовать несколько подчеркиваний подряд:
$x = 1_0_0;
$y = 2__5________0;
$z = $x+$y;
print "Sum of $x + $y = $z";
Выведет Sum of 100 + 250 = 350
(проверить).
19_93 Ruby
19_96 OCaml
Это первые два языка, где можно проследить, откуда пришло подчеркивание. OCaml (неожиданно) перенял подчеркивание у Caml, а Ruby создавался под влиянием Perl, откуда и перенял подчеркивание (правда, без возможности ставить несколько подряд).
20_03 D (v0.69)
D стал первым языком, в котором изначально в спецификации подчеркиваний не было, а их добавили позже (через два года после создания).
20_10 Rust
20_11 Java (SE 7)
20_12 Julia
Rust создавался под влиянием OCaml, а Julia под влиянием Ruby. В Java как и в Perl можно ставить несколько подчеркиваний подряд.
20_14 Swift
Под влиянием Rust.
20'14 C++ (v14)
У плюсовиков проблемы всегда отличаются от других. Дело в том, что идентификатор в C++ может состоять из подчеркивания и цифры. То есть, _1
правильное название переменной. И код:
#include <iostream>
int main()
{
for (int _1 = 0; _1 < 5; ++_1) {
std::cout << _1 << " ";
}
}
Выведет 0 1 2 3 4
(проверить). И чтобы не путать название переменных и цифры в C++ разделителем сделали одинарную кавычку 1'00
.
UPD: Более опытные объяснили, что подчеркивание конфликтовало с пользовательскими литералами (User-defined literals). Следующий код корректный и выведет 1
:
#include <iostream>
constexpr unsigned long long operator"" _0(unsigned long long i)
{
return 1;
}
int main()
{
int x = 0_0;
std::cout << x;
return 0;
}
20_16 Python (3.6)
20_17 C# (7.0), Kotlin (v1.1)
20_18 Haskell (GHC 8.6.1)
20_19 JS (V8 v7.5, Chrome 75), PHP (v7.4), Go (v1.13), Scala (v2.13)
Тут что-то произошло, и подчеркивание добавили во все основные языки. Здесь бы и хотел сделать замечание, что подчеркивание хоть и не сильно, но усложняет интерпретаторы или компиляторы. Например, из мануала в PHP регулярные выражения для цифровых литералов:
// PHP 7.3
decimal : [1–9][0–9]* | 0
hexadecimal : 0[xX][0–9a–fA–F]+
octal : 0[0–7]+
binary : 0[bB][01]+
// PHP 7.4
decimal : [1–9][0–9]*(_[0–9]+)* | 0
hexadecimal : 0[xX][0–9a–fA–F]+(_[0–9a–fA–F]+)*
octal : 0[0–7]+(_[0–7]+)*
binary : 0[bB][01]+(_[01]+)*
В добавок, теперь в PHP появилось еще больше способов записать одно и тоже число:
20_20 Erlang (v23)
Дольше всех держался Erlang. Но, что удивительно, с самого начала в Erlang можно было, как и в Ada (даже с похожим синтаксисом), записывать числа в произвольной системе исчисления (до 36). Например, следующий код печатает (онлайн) 3z
в системе с основанием 36 (=143
).
-module(main).
-export([start/0]).
start() ->
io:fwrite("~w", [36#3z]).
Но подчеркивание в цифрах добавили только спустя 33 года после создания языка.
sumanai
Выведет ошибку, потому что не все (увы) перешли на новые версии.
И да, до сих пор не понимаю, зачем это. Для большинства приложений достаточно создать нужные константы, что будет всяко понятнее записи 3_153_600, если вдруг понадобилось число секунд в году. Кстати, в прошлой записи ошибка, число должно быть на порядок больше. Поэтому
Что впрочем можно улучшить, используя другие константы. И с совместимостью чуть получше.
E_STRICT
10000000 => 10_000_000
lorc
10 * 1000 * 1000 ?
E_STRICT
Это подходит только для круглых чисел.
domix32
У кого-то компилятор по честному вставит посчитанную константу, а у кого-то виртуальные машины и такие константы придется на ходу вычислять.
sumanai
Например? До версии 7.0 PHP оптимизировал это на стадии OpCache, сейчас же оно встроено в сам «компилятор». Нулевые накладные расходы. Думаю и в остальных мейнстримных языках должна быть подобная оптимизация.
domix32
JS в зависимости от скоупа константы может сделать оптимизацию и вычислить единожды, но скажем, перезагрузка страницы заставит его выполнить вычисление заново ибо контекст снова будет пересоздан. Есть нюансы, но идея я думаю понятна. Его сосед WASM же вычислит число еще на этапе компиляции и ее можно сразу читать.
Питон вычислит единожды при старте контекста и закэширует в .pyc т.е. и в отличие от JS перезапуск контекста не должен приводить к пересчету. PHP, Ruby та же история.
Ну, а в целом да, вычисления констант обычно супер дешевые и это скорее перфекционизм.
kostia256
главное чтобы был принят единый стандарт в проекте для форматирования чисел. Например индус запишет данное число как 31_53_600 и ему будет норм :)
VolCh
Даже в голову не пришло, что кто-то может так извратиться
MechanicZelenyy
Это в греко-римской культуре мы делим на тысячи: кило, мега, гига, а например японцы делят манами (10000).
VolCh
Про вычисляемые константы типа числа секунд в году хорошая идея, но вот, например записывать пределы вида миллиард = 100010001000 не очень, имхо. 1_000_000_000 куда читаемей, особенно если это не функция приобразования гигабайт в байты и обратно, а, например, лимиты операций по счету
adeshere
Все верно… ну а если год високосный? А астрономы и вовсе верят, что средний тропический год — это 31 556 925 с… Так что простое умножение не всегда спасает. Иногда приходится и константы писать…
Впрочем, с астрономами вообще лучше не связываться, у них даже сутки не всегда равны 60*60*24=86 400 с, т.к. Земля не совсем равномерно вращается ;-)
fougasse
Ну так заведите константу с названием типа LEAP_DIFFERENCE, AVG_TROPICAL_DIFFERENCE и вычисляйте от базового значения 60 х 60 х 24…
Всяко лучше 31566925 как magic number.
adeshere
Само собой, в коде надо писать мнемонику, а не цифру. Но при инициализации этой константы все равно приходится цифры расписывать. То есть, вопрос о разделителях внутри числа не снимается, а только отодвигается в специальное место…
sumanai
А это разве проблема? Иногда мне кажется, что человечество в конец деградировало, раз не может воспринять пусть даже 10 цифр подряд без разделителей. И да, в одном месте однократно можно и потерпеть, набрать и перепроверить. В общем всё ещё не понимаю, какую проблему решают эти разделители.
adeshere
Ну во-первых, человечество действительно деградирует ;-)
Например, в моей молодости фортран очень медленно работал со строками или с посимвольным выводом на экран (а нам хотелось интерфейс типа Norton Commander-а). Так у нас тогда было нормой некоторые функции на ассемблере переписать. И это практически каждый фортранист в какой-то степени мог. А сейчас вставки на ассемблере хорошо, если каждый сотый напишет. Вот и я уже давно не пишу.
Впрочем, возможно я зря обобщаю на все человечество, и деградация только лично у меня происходит ;-))
Но вообще, когда констант много, то просто для удобства чтения кода гораздо лучше числа писать с разделителями. Чтобы хотя бы в этом месте не терпеть и не напрягаться. В фортране это всегда было доступно (а для кого-то и нормой). Сейчас общая тенденция — чтобы всякие подобные мелкие удобства были доступны в любом языке. Чего в этом плохого? Тем более, что синтаксис в разных языках почти единообразный и даже новичку в языке такая запись понятна?
Ну а не если хочется — так никто не заставляет, можно и не использовать.
merhalak
Это не деградация. Просто выгрузили из горячего кеша за ненадобностью. Способность писать на ассемблере сильно переоценена. Долго, геморройно — да, но не сложно. Мы специализируемся на той задаче, которую выполняем сейчас и часто. Просто из-за ограниченности мозгов, увы.
Цепляться за подобные навыки — всё равно, что расписаться в том, что способность адаптироваться под ситуацию сильно ослабла.
Сейчас проблема с производительностью слегка другая: ты можешь написать шикарный, высокопроизводительный код. Но если ты не сможешь передать его для поддержки и развития следующим поколениям — он умрет.
sumanai
Но ведь раньше как-то справлялись. Не это ли признак деградации?
merhalak
И сейчас справляются. Просто на это нужно время. Много времени. Особенно — когда предыдущего сопровождающего уже нет. Ушёл уже куда-то.
Вопрос в том, оставил ли предыдущий хотя бы что-то для сопровождения или там только код. Знаешь, как весело из кода вытаскивать бизнес-логику с требованием ничего не ломать, но дорабатывать и дорабатывать серьёзно?
Впрочем, у каждого из нас могут быть такие грешки. И за мной такой есть.
sumanai
Опять таки, раньше успевали? Можно попытаться сказать, что мол раньше софт выпускали реже, но блин, почему-то мне кажется, что сроки поджимали всегда и везде, уж так устроен бизнес.
merhalak
Проще: и сейчас успевают. Просто вы говорите об ошибке выжившего, а не о деградации.
Yuuri
Во времена вашей молодости и ассемблер наверняка попроще был, не то что современный x86-64 да с расширениями всякими.