[js] что за веселый баг?

ramsit


['1'].map(parseInt)
[ 1 ]
> ['2'].map(parseInt)
[ 2 ]
> ['1', '2'].map(parseInt)
[ 1, NaN ]
> ['1', '2', '3'].map(parseInt)
[ 1, NaN, NaN ]
> ['2', '2', '3'].map(parseInt)
[ 2, NaN, NaN ]
> ['2', '2', '-1'].map(parseInt)
[ 2, NaN, -1 ]
> ['2', '1', '-4'].map(parseInt)
[ 2, NaN, NaN ]
> ['2', '1', '-2'].map(parseInt)
[ 2, NaN, NaN ]
> ['2', '1', '-1'].map(parseInt)
[ 2, NaN, -1 ]
> ['2', '1', '-1', '-4'].map(parseInt)
[ 2, NaN, -1, NaN ]
> ['2', '1', '-1', '-2'].map(parseInt)
[ 2, NaN, -1, -2 ]

и так далее.
Это ваще что такое?

Dasar

http://stackoverflow.com/questions/262427/javascript-arrayma...
The callback function in Array.map has three parameters:
callback is invoked with three arguments: the value of the element, the index of the element, and the Array object being traversed
In this case, you ended up calling parseInt with radix 0, 1 and 2 in turn. The first is the same as not supplying the parameter, so it defaulted to base 10. Base 1 is an impossible number base, and 3 is not a valid number in base 2:
So if you call a function which actually expects two arguments, the second argument will be the index of the element.
parseInt('1', 0); // OK - gives 1
parseInt('2', 1); // FAIL - 1 isn't a legal radix

kill-still

Я так одного нашего фронтэндщика тролил. Поэтому меня на собеседования с собой не берут - говорят я слишком злой. :(

ramsit

мда.
сочувствую тем, кто много пишет на js

Papazyan

вообще, такое могло произойти и в с++.

artimon

Не сочувствую тем, кто не осилил документацию и/или гугл. :p

luna89

Самое смешное, что проблема не связана с динамической типизацией.

kill-still

Это почему же? Функциональный тип никто не отменял!

Dasar

Самое смешное, что проблема не связана с динамической типизацией.
Частично связана.
Статический типизатор может выдать ошибку или подсветить warning, что присутствует неоднозначность: подходят два неэквивалентных варианта. Какой из них имел ввиду программист?
С точки зрения статической типизации в данном случае есть три вида функций map:

IEnumerable<T> map<T>(this IEnumerable<T> items, Func<T, T> f)
IEnumerable<T> map<T>(this IEnumerable<T> items, Func<T, int, T> f)
IEnumerable<T> map<T>(this IEnumerable<T> items, Func<T, int, IEnumerable<T>, T> f)

и два вида функции parseInt

int parseInt(string s);
int parseInt(string s, int base);

6yrop

Не сочувствую тем, кто не осилил документацию и/или гугл.
Если в документации прописать, что программы надо вводить с помощью перфокарт, то ты будешь счастлив пользоваться такой системой?

artimon

Не передёргивай. Если человек не удосужился посмотреть что делает `map` и какие параметры у функции `parseInt` — ему нечего сочувствовать.

ramsit

Не передёргивай. Если человек не удосужился посмотреть что делает `map` и какие параметры у функции `parseInt` — ему нечего сочувствовать.
мап он на то и мап, чтобы делать отображение функции на вектор. В нормальных языках никакой подобной неоднозначности не бывает, если я делаю map(function, array1 то функция берет один аргумент, даже если она потенциально может принимать и больше.
Если я делаю map(function, array1, array2 то функция function будет работать с двумя аргументами, и т.д.
А тут я конечно дико извиняюсь, но ['1', '2'].map(parseInt) делает что-то иное, чем [parseInt('1' parseInt('2')], то это уже не map.
Тады в документации надо большими буквами писать, что мап в js это вовсе не мап, а какая-то помесь с apply
Вот если челоdек, который использует js эпизодически и не знает этих безумных тонкостей, будет логично считать, что мап такой же как и везде, а то можно дойти и до того, чтобы читать документацию на + и -

ramsit

че-то вильфред-стайл какой-то получился :shocked:

Papazyan

Вот если челоdек, который использует js эпизодически и не знает этих безумных тонкостей, будет логично считать, что мап такой же как и везде, а то можно дойти и до того, чтобы читать документацию на + и -
Для js характерно передавать разное количество аргументов в зависимости от входной функции, это основной паттернв языке. Со своим уставом в чужой монастырь не лезь.

artimon

читать документацию на + и -
Ну вообще неплохо бы. Вот в JS `+` конкатенирует строки, а в perl приводит к числу

margadon

музыкой навеяло

ramsit

Ну вообще неплохо бы. Вот в JS `+` конкатенирует строки, а в perl приводит к числу
не пользуюсь подобными фичами, которые подразумевают неявное преобразование типов. Лучше написать ''.concat(a, b так сразу видно что это строки и только строки, а что в a+b - хз, поэтому плюс стараюсь ставить только там, где числа. Тогда смотришь на + и понимаешь, что это арифметика.
И т.д.

ramsit

музыкой навеяло
WTFJS

apl13

Первый пример:
/[A-z]/.test("\\"); // true WTF?
It's supposed to accept only letters from A to Z and a to z.
Дальше как-то лень читать.

yroslavasako

Не сочувствую тем, кто не осилил документацию и/или гугл. :p
Но зачем намеренно усложнять язык/библиотеку? Можно и на брейнфаке кодить, но неудобно же. А очевидное поведение - гораздо удобнее.

yroslavasako

Для js характерно передавать разное количество аргументов в зависимости от входной функции, это основной паттернв языке
Ну допустим, в языке есть перегрузка функций по количеству аргументов. Это нормально. Но вот у тебя есть конструкция из двух функций, где-за перегрузки обоих, появилась не однозначность. Тогда надо просто отказываться её обрабатывать. Выдаёшь по-человечески исключение на стадии исполнения или ошибку на стадии компиляции.

kill-still

О чем вы? В js нет никакой перегрузки функций.
var foo = function (a, b) {
console.log(a);
console.log(b);
};
foo(1);
>: 1
>: undefined

6yrop

Для js характерно передавать разное количество аргументов в зависимости от входной функции, это основной паттернв языке. Со своим уставом в чужой монастырь не лезь.
Слушай, ну какой там устав у js-а. Js это язык для некритичных маленьких скриптиков. Там фигачат кто во что горазд. Таким он был, такими и остается до сих пор.

Dasar

О чем вы? В js нет никакой перегрузки функций.
Это вопрос угла зрения.
Функция с опциональными параметрами одновременно удобно рассматривать: и как одну функцию, и как несколько перегруженных функций.
Второй вариант появляется в случае, когда контракт функции рассматривается отдельно от её "экземплярности".

luna89

Слушай, ну какой там устав у js-а. Js это язык для некритичных маленьких скриптиков.
Да, согласен - то что у программиста на js будет маленьким скриптиком, у программиста на каком-нибудь java/C# скорее всего окажется проектом с десятками классов, конфигурируемыми с помощью xml.

kokoc88

Да, согласен - то что у программиста на js будет маленьким скриптиком, у программиста на каком-нибудь java/C# скорее всего окажется проектом с десятками классов, конфигурируемыми с помощью xml.
У тебя двойные стандарты. Посмотри на свой код. Ты операцию + обернул в функцию и наворотил кучу кода только ради того, чтобы избежать одной лишней переменной. И при этом в твом коде стало ещё больше переменных.

6yrop

Да, согласен - то что у программиста на js будет маленьким скриптиком, у программиста на каком-нибудь java/C# скорее всего окажется проектом с десятками классов, конфигурируемыми с помощью xml.
Количество кода C# скорее всего пропорционально js коду. Да, коэффициент пропорциональности больше единицы. Но после определенного объёма коэффициент уже не особо критичен, и того и того кода уже много и его надо есть по частям. А вот есть по частям js код проблематично.

luna89

У тебя двойные стандарты. Посмотри на свой код. Ты операцию + обернул в функцию и наворотил кучу кода только ради того, чтобы избежать одной лишней переменной. И при этом в твом коде стало ещё больше переменных.
Это один из возможных подходов к работе с частично неопределенными данными - пишешь нормальные функции, потом лифтишь их в аппликативный функтор. Если бы там вычислялась сложная функция от 10 переменных, то мне не надо было бы в коде бизнес-логики проверять для каждой переменной, определена она или нет.
Как бы ты решал ту же проблему?

kokoc88

Как бы ты решал ту же проблему?
Простым mutable состоянием без всяких ненужных наворотов и паники. Лучше я потом на том объёме, что у тебя, добавлю автоматических тестов.

luna89

Простым mutable состоянием

У меня mutable состояние. Есть архитектура, когда на реакте пишут приложения с немутабельными данными, но я пока даже хелловорлды не пробовал так писать.
всяких ненужных наворотов и паники.

Вот ты и объясни, почему считаешь это ненужными наворотами и паникой.

Dasar

Простым mutable состоянием без всяких ненужных наворотов и паники.
Код покажи

Papazyan

Js это язык для некритичных маленьких скриптиков. Там фигачат кто во что горазд. Таким он был, такими и остается до сих пор.
Фигня. На нем очень просто писать офигительные интерфейсы, а теперь еще и векторную графику делать.

6yrop

Это не заслуга js.
Так исторически сложилось, на каждой платформе были попытки сделать UI движки, но, к сожалению, на эти проекты приходили архитекторы астронавты. Когда на проекте архитекторы астронавты, то проект долго мучается и медленно умирает.
В итоге лучшим UI движком оказался html/css/js движок.
Но это заслуга самого интерфейсного движка, написанного на C++, а как язык js убог.

luna89

Так исторически сложилось, на каждой платформе были попытки сделать UI движки, но, к сожалению, на эти проекты приходили архитекторы астронавты. Когда на проекте архитекторы астронавты, то проект долго мучается и медленно умирает.
То есть программисты на других языках - астронавты, усилия которых приводят к мучениям и смерти проекта? За все языки не скажу, но ситуацию с java ты описал довольно точно.
В итоге лучшим UI движком оказался html/css/js движок.
Js-программисты могут обойтись и без HTML DOM. Вот, например, разработчикам не подходил HTML (оказался слишком медленным для них, несмотря на C++ они написали бэкенд для react, который рендерит в canvas. Лэйаут движок тоже на js.

6yrop

То есть программисты на других языках - астронавты, усилия которых приводят к мучениям и смерти проекта?
Не все. Проекты по созданию UI движков это единичные проекты, даже если брать всю планету. Вероятность того, что на эти проекты попадут архитекторы астронавты довольно большая. Это и случилось. Рынок и эволюционные механизмы отбора еще просто не успели отрегулировать это. Программирование еще очень молодой вид человеческой деятельности.

Js-программисты могут обойтись и без HTML DOM. Вот, например, разработчикам не подходил HTML (оказался слишком медленным для них, несмотря на C++ они написали бэкенд для react, который рендерит в canvas. Лэйаут движок тоже на js.

Эти поделки без будущего. Хотя ребятам респект.
Если бы, скажем, на проект WPF попали бы не астронавты, то сейчас бы в энтерпрайзе никто бы и не вспоминал про HTML.
А что мы имеем в реальности. Microsoft выпускает Visual Studio Code – текстовый редактор написанный на javascript, который работает под оболочкой Chromium. После такого архитекторы WPF должны посыпать голову пеплом и сделать харакири.

luna89

Если бы, скажем, на проект WPF попали бы не астронавты
А на js нет архитектурных астронавтов. Если пишешь на js, то автоматически защищен от них. Поэтому написание UI фреймворка является не мегазадачей планетарного масштаба, а проектом, посильным для небольшого стартапа, у которого цель - написать быстрое кроссплатформенное приложение.

kokoc88

А на js нет архитектурных астронавтов. Если пишешь на js, то автоматически защищен от них.
Кажется, лет 8 назад я это уже слышал. В этом же разделе. Но про какой-то другой язык программирования.

6yrop

проектом, посильным для небольшого стартапа, у которого цель - написать быстрое кроссплатформенное приложение.
И что? Многие стартапы пишут прям сразу в мусорку. Надо смотреть не то, что пишет стартап, а во что это вылилось. Мне пока не попадалось на глаза что-то стоящее на js.

Papazyan

Мне пока не попадалось на глаза что-то стоящее на js.
Ха-ха, хорошая шутка, учитывая, что классические продукты того же гугл уже больше 10 лет на рынке.

luna89

И что? Многие стартапы пишут прям сразу в мусорку. Надо смотреть не то, что пишет стартап, а во что это вылилось.
У этого стартапа сейчас 100 000 000 пользователей.

kokoc88

У меня mutable состояние. Есть архитектура, когда на реакте пишут приложения с немутабельными данными, но я пока даже хелловорлды не пробовал так писать.
Да, у тебя тоже mutable состояние. Но оно не простое. Ты мог бы написать решение, не оборачивая переменные в отдельные объекты, а просто добавив два поля isGoodXXX. У тебя бы получился простой императивный код.
Вот ты и объясни, почему считаешь это ненужными наворотами и паникой.

Ты же сам жалуешься на десятки классов, конфигурируемых с помощью xml. Но твои функции - это то же самое. С чего это вдруг лишний класс - это плохо, а лишнее замыкание - это "маленький скриптик"?

6yrop

Поэтому написание UI фреймворка является не мегазадачей планетарного масштаба, а проектом, посильным для небольшого стартапа, у которого цель - написать быстрое кроссплатформенное приложение.
Ну так они и не написали UI движок:

React Canvas is not meant to completely replace the DOM. We utilize it in performance-critical rendering paths in our mobile web app, primarily the scrolling timeline view.
Where rendering performance is not a concern, DOM may be a better approach. In fact, it’s the only approach for certain elements such as input fields and audio/video.

luna89

не оборачивая переменные в отдельные объекты, а просто добавив два поля isGoodXXX
Это очень плохой способ, так как теряется информация, что isGoodXXX относится к XXX, а isGoodYYY к YYY. Можно легко опечататься, типа вместо

isGoodXXX ? XXX : null

случайно написать

isGoodYYY ? XXX : null

Намного круче упаковать XXX и isGoodXXX в одну структуру, и оперировать с ними как с одним целым.
Если у нас есть функция f с типом (X,Y,Z) -> W, то функция lift f будет иметь тип (Maybe X, Maybe Y, Maybe Z) -> Maybe W. Это намного удобнее, чем таскать с собой флаги.

luna89

Ну так они и не написали UI движок:
Из твоей цитаты не следует, что это не UI движок. Там написано, что их движок нужен для быстрых анимаций, но DOM лучше для других задач. Это обычная ситуация - где-то выигрываем, где-то проигрываем.

6yrop

случайно написать
ты еще не знаешь, что ответит Майк? :grin:

luna89

наворотил кучу кода
Замечу, что 70% написанного кода никак не относится к калькулятору, и их можно спокойно использовать для писания любых похожих форм. Сам калькулятор составляет 15 строк, включая html верстку

kokoc88

Это очень плохой способ, так как теряется информация, что isGoodXXX относится к XXX, а isGoodYYY к YYY. Можно легко опечататься, типа вместо
Можно. У тебя тоже можно вместо lift2 написать lift, а вместо a + b написать a + a, и так далее по списку. Потому что написание кода - это один процесс, а проверка правильности - другой.
Замечу, что 70% написанного кода никак не относится к калькулятору, и их можно спокойно использовать для писания любых похожих форм. Сам калькулятор составляет 15 строк, включая html верстку
Я с этим не спорю. Но притащи в проект все свои библиотеки и получишь то же самое, что и в Java: *.jar против *.js При этом Java ты ненавидишь и там тонны кода и ненужных классов, а JavaScript няшный и пушистый.

6yrop

Потому что написание кода - это один процесс, а проверка правильности - другой.
Пишешь код сегодня, а проверяешь через месяц?

kokoc88

Пишешь код сегодня, а проверяешь через месяц?

6yrop

Я про тебя спрашиваю. Раз у тебя написание и проверка две совсем разные задачи, и с учетом известного правила кратковременной памяти 7+-2, получается ты загружаешь в кратковременную память все детали задачи по два раза. Это же не эффективно.

kokoc88

Я про тебя спрашиваю. Раз у тебя написание и проверка две совсем разные задачи, и с учетом известного правила кратковременной памяти 7+-2, получается ты загружаешь все детали задачи дважды в кратковременную память.
Ты только что завалил тест Тьюринга.

luna89

Я с этим не спорю. Но притащи в проект все свои библиотеки и получишь то же самое, что и в Java: *.jar против *.js
Нет, конечно - я же не пишу в стиле AbstractSingletonProxyFactoryBean.

yroslavasako

Используй другие либы

luna89

Используй другие либы
Я же не могу в одиночку программировать. Коллеги захотят использовать либы, более привычные их вкусу.

kokoc88

Нет, конечно - я же не пишу в стиле AbstractSingletonProxyFactoryBean.
Но зато ты используешь liftAAA liftBBB wrappedOperatorXXX wrappedSdkFunctionYYY, никакой разницы.

yroslavasako

javascript либы? Через nashorn будете запускать?

6yrop

Но зато ты используешь liftAAA liftBBB wrappedOperatorXXX wrappedSdkFunctionYYY, никакой разницы.
Все пишут читаемый код, но не любят читать код друг друга.
Оставить комментарий
Имя или ник:
Комментарий: