ObjectScript — новый встраиваемый и очень легкий объектно-ориентированный язык программирования с открытым исходным кодом. ObjectScript расширяет возможности таких языков, как JavaScript, Lua и PHP. Синтаксис в основном взят из JavaScript, множественное присваивание — из Lua, работа со свойствами — из PHP.
Проект ObjectScript совсем молодой, только недавно появились первые рабочие и стабильные версии. Тем не менее вопрос о спецификации некоторых моментов языка не решен окончательно и находится в стадии проработки. Например, операторы сравнения в разных скриптовых языках работают по-разному, это зависит от того, какие типы данных участвуют в сравнении и какой алгоритм используется в конкретном языке программирования.
Вопрос довольно щекотливый, т.к. от результата булевского выражения зависит, не много не мало, выполнится кусок кода или нет. Русская пословица «одна голова хорошо, а много лучше» подсказывает мне, что лучше обратится к программерскому сообществу и разобраться наверняка в том, какое поведения при сравнении (это операторы >=, >, <=, <, ==, !=) разных типов данных в скриптовом языке является наиболее уместным. Выработать коллегиональное решение и закрепить результат в спецификации ObjectScript.
ObjectScript поддерживает перегрузку операторов сравнения для объектов, но я предлагаю в текущем вопросе остановится на работе операторов сравнения только для примитивных типов данных, это null, boolean, number и string.
Как работает PHP при сравнении
PHP преобразует аргументы в числовые типы, если один из аргументов — число. null преобразуется в 0, true в 1, false в 0, string преобразуется в число до первого невалидного символа, после чего возвращается число (получившееся на текущий момент). В итоге если оба аргумента числа, происходит численное сравнение, если строки — строковое.
Выполним следующий скрипт на PHP:
echo "'a' > 'b' t--> "; var_dump('a' > 'b');
echo "'a' < 'b' t--> "; var_dump('a' < 'b');
echo "'a' > 1 t--> "; var_dump('a' > 1);
echo "'a' < 1 t--> "; var_dump('a' < 1);
echo "'1' > 1 t--> "; var_dump('1' > 1);
echo "'1' < 1 t--> "; var_dump('1' < 1);
echo "'+2.9' > 1 t--> "; var_dump('+2.9' > 1);
echo "'+2.9' < 1 t--> "; var_dump('+2.9' < 1);
echo "'2.9' > 1 t--> "; var_dump('2.9' > 1);
echo "'2.9' < 1 t--> "; var_dump('2.9' < 1);
echo "true > 1 t--> "; var_dump(true > 1);
echo "false < 1 t--> "; var_dump(false < 1);
echo "null > 1 t--> "; var_dump(null > 1);
echo "null < 1 t--> "; var_dump(null < 1);
он выведет:
'a' > 'b' --> bool(false)
'a' < 'b' --> bool(true)
'a' > 1 --> bool(false)
'a' < 1 --> bool(true)
'1' > 1 --> bool(false)
'1' < 1 --> bool(false)
'+2.9' > 1 --> bool(true)
'+2.9' < 1 --> bool(false)
'2.9' > 1 --> bool(true)
'2.9' < 1 --> bool(false)
true > 1 --> bool(false)
false < 1 --> bool(true)
null > 1 --> bool(false)
null < 1 --> bool(true)
Как работает JavaScript при сравнении
JavaScript также преобразует аргументы в числовые типы, если один из них — число, и делает это по следующим правилам: null в 0, undefined в NaN, true в 1, false в 0, string преобразуется в число, если в строке встречается невалидный символ, то возвращается NaN. В итоге, если оба аргумента числа (NaN — тоже число), то сравнение происходит обычным математическим способом, но нужно иметь в виду, что любое сравнение с NaN всегда возвращает false. Например, при штатном программировании на PHP, NaN редко всплывает и его практически никогда не обрабатывают отдельно, вот и строки на PHP будут преобразованы в валидное число в любом случае, в случае ошибки вернется 0, а вот в JS ситуация другая.
Если при сравнении аргументы — строки, то происходит строковое сравнение.
PHP не имеет типа данных undefined, а только null. При конвертировании скриптов c PHP на JS, мы бы всегда задумывались, что использовать на JS вместо PHP-шного null, то ли JS-ый null, то ли JS-ый undefined. Поэтому мы обязаны в тест на JS включить undefined и проверить, как он работает в сравнении с числом.
Выполним следующий код на JS в браузере:
console.log("'a' > 'b' t--> ", 'a' > 'b');
console.log("'a' < 'b' t--> ", 'a' < 'b');
console.log("'a' > 1 t--> ", 'a' > 1);
console.log("'a' < 1 t--> ", 'a' < 1);
console.log("'1' > 1 t--> ", '1' > 1);
console.log("'1' < 1 t--> ", '1' < 1);
console.log("'+2.9' > 1 t--> ", '+2.9' > 1);
console.log("'+2.9' < 1 t--> ", '+2.9' < 1);
console.log("'2.9' > 1 t--> ", '2.9' > 1);
console.log("'2.9' < 1 t--> ", '2.9' < 1);
console.log("true > 1 t--> ", true > 1);
console.log("false < 1 t--> ", false < 1);
console.log("null > 1 t--> ", null > 1);
console.log("null < 1 t--> ", null < 1);
console.log("undefined > 1 t--> ", undefined > 1);
console.log("undefined < 1 t--> ", undefined < 1);
в консоли будет выведено:
'a' > 'b' --> false
'a' < 'b' --> true
'a' > 1 --> false
'a' < 1 --> false
'1' > 1 --> false
'1' < 1 --> false
'+2.9' > 1 --> true
'+2.9' < 1 --> false
'2.9' > 1 --> true
'2.9' < 1 --> false
true > 1 --> false
false < 1 --> true
null > 1 --> false
null < 1 --> true
undefined > 1 --> false
undefined < 1 --> false
Как работает Lua при сравнении
Lua разрешает сравнивать только числа с числами, строки со строками. В противном случае выкидывает ошибку вида: attempt to compare number with string. Даже boolean сравнить с числом не выйдет, boolean с boolean сравнить тоже не выйдет. Вместо null в Lua используется nil. nil сравнить с числом не получится, nil c nil аналогично.
В общем на Lua тестирование как таковое провалилось по данному вопросу.
Как работает ObjectScript при сравнении
Если один из аргументов сравнения — строка, то происходит строковое сравнение. В противном случае (если аргументы — примитивные типы), то они конвертятся в числа и происходит математическое сравнение. null преобразуется в 0, true в 1, false в 0, строка полностью преобразуется в число, если в строке есть не валидные символы, то возвращается 0.
В итоге код на OS:
print("'a' > 'b' t--> ", 'a' > 'b')
print("'a' < 'b' t--> ", 'a' < 'b')
print("'a' > 1 t--> ", 'a' > 1)
print("'a' < 1 t--> ", 'a' < 1)
print("'1' > 1 t--> ", '1' > 1)
print("'1' < 1 t--> ", '1' < 1)
print("'+2.9' > 1 t--> ", '+2.9' > 1)
print("'+2.9' < 1 t--> ", '+2.9' < 1)
print("'2.9' > 1 t--> ", '2.9' > 1)
print("'2.9' < 1 t--> ", '2.9' < 1)
print("true > 1 t--> ", true > 1)
print("false < 1 t--> ", false < 1)
print("null > 1 t--> ", null > 1)
print("null < 1 t--> ", null < 1)
выведет следующее:
'a' > 'b' --> false
'a' < 'b' --> true
'a' > 1 --> true
'a' < 1 --> false
'1' > 1 --> false
'1' < 1 --> false
'+2.9' > 1 --> false
'+2.9' < 1 --> true
'2.9' > 1 --> true
'2.9' < 1 --> false
true > 1 --> false
false < 1 --> true
null > 1 --> false
null < 1 --> true
Итого
Сведем полученные результаты в одну таблицу:
Вопрос знатокам
Так какое поведение при сравнении следует считать эталонным для скриптового языка программирования и закрепить в спецификации ObjectScript?
Высказывайтесь пожалуйста в комментариях, т.к. уверен, что каждый голос будет на счету и возможно именно ваше слово будет решающим в выборе дальнейшего пути развития ObjectScript.
Другие релевантные статьи об ObjectScript:
- ObjectScript API, интеграция с C++. Часть 4: подключение пользовательских классов и функций на C++
- ObjectScript API, интеграция с C++. Часть 3: подключение модуля с функциями на C++
- ObjectScript API, интеграция с C++. Часть 2: выполнение скрипта на OS из C++
- ObjectScript API, интеграция с C++. Часть 1: работа со стеком, вызов функций OS из C++
- ObjectScript — новый язык программирования, быстрее чем PHP и JS
- ObjectScript — новый язык программирования
Автор: evgeniyup