Итоговая таблица для тех кто не хочет много читать | |||
Результат | Ошибка компиляции | False | True |
Языки | C++ Pascal FORTRAN-95 Java C# Go Rust Haskel |
C Lisp Python Lua Ruby |
JavaScript PHP Perl |
Компилятор C выдаёт предупреждение, компилятор C++ ошибку которая превращается в предупреждение если указать флаг -fpermissive.
Под катом для каждого из языков приведена строчка кода, вызвавшая тот или иной результат, с небольшим комментарием.
Бонусом — функции вывода на консоль для этих языков.
Ошибка компиляции
Самый простое и неинтересное поведение — это ошибка компиляции, происходит во всех строго типизированных языках.
C++
cout << (2 + 2 == "4") << endl;
error: ISO C++ forbids comparison between pointer and integer [-fpermissive]
Если указать флаг -fpermissive то произойдёт сравнение указателя на строку и числа 4 которое скорее всего вернёт 0.
Pascal
writeln((2 + 2) = "4");
Fatal: illegal character "'"'" ($22)
Сообщение об ошибке довольно непонятное
writeln(2 + 2 = '4');
Error: Incompatible types: got «Char» expected «Int64»
Сообщение об ошибке стало вполне понятным. Спасибо GebekovAS.
FORTRAN-95
Print *, 2 + 2 == "4"
Error: Operands of comparison operator '==' at (1) are INTEGER(4)/CHARACTER(1)
Забавно что в этом тексте нет собственно сообщения о том, что сравнение невозможно, просто констатация факта.
Java
System.out.println((2 + 2) == "4");
error: incomparable types: int and String
В сообщение об ошибке всё хорошо кроме того, что не указана какая операция вызвала ошибку.
C#
Console.WriteLine((2 + 2) == "4");
error CS0019: Operator `==' cannot be applied to operands of type `int' and `string'
Тут всё хорошо.
Go
fmt.Printf(2 + 2 == "4")
cannot convert «4» to type int
invalid operation: «4» == 2 + 2 (mismatched types string and int)
А тут еще лучше
Rust
println!("{:?}", 2 + 2 == "4");
error: the trait `core::cmp::PartialEq<&str>` is not implemented for the type `_` [E0277]
Логичное, но честно говоря далеко не самое понятное сообщение об ошибке
Haskel
main = putStrLn (show ((2 + 2) == "4"))
No instance for (Num Char) arising from a use of `+'
Сперва я не понял сообщение, потом немного подумал и понял. Но стал понимать Haskel еще меньше чем раньше.
Решение от Sirikid если всё таки очень хочется сравнить ideone.com/CJifV3
Результат False
Следующие на очереди языки которые позволяют сравнивать число и строку, при этом возвращая false (или что-то похожее), скорее всего из-за несовпадения типов переменных.
C
printf("%i\n",(2 + 2 == "4"));
результат — 0. Сравнение указателя на строку и числа 4 скорее всего вернёт 0. При этом выводится предупреждение, почти такое же как в C++:
warning: comparison between pointer and integer [enabled by default]
Lisp
(write (eq "123" 123))
результат — NIL
Python
print (2 + 2 == "4")
результат — False
Lua
print(2 + 2 == "4")
результат — false
Ruby
puts 2 + 2 == "4";
результат — false
1С
2+2=«4»
False
Спасибо, ACPrikh. «Адинэснеги встали в ряд гуру C Lisp Python Lua Ruby.»
Результат True
И наконец языки которые вернут true для сравнения.
JavaScript
console.log(2 + 2 == "4");
К счастью есть операция строгого сравнения (тройное равенство ===), которая вернёт false
PHP
echo (2 + 2 == "4");
Так же, как и в JavaScript есть операция тройное равенство, результатом которой будет FALSE, что при выводе на консоль выглядит как пустая строка (если я что-то путаю поправьте меня).те меня).
Perl
print 2 + 2 == "4";
Операции строгого сравнения нет, кроме того для шестнадцатеричной записи (а почему бы и нет)
print 0x2 + 0x2 == "0x4";
Perl интерпретирует строку «0x4» как 0 (в отличие от JavaScript и PHP, которые разбирают шестнадцатеричные строки) и вернёт FALSE, при выводе на консоль так же будет пустая строка.
REXX
say 2+2="4"
true
Спасибо, impetus. «При дефолтных ключах/настройках, что документировано и для этого языка логично и ожидаемо.»
Tcl
puts [expr { 2 + 2 == "4" }]
true
Спасибо Chpock, «every value is a string».
Есть ли еще языки с необычным поведением при сравнении числа со строкой, я пока не знаю.
Для изучения вопроса использовался сайт, используемые версии компиляторов и интерпретаторов соответствуют предоставленным на сайте.
UPDATE
Исправил досадную ошибку с паскалем, спасибо указавшим. И добавил примеры из комментариев.
Комментарии (83)
alex_ter
04.06.2017 16:00+2Pascal
В паскале вместо двойных кавычек нужно использовать одинарные.
writeln((2 + 2) = «4»);
Fatal: illegal character "'"'" ($22)
Сообщение об ошибке довольно непонятное
Mutineer
04.06.2017 16:04+14error: incomparable types: int and String
В сообщение об ошибке всё хорошо кроме того, что не указана какая операция вызвала ошибку.
Как не указано? Incomparable же
iSage
04.06.2017 16:11+4error: incomparable types: int and String
В сообщение об ошибке всё хорошо кроме того, что не указана какая операция вызвала ошибку.
Очевидно же, что incomparable может возникнуть только в результате compare — т.е. сравнения.
impwx
04.06.2017 16:47+12Автор открыл для себя сильную и слабую виды типизации.
MaM
05.06.2017 00:05-13Автор фигней какой-то помаялся, недавно пациента видел который учиться в Израиле, и думает, что static инициализируется каждый раз при обращении, в подкасте РадиоТ о перформансе чет говорят и то, что надо закидывать железом и писать на питоне норм, программисты дорогое удовольствие и тд и тп Боже как же я стал ненавидеть этих ваших хипстеров программистов заполонивших отрасль. Строгая статическая для них не удобная, все знают, что динамическая лучше и конечно же 2+2 = «4» должно быть true, а язык Си — синтаксис которого учиться за две недели для них сложен и вообще. Я даже щупая перегруженный swift везде явно типы писал ибо удобно и почему нет. Я раньше не понимал, тех кто гонит программистов-гребцов на галеры, ан нет теперь понимаю, пуст давятся в этих ваших офисах, у меня все пусть ненависть наполнит ваши глаза.
vlreshet
05.06.2017 10:02+2а язык Си — синтаксис которого учиться за две недели
О боже! Автор книги «С++ за 21 день» — это вы?impwx
05.06.2017 10:32+4Справедливости ради, именно синтаксис нового языка можно выучить и быстрее, если до этого уже на чем-то писал. А вот научиться программировать с нуля — согласен, невозможно.
vlreshet
05.06.2017 10:45-1Да в си и с синтаксисом беда. Он очень перегружен, куча разных конструкций, операторов, разных смыслов в зависимости от конструкции. Если под «выучить» имеется ввиду уровень универской лабораторной — тогда да. А если имеется в виду адекватный уровень — то я не уверен что для си хватит 2 недели.
OnYourLips
05.06.2017 10:53+6Вы ничего не путаете? Синтаксис языка C примитивен по сравнению с другими популярными языками.
Какие конструкции и операторы вы имеете ввиду?Eldhenn
05.06.2017 11:05+1int (*(*(*f3)(int))(double))(float);
impwx
05.06.2017 12:02Синтаксис
typedef
на удивление запутанный, но легко запомнить правило «из центра по спирали».
Кстати. кто-нибудь из знающих людей может объяснить, почему при создании алиаса для массива типа X скобки ставятся около нового типа?
typedef int arr[]; // так положено typedef int[] arr; // но почему не так?
mayorovp
05.06.2017 13:12+3Потому что синтаксис typedef повторяет синтаксис объявления переменных.
Тут надо спрашивать почему объявления переменных сделаны настолько нелогично. Видимо, когда-то давно считалось, что массив — это не отдельный тип данных, а модификатор переменной.
impwx
05.06.2017 13:47Спасибо! Теперь всё встало на свои места. Легко поверить, что во времена первого C, когда повсеместно использовалась адресная арифметика, было так: тип задает размер указателя, а сколько там элементов подряд идет — один или несколько — это уже модификатор переменной.
iCpu
06.06.2017 09:47Справедливости ради, 90% задач не требуют таких монструозных конструкций, да и C99 позволяет писать вместо этой вакхвнвлии
А это старый стандарт.typedef int (*f1)(float); typedef f1 (*f2)(double); typedef f2 (*f3)(float);
vlreshet
05.06.2017 11:50-2Разнообразные "*&><^" во всех возможных местах. Или я путаю с С++? Если да — то пардон, посыпаю голову пеплом
PavelZhigulin
05.06.2017 20:30Самое смешное, что если убрать взятие адреса и разыменование указателя, эти же символы употребляются в тех же самых контекстах, что и в остальных С-подобных языках.
Chpock
04.06.2017 17:24tcl — 1 (то бишь true)
% puts [expr { 2 + 2 == "4" }]
1
%
что логично — «every value is a string»
Sirikid
04.06.2017 17:44+6Pascal
Одинарные кавычки fpc, одинарные кавычки gpc, двойные кавычки gpc.
Рано вы остановились, вообще у распространенных компиляторов Паскаля свои диалекты и немного некорректно на основании ошибки одного компилятора делать выводы о всех.
Go
Вместо
fmt.Printf
должен бытьfmt.Print
, или вы забыли форматную строку.
Rust
Скорее всего вы использовали старую версию компилятора, в последнем stable нормальное сообщение. А если явно указать тип, ошибка будет уже другая.
Haskell
Это магия числовых литералов :^) Если явно указать их тип, будет уже конкретная ошибка несоответствия типов оператора сравнения.
Lisp
А какой это Lisp? В Common Lisp, например,
eq
это самое строгое равенство.Sirikid
04.06.2017 19:35Придумал более интересный инстанс https://ideone.com/CJifV3
igormich88
05.06.2017 19:54То есть можно добавить новую операцию сложения, которая внутри себя преобразует результат обычного сложения в строку — здорово! Надо будет почитать про Haskell, хотя бы для общего развития.
А компиляторы/интерпретаторы я использовал какие были на сайте — ставить на рабочий комп такой зоопарк как то не очень хочется.
sun-sapient
05.06.2017 19:33Lisp:
не важно какой лисп, разные типы
N> (class-of "123") #<BUILT-IN-CLASS SB-KERNEL:SIMPLE-CHARACTER-STRING> N> (class-of 123) #<BUILT-IN-CLASS COMMON-LISP:FIXNUM>
MrSelfDestruct
04.06.2017 18:23-12Для python сравниваются разные типы данных
print (2 + 2 == 4)
В Вашем случае будет False, поскольку правая часть выражения является str, а левая int.
Правильней вот так:
print (2 + 2 == 4)
splav_asv
04.06.2017 19:17+4Так в этом и суть(сравнение результата арифметического выражения со строковым представлением правильного результата), или я что-то не понимаю?
gro
04.06.2017 20:13>Perl интерпретирует строку «0x4» как 0
Вообще любую строку или только строковые литералы?cynovg
04.06.2017 21:14Если отключить warnings, то при попытке использовать сложение (а не конкатенацию) Perl попытается привести строку к числу. Для этого он начнет анализировать строку слева на право и отбросит всё, начиная с первого символа, отличного от числа. Всё, что останется — будет интерпретировано, как число.
Если включить режим предупреждений, то будет выведено предупреждение: Argument «0x4» isn't numeric in addition (+).
cynovg
04.06.2017 21:25Perl приводить 0x2 к строке (что при использовании прагмы warnings вернет предупреждение) по тому, что происходит сравнение с строкой, если производить сравнение с числом, всё будет тип-топ. На пример:
print 0x2 + 0x2 == 0x4;
вернет 1
impetus
04.06.2017 22:10язык REXX (regina) — true оба варианта: и 2+2='4' и
2+2="4"
(при дефолтных ключах/настройках ), что документировано и для этого языка логично и ожидаемо.
oleg_gf
04.06.2017 22:50-7В общем, самый осмысленный результат выдают JS и PHP.
denis-isaev
05.06.2017 01:17+4Антропный коммент кодера на js и php? :)
oleg_gf
06.06.2017 09:03-2Если бы я ещё был кодером… ))
Если просто здраво рассудить с точки зрения пользователя, то сравнение 2 + 2 = «4» должно выдавать либо истину, либо ложь, в зависимости от точности запроса. С этой точки зрения самый осмысленный результат выдают JS и PHP.cynovg
06.06.2017 09:22+1Не пользователя, а программиста, наверное. А вот с моей точки зрения — тут явная ошибка, на которую как минимум надо выводить предупреждение. Иначе, это ещё один способ отстрелить себе ногу.
Ниже, кстати, приводится поведение того же JS в более сложных случаях, и это поведение — следствие той «магии», которая пытается исправить ошибку.
lagranzh
05.06.2017 02:12+3В C и C++ теоретически может вернуться тру, если строка "4" случайно окажется расположеной по адресу 4.
я так думаю.Eldhenn
05.06.2017 11:250x00F Ever change the value of 4?
0x010… Unintentionally?
0x011… In a language other than Fortran?
LmTinyToon
05.06.2017 18:23Зависит от окружения, если не ошибаюсь, windows например резервирует начальные адреса для отладки, поэтому под ней строка никогда не окажется по адресу 4
Tujh
06.06.2017 09:37Не для отладки, туда загружаются системные библиотеки если я не путаю и память помечается защищённой от записи.
LmTinyToon
06.06.2017 11:57+2Мои знания могут быть устаревшими (читал книгу по Рихтеру — на тот момент Windows 2000/98). В тех версиях windows (думаю на данный момент ничего не изменилось) — существовал раздел адресного пространства для выявления нулевых указателей (занимал первые 0xFFFF байт для 32/64 битных версий). Любая попытка чтения/записи из данного раздела запрещена.
Tujh
06.06.2017 12:47Да, я забыл про первые 64к и нет, ваши знания не устарели и всё так и осталось :)
Error1024
05.06.2017 02:35Pascal
writeln((2 + 2) = «4»);
Fatal: illegal character "'"'" ($22)
Сообщение об ошибке довольно непонятное
Глупая статья
keydon2
05.06.2017 04:12Статья больше интересна по теме «как компилятор\интерпретатор пишут об ошибках».
По многим сообщениям действительно не сразу понимаешь что именно нужно исправить.
Это серьезное упущение, учитывая, что обычно их допускают новички и для них интерпретация ошибок в новых языках дело затратное и негативно сказывается на обучении, да и опытным программистам приходится часто их видеть.
shushu
05.06.2017 08:05+1В перл сравнения со строками надо делать оператором eq
print 2+2 eq "4" ? "TRUE" : "FALSE"; # > TRUE
igormich88
05.06.2017 19:44Так ведь результат в данном случае будет тот же, что строку приводить к числу, что число к строке.
cynovg
05.06.2017 21:55Не совсем. В первом случае строка приводится к числу, во втором — число к строке. Приведу пример, для наглядности:
#!/usr/bin/env perl use warnings; print 2 + 2 == "4a"; print 2 + 2 eq "4a";
В первом сравнении будет выведена предупреждение «Argument „4a“ isn't numeric in numeric eq (==)», но результат сравнения будет положительным (почему — см. мой комментарий выше). Во-втором случае будет просто false и всё.
chemistmail
05.06.2017 08:21-7Да уж. Исследование.
haskell:
? print $ show $ 2 + 2 == 4
«True»
А в вашем примере вы сравнили 2+2 :: Int
c «4» :: String
И получили ошибку сравнения теплого с мягким. О чем компилятор честно и сказал.Sirikid
05.06.2017 08:42+1Во-первых, суть была именно в этом. Во-вторых, компилятор сказал совершенно о другом.
RogueShy
05.06.2017 10:18Powershell:
echo (2+2 -eq "4")
TrueТо же для одинарных кавычек.
Однако,
"4" -is [string]
TrueА если
[int]$a = 2 + 2
[char]$b = "4"
echo ($a -eq $b)
Falsemayorovp
05.06.2017 10:39-1При чем тут вообще char? Тут же во всех языках со строками сравнивают, а не с символами.
Tujh
05.06.2017 12:44-2В С/С++ нет понятия строк в синтаксисе языка, они слишком низкоуровневые для этого. В «С» есть только массив чаров, а в «С++» шаблон стандартной библиотеки являющийся контейнером для некоторого типа данных (чары или «широкие чары») и позволяющий выполнять операции конкатенации и т.п. над последовательностью данных, но это не встроенный тип и более того, можно написать свои собственные «строки» работающие с utf8, к примеру.
mayorovp
05.06.2017 13:14В Си/С++ строкой является любой массив байт или указатель на первый элемент такого массива.
Tujh
05.06.2017 13:48-1То есть int string[10] — тоже строка? Массив байт же.
И это… как бы процитируйте пункт стандарта языка «С» который бы подтвердил Ваши слова.
Я могу процитировать учебник по Си, если Вам интересно:
Язык Си не поддерживает отдельный строковый тип данных, но он позволяет определить строки двумя различными способами. В первом используется массив символов, а во втором — указатель на первый символ массива.
Определение char а[10]; указывает компилятору на необходимость резервирования места для максимум 10 символов. Константа а содержит адрес ячейки памяти, в которой помещено значение первого из десяти объектов типа char.mayorovp
05.06.2017 13:49Ну оговорился я. Символов, конечно же, не байт. Хоть это и "почти синонимы".
Mutineer
05.06.2017 19:26+1Ну как сказать
— указатель на массив из двух char"4"
— одиночный char'4'
Типа может и нет, а разница при записи литерала есть
hamnsk
05.06.2017 11:57Интересное исследование, сравнить результат сложения двух чисел со строкой. А сразу как бы не понятно что для языков со строгой типизацией результат будет либо ошибкой либо false.
GebekovAS
05.06.2017 13:22+1Pascal:
begin
writeln(2+2='4');
end.
Результат:
source.pas(6,17) Error: Incompatible types: got «Char» expected «Int64»
source.pas(8) Fatal: There were 1 errors compiling module, stopping
p.s. для протоколаGebekovAS
05.06.2017 13:29Кстати, попробовал на стареньком компиляторе TBPascal, вернул:
Error: no common type between integer and string ("=", line 4)GebekovAS
05.06.2017 21:20Первый мой коммент был верен для Free Pascal версии 3.0.0 и выше версии, а вот скрин результата Borland Pascal v7 (классика):
p.s. теперь думаю ответ можно считать исчерпывающим=) спасибо автору за nostalgie
vladbarcelo
05.06.2017 16:412 + 2 = «4» это ещё шуточки для JS:
> '5' - 3 2
Отнимаем int от строки, получаем int. А если наоборот?
> '5' + 3 '53'
А если наоборот, то получаем конкатенацию в строку. Неплохо, правда? Ну хорошо, а если от строки отнять строку?
> '5' - '4' 1
… получаем int!
Ещё немного магии. Строка плюс плюс строка:
> '5' + + '5' '55'
Конкатенация, вроде всё понятно. Ну-ка ещё раз:
> 'foo' + + 'foo' 'fooNaN'
О как!
Ещё JS забавно воспринимает знаки математических действий:
> '5' + - '2' '5-2' > '5' + - + - - + - - + + - + - + - + - - - '2' '52'
И, напоследок, немного javascript-алгебры:
> var x = 3; > '5' + x - x 50 > '5' - x + x 5
teh end.
Нет, это всё, разумеется, элементарно объясняетсяно понять новичку что такое weak typing + implicit conversions, и почему вообще это всё так работает — это целое удивительное путешествие, ЕВПОЧЯ.
saw-friendship
05.06.2017 19:07-2Вот совсем неудивительно что в языках со строгой типизацией это не канает. Интереснее было бы, еслиб вы сравнили это выражение без заключения четверки в кавычки.
В каких языках 2 + 2 == 4 будет ложным?
elnardu
05.06.2017 19:31-1В паскале строки заключаются в ' '.
writeln((2 + 2) = '4');
Error: Incompatible types: got «Char» expected «Int64»
chv
05.06.2017 19:31-2Вообще-то в Паскале строки заключаеются в одинарные кавычки. И сообщение об ошибке там вполне понятное.
Shtucer
Вполне понятное. Заключите строку в одинарные кавычки.