Здравствуйте, Ka3a4oK, Вы писали:
M>>Люди саркастически издеваются над нашими любимыми языками программирования: M>>https://www.destroyallsoftware.com/talks/wat KK>Кто на C++ писал, тот в цирке не смеется.
По сравнению с JS — С++ это малый ребёнок.
Здравствуйте, VladD2, Вы писали:
C>>С отладчиком AV — это не проблема. Корки даже удобнее stacktrace'ов. VD>Эту сказку ты рассказывай тем, кто не ловил блуждающих AV, которые являлись ошибкой третьего порядка.
Эту сказку ты рассказывай тем, кто не ловил блуждающих NPE, которые являлись ошибкой третьего порядка от инструментации байт-кода.
Везде свои сложности.
C>>Речь про другое — сам С++ хотя и переусложнён, но WTF'ов типа "{}+[]" в нём меньше. VD>Бесспорно, недоязыки вроде жабаскрипа имеют феерическую семантику в некоторых вопросах. Но плюсы от них не так уж и далеко ушли. В них тоже приколов хватает. И это при том что есть туча языков в которых подобных приколов нет.
В С++ большая часть вещей вполне логична, если понимать причины, по которым оно так получилось. Оно всё переусложнено, но логично.
.>По-моему вполне логично и ожидаемо. Вот спека, где написано как оно должно работать, так оно и работает. .>Что я делаю не так?
В-нулевых, ты оффтопишь.
Во-первых, не так то, что ты пытаешься разобраться в сортах, ибо в ролике показан принцип "shit in, shit out" в действии. Даже если предположить, что в ролике действительно складывается массив и хеш-таблицей (что не так), то название персонажу, ожидающему осмысленного результата, придумай сам.
Во-вторых, сделай {}+[] в JavaScript/Error Console в том же фаерфоксе (Ctrl+Shift+J).
Вопрос: какого х?
Ответ: потому что {} парсится как блок (в смысле блок операторов типа if(...){вот такой}), за которым идет выражение +[] (унарный плюс), которое и возвращает "0". Подробности — после рекламы небольшого лирического отступления, оно же — в-третьих. А в вызове функции (например, document.write) {}+[] парсится как бинарный оператор +. Для консоли/eval можно короче: ({}+[]).
Отступление.
Встречаются два еврея.
— Ой, Ося! Не пойму, чего это все тащатся от этого Шаляпина? Фальшивит, шепелявит, в такт не попадает!
— А ты слышал Шаляпина?
— Да мне Рабинович напел.
Или как-то так. Так вот, в-третьих, ты вместо пары страниц спеки, в которой пошагово расписан алгоритм работы оператора +, читаешь какие-то левые мега-простыни, которые в лучшем случае тупо перескажут спеку своими словами (не факт, что не корявыми) и "добавят воды" (тм). В худшем же, они еще и содержат откровенное гонево:
only if both operands are numbers to start with will the + operator perform addition. Otherwise it converts all of its operands to strings and does concatenation.
var a = 100; // вот это - number.
var b = {valueOf:function(){return 42;}}; // а это - не number, а object с переопределенным методом valueOf.
a + b; // а это - "сюрпрайз".
11.6.1 The Addition operator ( + )
The addition operator either performs string concatenation or numeric addition.
The production AdditiveExpression : AdditiveExpression + MultiplicativeExpression is evaluated as follows:
1. Evaluate AdditiveExpression.
2. Call GetValue(Result(1)).
3. Evaluate MultiplicativeExpression.
4. Call GetValue(Result(3)).
5. Call ToPrimitive(Result(2)).
6. Call ToPrimitive(Result(4)).
7. If Type(Result(5)) is String or Type(Result(6)) is String, go to step 12. (Note that this step differs from step 3 in
the comparison algorithm for the relational operators, by using or instead of and.)
8. Call ToNumber(Result(5)).
9. Call ToNumber(Result(6)).
10. Apply the addition operation to Result(8) and Result(9). See the note below (section 11.6.3).
11. Return Result(10).
12. Call ToString(Result(5)).
13. Call ToString(Result(6)).
14. Concatenate Result(12) followed by Result(13).
15. Return Result(14).
NOTE No hint is provided in the calls to ToPrimitive in steps 5 and 6. All native ECMAScript objects except Date objects handle
the absence of a hint as if the hint Number were given; Date objects handle the absence of a hint as if the hint String were given.
Host objects may handle the absence of a hint in some other manner.
По шагам, для твоего теста с {}+[]:
1. {} // объект
2. {} // он же
3. [] // массив
4. [] // он же
5. ToPrimitive(Result(2))
1) вызываем {}.[[DefaultValue]](hint Number)
1) вызываем {}.valueOf(), умолчальная реализация которого
возвращает this (в классе Date он переопределен и возвращает
unix timestamp в миллисекундах), который не является primitive
value (это undefined, null, true, false, числовой или строковый
литерал), поэтому
2) вызываем {}.toString(), который возвращает строковый литерал
"[object Object]", который, хвала богам, является primitive value.
Иначе пришлось бы бросать исключение. Для демонстрации измени b
из сюрпрайза: var b = {toString:function(){return this/*например*/;}}
Итого, Result(5) = "[object Object]".
6. ToPrimitive(Result(4))
... ровно то же самое, с той лишь разницей, что [].toString()
(Array.prototype.toString) возвращает this.join().
Итого, Result(6) = "".
7. Переходим в шаги 12-15, где просто конкатенируем Result(5) и Result(6),
и возвращаем результат: "[object Object]".
Теперь, когда у нас есть спека и вагон времени, которому мы не нашли лучшего применения, вернемся к "во-вторых" и посмотрим, что происходит с выражением +[]:
+[]:
1. ToNumber([])
= ToPrimitive([], hint Number)
= "" (Result(6) выше)
2. ToNumber(Result(1)) = ToNumber("")
= 0 // Из "9.3.1 ToNumber Applied to the String Type":
// A StringNumericLiteral that is empty or contains
// only white space is converted to +0.
Здравствуйте, VladD2, Вы писали:
C>>По сравнению с JS — С++ это малый ребёнок. VD>Ну, да в нем все предсказуемо — AV. Как говорится — семь бед, одни резет.
С отладчиком AV — это не проблема. Корки даже удобнее stacktrace'ов.
Речь про другое — сам С++ хотя и переусложнён, но WTF'ов типа "{}+[]" в нём меньше.
Здравствуйте, dimgel, Вы писали:
D>Т.е. к статике идиотские спецификации почему-то в разы сложнее прикрутить. Вот есть перегруженный оператор — известно, на каких классах он перегружен и как. Жёстко и предсказуемо. Так что сдаётся мне, статика/динамика и сильная/слабая — вещи далеко не ортогональные.
Вот найдется идиот который в черт знает каком вложенном инклюде переопределит оператор, и будут всех офигивать от интуитивности поведения.
Да что там оператор? С++ под час невинная опечатка превращается в выдачу моря сообщений об ошибках и все не в том месте где ошибка. А динамики никакой нет.
ЗЫ
Я тоже люблю статику. Но совсем за другое. За возможность статической проверки контрактов и за качественные средства рефакторинга.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Mamut, Вы писали:
M>В данном конекретном случае проблема не совсем в динамике, а в слабой типизации и идиотских спецификациях
Да про слабую типизацию я помню, ты же мне и объяснял. Но только мне от этих слов не сильно приятнее: слабый js или сильный, а всё одно говно, от которого не уйти.
Короче говоря, это всё теория. А практика такова, что динамику я ненавижу.
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, dimgel, Вы писали:
DR>>>Ты забываешь о шаблонах С++.
D>>разворачиваются без контроля типизатора.
J>Это что тут имеется в виду?
Что такое шаблон? Фактически, шаблон — это программа, которая генерит код. Так вот, эта программа — динамически типизирована. так же как например программа на питоне, руби и тд. То есть ошибки типизации в ней проявятся в момент ВЫПОЛНЕНИЯ этой программы.
Заметь, он сказал не "С++ динамически типизирован", а "в С++ типы динамически типизированы". Это разные вещи. Он говорил о времени компиляции. О том, что как и в динамических языках при типизации шаблонов типы не известны до момента их воплощения.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Don Reba, Вы писали:
DR>Здравствуйте, dimgel, Вы писали:
D>>О, тут самое время засуммонить WolfHound-а, который впрочем уже наверное задолбался всем по сто раз рассказывать, что метапрограммирование и статика/динамика — вещи ортогональные.
DR>В том то и дело, что ортогональные. Благодаря этому, того замечательного мира, что ты описываешь в статических языках не существует. В С++ приходится иметь дело с шаблонами, в Яве/Шарпе с интроспекцией, в Немерле с полноценным метапрограммированием. Жёстко и предсказуемо всё только в Паскале.
Здравствуйте, dimgel, Вы писали:
D>А касательно шаблонов C++ — кажется он же с год назад в каком-то флейме (помню, там ещё был adontz) утверждал, что они — динамика, т.к. разворачиваются без контроля типизатора.
Думаю ты что-то путаешь. То что они разворачиваются без контроля типизации не значит, что они динамика. Но проблем это, несомненно, добавляет.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Возможно, там имелось в виду нечто немного иное.
VD>Заметь, он сказал не "С++ динамически типизирован", а "в С++ типы динамически типизированы". Это разные вещи.
Здравствуйте, мыщъх, Вы писали:
М>вы неправильно пробовали. возьмите в руки шелл. хоть ff, хоть от хрома. а еще можно покурить ECMAScripting. покажите мне место стандарта по которому должно быть иначе -- я тогда сильно удивлюсь, поскольку, реализацию js движка писал сам и угадал правильные ответы во всех случаях, т.к. оно очевидно. если интересно могу объяснить почему, но это ж тривиально. подумайте головой и все станет ясно.
О, мне теперь ясно! Такая фигня в джаваскрипте, потому что его движки пишут такие укурки!
Здравствуйте, dimgel, Вы писали:
D>Короче говоря, это всё теория. А практика такова, что динамику я ненавижу.
Т.е. к статике идиотские спецификации почему-то в разы сложнее прикрутить. Вот есть перегруженный оператор — известно, на каких классах он перегружен и как. Жёстко и предсказуемо. Так что сдаётся мне, статика/динамика и сильная/слабая — вещи далеко не ортогональные.
D>>Короче говоря, это всё теория. А практика такова, что динамику я ненавижу.
D>Т.е. к статике идиотские спецификации почему-то в разы сложнее прикрутить.
Да ладно Сколько там IB и UB в стандарте С++?
D>Вот есть перегруженный оператор — известно, на каких классах он перегружен и как. Жёстко и предсказуемо. Так что сдаётся мне, статика/динамика и сильная/слабая — вещи далеко не ортогональные.
Здравствуйте, dimgel, Вы писали:
D>Т.е. к статике идиотские спецификации почему-то в разы сложнее прикрутить. Вот есть перегруженный оператор — известно, на каких классах он перегружен и как. Жёстко и предсказуемо. Так что сдаётся мне, статика/динамика и сильная/слабая — вещи далеко не ортогональные.
Ты забываешь о шаблонах С++. А в других статических языках есть и более мощные средства метапрограммирования.
Здравствуйте, Don Reba, Вы писали:
DR>Ты забываешь о шаблонах С++. А в других статических языках есть и более мощные средства метапрограммирования.
О, тут самое время засуммонить WolfHound-а, который впрочем уже наверное задолбался всем по сто раз рассказывать, что метапрограммирование и статика/динамика — вещи ортогональные. А касательно шаблонов C++ — кажется он же с год назад в каком-то флейме (помню, там ещё был adontz) утверждал, что они — динамика, т.к. разворачиваются без контроля типизатора.
Здравствуйте, dimgel, Вы писали:
D>О, тут самое время засуммонить WolfHound-а, который впрочем уже наверное задолбался всем по сто раз рассказывать, что метапрограммирование и статика/динамика — вещи ортогональные.
В том то и дело, что ортогональные. Благодаря этому, того замечательного мира, что ты описываешь в статических языках не существует. В С++ приходится иметь дело с шаблонами, в Яве/Шарпе с интроспекцией, в Немерле с полноценным метапрограммированием. Жёстко и предсказуемо всё только в Паскале.
Здравствуйте, Cyberax, Вы писали:
C>С отладчиком AV — это не проблема. Корки даже удобнее stacktrace'ов.
Эту сказку ты рассказывай тем, кто не ловил блуждающих AV, которые являлись ошибкой третьего порядка.
C>Речь про другое — сам С++ хотя и переусложнён, но WTF'ов типа "{}+[]" в нём меньше.
Бесспорно, недоязыки вроде жабаскрипа имеют феерическую семантику в некоторых вопросах. Но плюсы от них не так уж и далеко ушли. В них тоже приколов хватает. И это при том что есть туча языков в которых подобных приколов нет.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Динамика тут не причем. Это называется отсутствие строгой типизации. Скрипты ею страдают чаще только потому, что их авторы пытаются по больше разрешить. Но нет никаких проблем спроектировать скрипт который был бы строго типизирован.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
D>>А касательно шаблонов C++ — кажется он же с год назад в каком-то флейме (помню, там ещё был adontz) утверждал, что они — динамика, т.к. разворачиваются без контроля типизатора.
VD>Думаю ты что-то путаешь. То что они разворачиваются без контроля типизации не значит, что они динамика. Но проблем это, несомненно, добавляет.
Здравствуйте, Mamut, Вы писали:
M> Люди саркастически издеваются над нашими любимыми языками программирования: M> https://www.destroyallsoftware.com/talks/wat
Я может и зануда и вообще оффтопик, но то что он там показывает в js, сложение объектов и массивов — лажа какая-то. Я попробовал в браузерном мозилльном яваскрипте — работает вполне ожидаемо — перед конкатенацией "+" переводит всё в строку, никаких NaN не получается.
Здравствуйте, ., Вы писали:
.>Здравствуйте, Mamut, Вы писали:
M>> Люди саркастически издеваются над нашими любимыми языками программирования: M>> https://www.destroyallsoftware.com/talks/wat .>Я может и зануда и вообще оффтопик, но то что он там показывает в js, сложение объектов и массивов — лажа какая-то. Я попробовал в браузерном мозилльном яваскрипте — работает вполне ожидаемо — перед конкатенацией "+" переводит всё в строку, никаких NaN не получается.
вы неправильно пробовали. возьмите в руки шелл. хоть ff, хоть от хрома. а еще можно покурить ECMAScripting. покажите мне место стандарта по которому должно быть иначе -- я тогда сильно удивлюсь, поскольку, реализацию js движка писал сам и угадал правильные ответы во всех случаях, т.к. оно очевидно. если интересно могу объяснить почему, но это ж тривиально. подумайте головой и все станет ясно.
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
м> вы неправильно пробовали. возьмите в руки шелл. хоть ff, хоть от хрома. а еще можно покурить ECMAScripting. покажите мне место стандарта по которому должно быть иначе -- я тогда сильно удивлюсь, поскольку, реализацию js движка писал сам и угадал правильные ответы во всех случаях, т.к. оно очевидно. если интересно могу объяснить почему, но это ж тривиально. подумайте головой и все станет ясно.
Так я взял! Вот мой файл, в FF9.0.1 и в Chromium 16.0.912.75 выдаёт следующее:
Здравствуйте, zalldone, Вы писали:
z> В-нулевых, ты оффтопишь.
в этом я сразу признался.
z> Во-первых, не так то, что ты пытаешься разобраться в сортах, ибо в ролике показан принцип "shit in, shit out" в действии. Даже если предположить, что в ролике действительно складывается массив и хеш-таблицей (что не так), то название персонажу, ожидающему осмысленного результата, придумай сам.
Это просто демонстрация приведения типов. Почему бы не ожидать.
z> Во-вторых, сделай {}+[] в JavaScript/Error Console в том же фаерфоксе (Ctrl+Shift+J). z> Вопрос: какого х? z> Ответ: потому что {} парсится как блок (в смысле блок операторов типа if(...){вот
Понятно теперь. Просто в ролике говорится что складываются массивы и объекты, т.е. expressions, а на самом деле statements. Вот и сбило с толку.
z> Или как-то так. Так вот, в-третьих, ты вместо пары страниц спеки, в которой пошагово расписан алгоритм работы оператора +, читаешь какие-то левые мега-простыни,
Я это не читал, первая ссылка что нагуглилась.
Здравствуйте, ., Вы писали:
.>Здравствуйте, мыщъх, Вы писали:
.>Что я делаю не так?
вы забыли, что wat-гай демонстрировал все это в шелле. следовательно, нужно смотреть как работает шелл. а шелл делает eval(), в резульате чего {} + {} сильно отличается от eval(_"_ {} + {} _"_);
а вот его результат:
[] + [] is ''
{} + [] is '0'
[] + {} is '[object Object]'
{} + {} is 'NaN'
Array(16) is ',,,,,,,,,,,,,,,'
Array(16).join('KPNC') is 'KPNCKPNCKPNCKPNCKPNCKPNCKPNCKPNCKPNCKPNCKPNCKPNCKPNCKPNCKPNC'
Array(16).join('KPNC' — 1 ) is 'NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN'
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Здравствуйте, мыщъх, Вы писали:
м> вы забыли, что wat-гай демонстрировал все это в шелле. следовательно, нужно смотреть
как работает шелл. а шелл делает eval(), в резульате чего {} + {} сильно
Да, уже понял... Он просто с толку сбил, говорил, что объекты складывает.
м> Array(16).join('KPNC' — 1 ) is 'NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN'
А это не понял что такого — работает вполне логично.
Здравствуйте, ., Вы писали:
.>Здравствуйте, мыщъх, Вы писали:
м>> Array(16).join('KPNC' — 1 ) is 'NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN' .>А это не понял что такого — работает вполне логично.
а вот еще вариация на эту тему:
var e130 = 96
print (eval("69-e13" + eval('{} + []')));
это затрагивает правило парсинга строк и как быть, если строка в стиле '1e3', но у нас уже есть переменная e3.
это такой хакерский способ поставить хук на нужное место по крайней мере некоторые биллинговые системы, написанные на коленке, ему подвержены.
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Здравствуйте, мыщъх, Вы писали:
м> а вот еще вариация на эту тему:
м> var e130 = 96 м> print (eval("69-e13" + eval('{} + []')));
м> это затрагивает правило парсинга строк и как быть, если строка в стиле '1e3', но у нас уже есть переменная e3.
Экспоненциальная запись выглядит как "[+-]\d+e\d+", т.е. "-2e3", а не "2-e3". Совсем разные записи.
м> это такой хакерский способ поставить хук на нужное место по крайней мере некоторые биллинговые системы, написанные на коленке, ему подвержены.
Не понял. Можно подробнее?
Здравствуйте, 0x7be, Вы писали:
0>Здравствуйте, Wolverrum, Вы писали:
VD>>>По ржал до слез. Спасибо, от души. W>>Эдгар?! 0>Шутка не хуже самого видео
ага, я тоже по ржала до слез.
Здравствуйте, Jack128, Вы писали:
DR>>>>Ты забываешь о шаблонах С++.
D>>>разворачиваются без контроля типизатора.
J>>Это что тут имеется в виду?
J>Что такое шаблон? Фактически, шаблон — это программа, которая генерит код. Так вот, эта программа — динамически типизирована. так же как например программа на питоне, руби и тд. То есть ошибки типизации в ней проявятся в момент ВЫПОЛНЕНИЯ этой программы.
сорри, выполнения _какой_ программы? Вроде как компилятора как раз, не? И типизатора внутри него, что бы под ним ни подразумевалось
Указатели к слабой типизации ИМХО отношения не имеют. От того, что я возьму строку и стану рассматривать её как последовательность байт, в памяти эта строка не изменится. А где там неявное приведение типов?
M>>C/C++. В них есть неявное приведение типов и указатели (http://en.wikipedia.org/wiki/Weak_and_Strong_typing)
D>Указатели к слабой типизации ИМХО отношения не имеют. От того, что я возьму строку и стану рассматривать её как последовательность байт, в памяти эта строка не изменится. А где там неявное приведение типов?
Есть как неявное (int -> float) так и явное, что тоже плохо с точки зрения строгости типизации. То есть (AnotherObject*)((void*)Object) прокатит и в С и в С++ на ура безо всякого контроля со стороны компилятора или рантайма.
Указатели позволяют прямую манипуляцию памятью, невзирая на тип объекта.
Здравствуйте, Mamut, Вы писали:
D>>Указатели к слабой типизации ИМХО отношения не имеют. От того, что я возьму строку и стану рассматривать её как последовательность байт, в памяти эта строка не изменится. А где там неявное приведение типов?
M>Есть как неявное (int -> float) так и явное, что тоже плохо с точки зрения строгости типизации.
Точно там неявное int -> float, или имеются в виду лишь правила вывода типа результата арифметических операций (int * float = float)? Последнее имеется чуть менее чем у всех и к слабости типизации операндов не имеет никакого отношения: типы исходных операндов не меняются.
M>То есть (AnotherObject*)((void*)Object) прокатит и в С и в С++ на ура безо всякого контроля со стороны компилятора или рантайма.
Это также ИМХО не катит: на java/scala я могу написать точно такой же левый каст, они от этого не станут слабыми. А то, что этот каст вылетит (точнее, может вылететь) в рантайме — дык это уже динамика, а не статика. А я спрашиваю про слабую статику. Техническая возможность беспредельничать разнообразными способами, форсированно обходя контроль системы типов, не означает отсутствие этого контроля. Грубо говоря, если я получу адрес объекта и тупо забью его мусором через memset(), это как бы к системе типов отношения не имеет.
M>Указатели позволяют прямую манипуляцию памятью, невзирая на тип объекта.
А битовые операции позволяют манипулировать целыми числами как наборами битовых флагов. Не знаю, насколько это формально корректно, может быть я собственную терминологию выдумываю, но если "объект — это область памяти" (с) Буч, то преобразование типов предполагает изменение структуры/содержимого области памяти. В твоих примерах этого нет, есть только семантически-некорректное обращение к неизменной существующей области.
Здравствуйте, dimgel, Вы писали:
D>Здравствуйте, Mamut, Вы писали:
M>>То есть (AnotherObject*)((void*)Object) прокатит и в С и в С++ на ура безо всякого контроля со стороны компилятора или рантайма.
D>Это также ИМХО не катит: на java/scala я могу написать точно такой же левый каст, они от этого не станут слабыми. А то, что этот каст вылетит (точнее, может вылететь) в рантайме — дык это уже динамика, а не статика. А я спрашиваю про слабую статику. Техническая возможность беспредельничать разнообразными способами, форсированно обходя контроль системы типов, не означает отсутствие этого контроля. Грубо говоря, если я получу адрес объекта и тупо забью его мусором через memset(), это как бы к системе типов отношения не имеет.
С чего это не имеет? Если ты берёшь строку, а работаешь в итоге как с числом, то это как раз и есть дыра в типизации -> слабая типизация.
Ещё явной дырой являются сишные объединения (по ср. с ADT из более внятных языков).
Здравствуйте, Курилка, Вы писали:
К>С чего это не имеет? Если ты берёшь строку, а работаешь в итоге как с числом, то это как раз и есть дыра в типизации -> слабая типизация. К>Ещё явной дырой являются сишные объединения (по ср. с ADT из более внятных языков).
Ну с unions вопросов нет. А на счёт взять строку и работать с ней как с числом — таки объясните мне, почему динамический по своей сути рантайм считается частью статически-типизированного языка? Формулировка вопроса именно такова, потому что я могу на любом (известном мне статически-типизированном) языке написать левый каст, и до момента выполнения не узнать о его некорректности; поэтому я рассматриваю такие касты не как часть системы типов, а как хак для её обхода. А то по-вашему выходит, что все языки, где есть операторы приведения типов, слабые.
Здравствуйте, dimgel, Вы писали:
D>Ну с unions вопросов нет.
Хотя в общем тоже не факт. Этот пример из той же серии, что и битовые операции над целым числом: работа с одной и той же областью памяти несколькими альтернативными, но валидными способами. Т.е. если я юзаю union с умом, никакая это не дыра. Ну а если без ума, дык на C++ отстрелить себе ногу можно гораздо проще и безо всяких систем типов — тупо ошибившись на +-1 при проходе по ASCIIZ-строке.
Здравствуйте, dimgel, Вы писали:
D>Ну с unions вопросов нет. А на счёт взять строку и работать с ней как с числом — таки объясните мне, почему динамический по своей сути рантайм считается частью статически-типизированного языка? Формулировка вопроса именно такова, потому что я могу на любом (известном мне статически-типизированном) языке написать левый каст, и до момента выполнения не узнать о его некорректности; поэтому я рассматриваю такие касты не как часть системы типов, а как хак для её обхода. А то по-вашему выходит, что все языки, где есть операторы приведения типов, слабые.
В статически и сильно типизированном языке во время компиляции можно гарантировать, что работа будет вестить только с правильным типом, а в слабо типизированном — нет.
Здравствуйте, Don Reba, Вы писали:
DR>В статически и сильно типизированном языке во время компиляции можно гарантировать, что работа будет вестить только с правильным типом, а в слабо типизированном — нет.
Java и scala — статически и сильно типизированные?
Здравствуйте, dimgel, Вы писали:
D>Здравствуйте, dimgel, Вы писали:
D>>Ну с unions вопросов нет.
D>Хотя в общем тоже не факт. Этот пример из той же серии, что и битовые операции над целым числом: работа с одной и той же областью памяти несколькими альтернативными, но валидными способами. Т.е. если я юзаю union с умом, никакая это не дыра. Ну а если без ума, дык на C++ отстрелить себе ногу можно гораздо проще и безо всяких систем типов — тупо ошибившись на +-1 при проходе по ASCIIZ-строке.
Строгий язык тебе в принципе не позволит что-то заюзать "не с умом".
Например, в строгом языке вот такая фигня будет:
double pow(double);
pow(0.0); // OK
pow(0); // won't compile - 0 is int
что несколько неудобно. Так что у нестрогости есть свои преимущества.
PS никто не мешает пользоваться только строгим подмножеством нестрогого в целом языка, или даже сотворить его своими руками.
Например, вышеприведенную pow можно сделать строгой и в С++:
template<class T>
enable_if< is_same<T, double>, double >
pow( T );
: "В статически и сильно типизированном языке во время компиляции можно гарантировать, что работа будет вестить только с правильным типом". Тем не менее, оно не выполняется. Следующую конструкцию компилятор схавает:
M>Указатели позволяют прямую манипуляцию памятью, невзирая на тип объекта.
Угу.
((void(*)(void))0)();
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Здравствуйте, dimgel, Вы писали:
D>Здравствуйте, Don Reba, Вы писали:
DR>>В статически и сильно типизированном языке во время компиляции можно гарантировать, что работа будет вестить только с правильным типом, а в слабо типизированном — нет.
D>Java и scala — статически и сильно типизированные?
M>>То есть (AnotherObject*)((void*)Object) прокатит и в С и в С++ на ура безо всякого контроля со стороны компилятора или рантайма.
D>Это также ИМХО не катит: на java/scala я могу написать точно такой же левый каст, они от этого не станут слабыми. А то, что этот каст вылетит (точнее, может вылететь) в рантайме — дык это уже динамика, а не статика. А я спрашиваю про слабую статику. Техническая возможность беспредельничать разнообразными способами, форсированно обходя контроль системы типов, не означает отсутствие этого контроля. Грубо говоря, если я получу адрес объекта и тупо забью его мусором через memset(), это как бы к системе типов отношения не имеет.
Ага, тока в жабе компилер не пропустит. И даже если ручками в байткоде написать — виртуалка не пропустит, обложили, демоны. А мемсета нету.
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Здравствуйте, jazzer, Вы писали:
J>Строгий язык тебе в принципе не позволит что-то заюзать "не с умом". J>Например, в строгом языке вот такая фигня будет: J>
J>double pow(double);
J>pow(0.0); // OK
J>pow(0); // won't compile - 0 is int
J>
J>что несколько неудобно. Так что у нестрогости есть свои преимущества.
: "В статически и сильно типизированном языке во время компиляции можно гарантировать, что работа будет вестить только с правильным типом". Тем не менее, оно не выполняется. Следующую конструкцию компилятор схавает: D>
D>var s = "hello"
D>var i = s.asInstanceOf[Int]
D>
Несмотря на приведение типа, у компилятора остаётся гарантия, что если типы не совместимы, то во время исполнения будет выброшено исключение. В С++ подобной гарантии нет; в любом месте пользователь может написать *(*double)2501 = PI. Поэтому, в С++ более слабая типизация.
Здравствуйте, Eugeny__, Вы писали:
E__>Ага, тока в жабе компилер не пропустит.
Пропустит. Может, не буквально это, но фигню посложнее, подобную очччень часто встречающуюся вот такому безобразию, пропустит на ура (пишу в псевдокоде, ближе к scala, т.к. оно короче):
[coode]
class A
class B extends A
class C extends A { def c() { ... } }
def f(a: A, ...) {
if (мы ну просто абсолютно твёрдо уверены, что a всегда типа B)
a.asInstanceOf[C].c()
}
[/code]
E__>И даже если ручками в байткоде написать — виртуалка не пропустит, обложили, демоны. А мемсета нету.
А виртуалка к статике никакого отношения не имеет. Повторяюсь: мой исходный вопрос — примеры слабой статики.
: "В статически и сильно типизированном языке во время компиляции можно гарантировать, что работа будет вестить только с правильным типом". Тем не менее, оно не выполняется. Следующую конструкцию компилятор схавает: D>>
D>>var s = "hello"
D>>var i = s.asInstanceOf[Int]
D>>
DR>Несмотря на приведение типа, у компилятора остаётся гарантия, что если типы не совместимы, то во время исполнения будет выброшено исключение.
Гы. "Однако, даже не знаю, что ответить, — говорит песец." (с) Ну например, так: у компилятора нет гарантий даже того, что скомпилированный код будет вообще хоть раз запущен. Какое отношение имеет компилятор к рантайму? Откуда ему знать, какая имплементация рантайма будет выполнять сгенерированный им код? В общем, какое отношение рантайм имеет ко времени компиляции?
Здравствуйте, Курилка, Вы писали:
DR>>>В статически и сильно типизированном языке во время компиляции можно гарантировать, что работа будет вестить только с правильным типом, а в слабо типизированном — нет.
D>>Java и scala — статически и сильно типизированные?
К>Лучше чем плюсы, но всё равно нет.
Хм. А что мешает? Ну generics на java кривые. Ещё этот typecast и рефлексия всю малину портят. Про JNI вот Don Reba упомянул. Если это всё убрать, они станут таковыми? Что ещё? А бывают вообще статические сильно типизированные языки?
E__>>Ага, тока в жабе компилер не пропустит.
D>Пропустит. Может, не буквально это, но фигню посложнее, подобную очччень часто встречающуюся вот такому безобразию, пропустит на ура (пишу в псевдокоде, ближе к scala, т.к. оно короче):
D>[coode] D>class A D>class B extends A D>class C extends A { def c() { ... } } D>def f(a: A, ...) { D> if (мы ну просто абсолютно твёрдо уверены, что a всегда типа B) D> a.asInstanceOf[C].c() D>} D>[/code]
E__>>И даже если ручками в байткоде написать — виртуалка не пропустит, обложили, демоны. А мемсета нету.
D>А виртуалка к статике никакого отношения не имеет. Повторяюсь: мой исходный вопрос — примеры слабой статики.
Приведенный выше пример только показывает, что в Жаве типизация строже, раз такие извороты надо делать
Здравствуйте, dimgel, Вы писали:
D>Гы. "Однако, даже не знаю, что ответить, — говорит песец." (с) Ну например, так: у компилятора нет гарантий даже того, что скомпилированный код будет вообще хоть раз запущен. Какое отношение имеет компилятор к рантайму? Откуда ему знать, какая имплементация рантайма будет выполнять сгенерированный им код? В общем, какое отношение рантайм имеет ко времени компиляции?
Виртуальная машина гарантирует строгую типизацию, компилятор — статическую. Всё просто, по-моему.
DR>>>>В статически и сильно типизированном языке во время компиляции можно гарантировать, что работа будет вестить только с правильным типом, а в слабо типизированном — нет.
D>>>Java и scala — статически и сильно типизированные?
К>>Лучше чем плюсы, но всё равно нет.
D>Хм. А что мешает? Ну generics на java кривые. Ещё этот typecast и рефлексия всю малину портят. Про JNI вот Don Reba упомянул. Если это всё убрать, они станут таковыми? Что ещё? А бывают вообще статические сильно типизированные языки?
Haskell, по идее.
Естественно, 100% строгой типизации никто не даст, потому что иначе программировать станет очень затруднительно, но к этому можно стремиться и не позволять что-нибудь типа (int)((void*)SomeObject)/1.0 для обхода системы типов.
Здравствуйте, Mamut, Вы писали:
D>>Хм. А что мешает? Ну generics на java кривые. Ещё этот typecast и рефлексия всю малину портят. Про JNI вот Don Reba упомянул. Если это всё убрать, они станут таковыми? Что ещё? А бывают вообще статические сильно типизированные языки?
M>Haskell, по идее.
M>>Естественно, 100% строгой типизации никто не даст, потому что иначе программировать станет очень затруднительно,
D>А хорошо, что я забыл добавить "И кому они нужны?" Это замечание собственно больше к предыдущей строке относится.
Здравствуйте, Mamut, Вы писали:
DR>>>>>В статически и сильно типизированном языке во время компиляции можно гарантировать, что работа будет вестить только с правильным типом, а в слабо типизированном — нет.
D>>>>Java и scala — статически и сильно типизированные?
К>>>Лучше чем плюсы, но всё равно нет.
D>>Хм. А что мешает? Ну generics на java кривые. Ещё этот typecast и рефлексия всю малину портят. Про JNI вот Don Reba упомянул. Если это всё убрать, они станут таковыми? Что ещё? А бывают вообще статические сильно типизированные языки?
M>Haskell, по идее.
Ну с требованием полной статической гарантии он не справится — к примеру, может сфейлиться ПМ, ну и unsafe тоже никуда не девается. Возможно требуемым критериям мог бы удовлетворять язык дающий total functional programming, только вроде таких так и не сделали толком.
Т.е. получается, что в любом случае часть проверок строгости переводится в рантайм (вплоть до почти полной динамики для динамических языков).
Здравствуйте, antonio_banderas, Вы писали:
_>Я хочу про С++. _>(руби и яваскрипт я всё равно не знаю)
Плюсую! Но по другой причине: тут как надо статику обосрать, туже на C++ кивают. Не язык, а терпила в натуре, за всю статику отдувается. Так что просьба закономерна и логична.
Здравствуйте, Mamut, Вы писали:
E__>>>Ага, тока в жабе компилер не пропустит.
D>>Пропустит. Может, не буквально это, но фигню посложнее, подобную очччень часто встречающуюся вот такому безобразию, пропустит на ура (пишу в псевдокоде, ближе к scala, т.к. оно короче):
D>>[coode] D>>class A D>>class B extends A D>>class C extends A { def c() { ... } } D>>def f(a: A, ...) { D>> if (мы ну просто абсолютно твёрдо уверены, что a всегда типа B) D>> a.asInstanceOf[C].c() D>>} D>>[/code]
E__>>>И даже если ручками в байткоде написать — виртуалка не пропустит, обложили, демоны. А мемсета нету.
D>>А виртуалка к статике никакого отношения не имеет. Повторяюсь: мой исходный вопрос — примеры слабой статики.
M>Приведенный выше пример только показывает, что в Жаве типизация строже, раз такие извороты надо делать
И то, это не джава — это скала. В джаве так не извратиться — компилер сходу завернет это дело.
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Здравствуйте, Eugeny__, Вы писали:
E__>И то, это не джава — это скала. В джаве так не извратиться — компилер сходу завернет это дело.
Ой, да що ви говорите!
dimgel@ascot ~/temp $ cat test.java
class Test {
static class A {}
static class B extends A {}
static class C extends A { void c() {} }
static C f(boolean isC, A a) {
return isC ? (C)a : null;
}
public static void main(String args[]) {
B b = new B();
C c = f(true, b);
System.out.println("Hello, фигли");
}
}
dimgel@ascot ~/temp $ javac test.java
dimgel@ascot ~/temp $ java Test
Exception in thread "main" java.lang.ClassCastException: Test$B cannot be cast to Test$C
at Test.f(test.java:6)
at Test.main(test.java:11)
Это essential-фича, неотъемлемое свойство таких кастов: либо они позволяют обманывать компилятор, либо их нет в языке вообще.
Здравствуйте, antonio_banderas, Вы писали:
_>Здравствуйте, Mamut, Вы писали:
M>>Люди саркастически издеваются над нашими любимыми языками программирования:
M>>https://www.destroyallsoftware.com/talks/wat
_>Я хочу про С++. _>(руби и яваскрипт я всё равно не знаю)
Да там одного дефайна хватит.
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Здравствуйте, Cyberax, Вы писали:
C>В С++ большая часть вещей вполне логична, если понимать причины, по которым оно так получилось. Оно всё переусложнено, но логично.
В JS то же самое.
C>А вот в JS нет никакой логики.
D>Это также ИМХО не катит: на java/scala я могу написать точно такой же левый каст, они от этого не станут слабыми. А то, что этот каст вылетит (точнее, может вылететь) в рантайме — дык это уже динамика, а не статика. А я спрашиваю про слабую статику. Техническая возможность беспредельничать разнообразными способами, форсированно обходя контроль системы типов, не означает отсутствие этого контроля. Грубо говоря, если я получу адрес объекта и тупо забью его мусором через memset(), это как бы к системе типов отношения не имеет.
Не всегда. Часто компилятор ругается, что такой каст никогда не прокатит. Пример:
String s = "";
int a = (int)(Object) s;
inconvertible types
found : java.lang.Object
required: int
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Здравствуйте, Eugeny__, Вы писали:
E__>Не всегда. Часто компилятор ругается, что такой каст никогда не прокатит. Пример: E__>
E__> String s = "";
E__> int a = (int)(Object) s;
E__>
E__>
E__>inconvertible types
E__>found : java.lang.Object
E__>required: int
Хм. Первая мысль была — не путаешь ли ты время компиляции со временем выполнения, но не похоже: во время выполнения ClassCastException вылетает. Возможно в данном случае фокус в том, что ты пытаешься привести объект к примитиву. Скале в этом случае пофиг, у неё есть Any, который обрабатывается в общем порядке, и автоматический boxing/unboxing:
scala> def f(s: String) = s.asInstanceOf[Object].asInstanceOf[Int]
f: (s: String)Int
scala> "".asInstanceOf[Object].asInstanceOf[Int]
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer