Так нет там ветвлений, там проверка входных параметров на соответствие ожидаемым, она достаточно простая, если она не проходит — все деоптимизация и попытка повторной оптимизации. Потому производительных жс выглядит довольно плохо так как приходится отказываться от любого вида мономорфизма. Иногда компилятор может быть уверенным на счет типа, если значение получено из типизированного массива (это пока не всегда хорошо работает, но это исправляют) или выполняется явное приведение типов. Так что в принципе как раз математику на жс писать можно довольно производительную, но на васм производительность будет более предсказуемой. По тестом это даже не на порядок, а в несколько раз 2-7.
Если тип не изменился — то не так уж и страшна эта проверка, так что не так все и плохо с математикой в js. Плохо правда, что не всегда делается приведение операций к типу данных и при сложении int8 могут использоваться операции над int32, но это сейчас в процессе доработки.
Поддержка int64 и вообще чисел произвольного размера добавлена в предложения.
сейчас это даже медленнее так как из wasm просто дергаются внешние функции на js, сама же wasm ничего о дом не знает и умеет только считать int и float 32 и 64, да в линейную память писать.
Что в коде и делается. Там одна описка при проверке на итератор тоже нужно проверять прототип. А так как раз изменяется прототип класса, а не каждый объект.
Можно написать простенький декоратор который будет это делать для синхронного или для асинхронного итератора. Пример map:
function functor(Target) {
if(!Reflect.has(Target, Symbol.asycIterator)) throw new Error(`${Target} should be async iterable`);
if(!Reflect.defineProperty(Target.prototype, 'map', {
value: async function(transform) {
const res = [];
for await(const el of this) {
res.push(transform(el));
}
return res;
}
}) throw new Error(`${Target} already has a map method`);
return Target;
}
@functor // или после объявления класса functor(Queue) если не хочется включать бабель для декоратора
class Queue {...}
В данном примере map просто асинхронно выгребет коллекцию, применит к ней заданную трансформацию и вернет промис с результатом, но можно поведение усложнять и генерировать события на каждый приход элемента.
Просто итератор будет бесконечный и проверку на выход прийдется делать руками каждый раз. В случае же асинхронного итератора у вас проверка будет спрятана в сам итератор и он не будет бесконечным.
Просто в жс быстрый код — это обычно уродский код, а его не так просто поддерживать. Понятно, что стоит выделять критические места типа работы с многомерными массивами в библиотеки и их уже максимально оптимизировать. Но проект лучше держать в читабельном виде максимально долго.
Для тежелых операций f, g разница не может быть в два раза, если операции очень дешевые, то оверхед может быть заметен и как раз и будет давать разницу в два раза.
Как правило, если проект большой, лучше писать красивее и понятнее, а уже потом думать о скорости. Часто узкие места появляются совсем не там где их ждешь.
А почему я их не должен использовать? Я и Foldable монады использую с их методом reduce там где это помогает читабельности. Оптимизация — это уже второй вопрос, где нужно можно и через цикл переписать, но обычно до этого не доходит, тем более на этом много не выиграешь.
В моно у вас компилятор перед выполнением все проверки сделает и выдаст вам идеальный машинный код, а в жс это все будет делать JIT ему прийдется многое угадывать и про ваш элемент и про ваш предикат. А если код который будет выполняться в компиляторе написан на смеси жс и с++ (да v8, это как раз компилятор с++ на жс и с++) то у вас будет теряться время на переход, так что не все так просто.
Я про внутреннюю реализацию в браузере, сейчас в v8 эти методы переводят на с++ и они будут инлайнится компилятором чтоб убрать расходы на переключение между с++ и js и повысить производительность. Про O(n) — сравните 100 n и n ** 2 при небольших n — или n и 10000 n, все имеет значение, для этого и используют комбинированные алгоритмы. У меня повседневное использование это счет и отрисовка графики, компилятор — нет, хотя не вижу в этом ничего дурного, но кодеки писали, не сказал бы, что мы что-то делаем не так.
Нативный метод может быть реализован на javascript или еще хуже — смеси c++ и javascript, сейчас почти все методы массива не оптимизированы на типизированных массивах. O(n) тоже бывает разным.
Паша, ну не редакс заставляет людей писать быдлокод, а руки-крюки. Проблема не в языке, везде нужно мастерство, чтоб сделать что-то стоящее. А юнити с ассет стором как раз сделал разработку ширпотребной, с пхп сравнить нельзя, но посмотри внутрь популярных плагинов и печалью наполнятся дни твои =)
Сейчас контекста операции нет и работает это не так, просто независимо друг от друга операнды без знания операции приводятся к примитивам, а затем происходит операция. Если проверять как говорите вы — прийдется сильно менять существующую схему работы. Как оно будет реализовано в итоге и будет ли пока загадка, я просто предположил как это может быть сделано дешево, с минимальными изменениями и добавлением дополнительного контекста.
Так наверняка можете и что-то более производительное и рабочее сделать тут главное не превращать все в монады, а оборачивать. Если решите поиграться — смотрите на спецификацию FantasyLand.
Да, я тоже мечтаю именно о такой реализации, но пока основная загвоздка в механизме работы арифметических операций, пока операнды приводятся к примитивам независимо друг от друга ничего об операции не зная и до выполнения операции, это хорошо работает для примитивов, но плохо сочетается с перезагрузкой, поэтому нужна новая схема применения операторов. Мне кажется через контекст операции это реализуется проще всего. Сначала каждый из операндов регистрирует себя в контексте операции (сейчас с помощью Symbol.toPrimitive можно регистрироваться в глобальном контексте), а затем во время вычисления операции нужно проверять — если контекст не пустой, то уже зная операцию вызывать нужный переопределенный метод для операндов из контекста (сейчас этого шага нет и операция просто проходит с примитивами, а в случае с фейковой перезагрузкой нужно иметь какой-то оберточный метод который будет проводить данную операцию для возвращения результата из контекста). Это кажется наименее затратной схемой которая минимально меняет правила применения операндов и видимо не особо повлияет на производительность для операций с примитивами (добавится простая проверка пустоты контекста).
Она понемногу появляется, можно например перезагружать оператор for-of через переопределения Symbol.iterator, можно перезагружать оператор точка (получение свойства) через прокси и т.д. Все к этому движется в основном благодаря символам, арифметические операции выполняются по другим правилам (если встречается объект он приводится с помощью Symbol.toPrimitive к примитиву) но возможно они введут новый символ который будет создавать контекст для операции (что-то по типу того как делается в фейковой перегрузке операторов, только не глобальный контекст, а именно локальный для операции).
Поддержка int64 и вообще чисел произвольного размера добавлена в предложения.
На самом деле 53 и 11.
нет нельзя, класс может наследоваться от чего-то другого, так что нужен именно декоратор-миксин.
В данном примере map просто асинхронно выгребет коллекцию, применит к ней заданную трансформацию и вернет промис с результатом, но можно поведение усложнять и генерировать события на каждый приход элемента.
Просто итератор будет бесконечный и проверку на выход прийдется делать руками каждый раз. В случае же асинхронного итератора у вас проверка будет спрятана в сам итератор и он не будет бесконечным.
Как правило, если проект большой, лучше писать красивее и понятнее, а уже потом думать о скорости. Часто узкие места появляются совсем не там где их ждешь.
В моно у вас компилятор перед выполнением все проверки сделает и выдаст вам идеальный машинный код, а в жс это все будет делать JIT ему прийдется многое угадывать и про ваш элемент и про ваш предикат. А если код который будет выполняться в компиляторе написан на смеси жс и с++ (да v8, это как раз компилятор с++ на жс и с++) то у вас будет теряться время на переход, так что не все так просто.
и
не значительна
Так наверняка можете и что-то более производительное и рабочее сделать тут главное не превращать все в монады, а оборачивать. Если решите поиграться — смотрите на спецификацию FantasyLand.