LINUX.ORG.RU

programming languages performance benchmarks

 , , ,


2

1

А какие еще есть онлайн системы для сравнения производительности реализаций языков программирования кроме всем известного benchmarksgame, который весьма специфичен + там мало языков, а когда-то было намного больше. Фреймворки и открытые библиотеки на основе которых можно сделать нечто подобное тоже приветствуются. Что бы вы хотели видеть в таком сервисе, что можно вообще улучшить?

Ответ на: комментарий от SR_team

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

Ошибка может портить произвольную память, включая адрес возврата в стеке. После этого упадёт совсем в другом месте и может даже с битым стектрейсом.

https://blogs.unity3d.com/ru/2016/04/25/debugging-memory-corruption-who-the-hell-writes-2-into-my-stack-2/

monk ★★★★★
()
Ответ на: комментарий от Benis

14 лет пишу на C++, ни про какую методологию не слышал

Продолжай в том же духе.

alienclaster ★★★
() автор топика
Ответ на: комментарий от bajex

Ты либо сообщаешь, что никакого ФП и чистоты у тебя нет(как это делает си),

Так их и нет как единственного пути. Есть удобство работы с ФП и чистыми функциями (а также ADT и ленивыми структурами), также как в Си++ есть удобство работы с указателями (но это же не запрещает писать на нём программы без указателей).

Вычисления не этапе компиляции - это не читы.

Да ну? Для pi-digits будет принято что-то вроде

(defmacro make-pi-10000 () ...)
(defvar *pi* (make-pi-10000))

(print-lines (subseq *pi* 0 (parse-integer (nth 1 sb-ext:*posix-argv*))))

?

monk ★★★★★
()
Ответ на: комментарий от iZEN

Андрей Паньгин — Мифы и факты о медленной Java

О, это просто источник фейспалмов. Как-то мне его кидали, дальше мой ответ.

В первом примере ему пришлось затормозить плюсы до состояния джавы, что тут ещё сказать. Второй и третий IO bound, т.е. любой язык, который не полный тормоз должен выдать примерно одинаковые результаты.

Тут пару минут о Java vs. C++: https://youtu.be/fHNmRkzxHWs?t=8m32s

А так джава может по сравнению со своими предыдущими версиями меньше тормозит, но если ты дашь ей столько же памяти, сколько требует аналогичный код на C++, или учтёшь разницу в потреблении при оценке, тогда уже будут осмысленные результаты сравнения (а не так что у тебя один поток в C++, а у джавы там что-то параллельно делается на другом ядре).

xaizek ★★★★★
()
Ответ на: комментарий от monk

Так их и нет как единственного пути. Есть удобство работы с ФП и чистыми функциями (а также ADT и ленивыми структурами), также как в Си++ есть удобство работы с указателями (но это же не запрещает писать на нём программы без указателей).

Нет, это всё манёвры. С++ не заявляется как язык «только про укзаталеи», а вот хаскель, фп и прочая дристня завяляется. В этом проблема.

Это как раст. Заявляется «безопасно и быстро», а в реальности весь код на расте там - ворованная перепаста с С/С++ написанная даже не на расте, а на интринсиках С/С++ компилятора.

Т.е. получается ситуация такая, что говоря про быстро и про результаты - мы показываем не безопасный код не на раста, при этом ворованная с ворованным же компилятором. При этом подобный «раст» уже потерял все свойства, которыми его неделяет пропаганда.

Вот представь, что мы бы говорили «нож безопасный и всё режет», только в одном случае мы бы говорили про нож из пенопласта, а в другом про обычный.

Да ну? Для pi-digits будет принято что-то вроде

Не будет. Во-первых это не соберётся никогда, а во-вторых это читы.

В хаскель-помойке компилтайм воспринимается за примитивную херню уровня «посчитать функцию», потому как для скриптухи подобное ничего не стоит.

Но компилтайм этим не ограничивается. Используй компилтайм не как читы уровня «Заранее посчитать», а как помощь в реализации эффективных решений.

bajex
()
Ответ на: комментарий от monk

Допустим, вот реализация revcomp в 10 раз более быстрая, нежели то дерьмо, что реализовано там.



template<size_t block_size, size_t lines> struct revcomp {
  
  constexpr static size_t line_size = 60;
  constexpr static uint8_t delim = '_';
  
  using T = uint16_t;
  using Tread = uint32_t;
  constexpr static size_t tsize = sizeof(T);
  constexpr static size_t read_size = sizeof(Tread);
  
  
  constexpr static size_t bytes_per_block = block_size * read_size;
  
  constexpr static size_t reads = (lines * line_size) / read_size;
  static_assert((reads * read_size) == (lines * line_size));
  
  constexpr static auto blocks = reads / block_size;
  constexpr static auto total = lines * (line_size + 1);
  static_assert(blocks * block_size == reads);
  
  
  constexpr static auto convert = [](auto value, auto to_type) {
    using T = typename decltype(+to_type)::type;
    return unpack(make_range(size_c<0>, hana::sizeof_(value) / hana::sizeof_(to_type)), [&](auto ... indexes) {
      return make_tuple((T(value >> (indexes * hana::sizeof_(to_type) * size_c<8>)))...);
    });
  };
  
  
  
  constexpr static auto nlcount = [](auto n, auto offset_in_bytes) {
    return (offset_in_bytes + (line_size - n)) / line_size;
  };
  
  constexpr static auto read_block = [](auto read_num, auto in) {
    auto range = to_tuple(make_range(read_num, size_c<read_num + block_size>));
    auto values = transform(range, [&](auto offset) {
      //нужно компенсировать '\n' при чтении.
      // Это значит, что через каждые line_size офсета нужно компенсировать 1 байт.
      constexpr auto nlc = nlcount(0, offset * read_size);
      return *((Tread *)(in - (offset * read_size + nlc)) - 1);
    });
    return values | (reverse ^ on ^ hana::reverse_partial(convert, type_c<T>));    
  };
  
  constexpr static auto store_block = [](auto outs, auto out) {
    for_each(outs, [&](auto rop) {
      auto base = out;
      *(std::decay_t<decltype(rop[1_c])> *)(base + rop[0_c]()) = rop[1_c];
    });
  };
  
  template<size_t n> struct selectn {
    constexpr static auto is_blocknl = [](size_t offset) {
      return nlcount(n, offset * read_size) < nlcount(n, offset * read_size + bytes_per_block);
    };
    
  constexpr static auto process_blocknl = [](auto block) {
    constexpr auto posb = ((n - size_c<1>) % bytes_per_block);
    
//     возможны два варианта:
//     (posb & 1):  [ab][ab] -> [ab][ab][_]
//     !(posb & 1): [ab][ab] -> [ab][a][_][b]
    if constexpr(posb & 1) {
      constexpr auto pos = size_c<(posb / tsize)>;
      auto el = block[pos];
      //вариант первый, записать [_] за pos-блоком
      return insert(block, pos + size_c<1>, make_tuple(el[0_c] + size_c<sizeof(el[1_c])>, delim));
    } else {
      constexpr auto pos = size_c<(posb / tsize)>;
      auto el = block[pos];
      auto els = zip(to_tuple(make_range(el[0_c], el[0_c] + size_c<tsize> + size_c<1>)), insert(convert(el[1_c], type_c<uint8_t>), 1_c, delim));
      return hana::insert_range(remove_at(block, pos), pos, els);
    }
  };
  
  
  
  constexpr static auto add_indexes = [](auto block_num, auto outs) {
    constexpr auto read_num = block_num * block_size;
    auto range = to_tuple(make_range(0_c, hana::size(outs)));
    return transform(range, [&](auto x) {
      constexpr ssize_t offset = read_num * read_size + x * tsize;
      constexpr auto nlc = nlcount(n, offset);
      return make_tuple(size_c<offset + nlc>, outs[x]);
    });
  };
  
  __always_inline static void process(const char * in, char * out) {
//     print("blocks:", blocks);
    size_c<blocks>.times.with_index([&](auto block_num) {
      constexpr auto offset = size_c<block_num * block_size>;
      
      
      auto block = read_block(offset, in);
      //       print(block | (reverse ^ on ^ hana::reverse_partial(convert, type_c<uint8_t>)));
      
      auto processed_block = transform(block, _[data(map<T>)]);
      //       auto processed_block = transform(block, [](auto x) { return __builtin_bswap16(x);});      
      
      auto outs = add_indexes(block_num, processed_block);      
      
      if constexpr(is_blocknl(offset)) {
        store_block(process_blocknl(outs), out);
//         store_block(outs, out);
      } else {
        store_block(outs, out);
      }                                    
    });    
  }  
    
  };
  
};

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

При этом эта реализация не просто в 10 раз быстрее - она максимально быстрая. Быстрее сделать невозможно - она даёт теоретический максимум производительности. Можно там попробовать потюнить под отдельных процессоры, но это уже нюансы и даст копейки и не факт, что это возможно.

bajex
()
Ответ на: комментарий от bajex

Нет, это всё манёвры. С++ не заявляется как язык «только про укзаталеи», а вот хаскель, фп и прочая дристня завяляется. В этом проблема.

И ты кончено же предоставишь пруфлинк, где разработчики заявляют, что Haskell исключительно для чистых ФП программ?

Не будет. Во-первых это не соберётся никогда, а во-вторых это читы.

Соберётся примерно за 4 секунды. А, во-вторых, ты писал «вычисления не этапе компиляции - это не читы».

Используй компилтайм не как читы уровня «Заранее посчитать», а как помощь в реализации эффективных решений.

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

monk ★★★★★
()
Ответ на: комментарий от alienclaster

Никто не отменял нормального курса / учебника о том как надо писать и в чем смысл тех или иных конструкций.

Согласен, поэтому мне, в свое время, очень понравились Racket, Guile и Emacs Lisp, у них есть классные мануалы, с примерами и разжевыванием.

Это где их нет? В racket, CL все есть, даже в clojure есть хоть и не идиоматично.

Я ошибся

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

Вот это и правда интересно. Для меня декларативщина это магия, поэтому с удовольствием бы посмотрел на реализацию.

snake266 ★★
()
Ответ на: комментарий от bajex

Где же замена бездарным крестам?

anonymous
()
Ответ на: комментарий от monk

И ты кончено же предоставишь пруфлинк, где разработчики заявляют, что Haskell исключительно для чистых ФП программ?

An advanced, purely functional programming language

Написано на сайте этой нелепой скриптухи. Ты решилначать отрицать очевидное?

Соберётся примерно за 4 секунды.

Не соберётся - ты взял какую-то мелкую n. Программа должна работать для любых n.

А, во-вторых, ты писал «вычисления не этапе компиляции - это не читы».

Я тебе дал расшифровку. Если тебе проще, то «нормальные вычисления», а у тебя не нормальные. У тебя как раз таки читы. Как раз таки в силу слабости тебя и твоей скриптухи, ты не можешь придумать ничего более, чем почитать результаты заранее. Это читы.

А нормальный компилтайм - не читы.

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

Где ты его и как используешь? Нигде. Ты пытаешься считарить - просто запустить скриптуху в момент фейковой компиляции. Это ничего не стоит и никому ненужно.

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

bajex
()
Ответ на: комментарий от bajex

Где царский крестовый блог и царский компилятор?

anonymous
()
Ответ на: комментарий от monk

Ты бы лучше отвечал за свои предыдущие заявления, а то что-то ты много заявляешь, а опровержения игнорируешь.

В Racket и без макроса лаконично:

Бездарная скриптуха не может быть лаконичной. Не говоря уже о том, что этот тормозной и бесполезны мусор. Лаконичность мы видим даже здесь:

(map (lambda (number1 number2)
         (+ number1 number2))
       '(1 2 3 4)
       '(10 100 1000 10000))

Состоящей даже в нелепой скриптухи без синтаксиса из синтаксического мусора. Что это за ’, что это за нелепое определение (lambda (number1 number2) (+ number1 number2)?

Почему оно выглядит так убого, при этом будучи тормозной скриптухой нетипизированной. Там врыажать семантики нужно на порядок меньше, нежели в С++. И выглядит оно как говнище. Им же и является.

bajex
()
Ответ на: комментарий от bajex

Очередная маня порвалась от скобок и страшного ’. Ты даже на уровень царского подражателя не годишься.

anonymous
()
Ответ на: комментарий от xaizek

Вроде была доступна какая-то старая версия, а не текущие исходники.

Исходники чего, веб-мордочки? Они не особо и нужны. Или там что-то ценное есть для автоматизации?

alienclaster ★★★
() автор топика

Что бы вы хотели видеть в таком сервисе, что можно вообще улучшить?

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

xaizek ★★★★★
()
Ответ на: комментарий от bajex

Не соберётся - ты взял какую-то мелкую n. Программа должна работать для любых n.

Тесты на на n до 10000. Можно ускорить получение результата для части n.

Ты пытаешься считарить - просто запустить скриптуху в момент фейковой компиляции. Это ничего не стоит и никому ненужно.

Почему фейковой? Компиляция нормальная. Также как расчёт CRC32 табличным методом.

monk ★★★★★
()
Ответ на: комментарий от monk

Тесты на на n до 10000. Можно ускорить получение результата для части n.

Это читы. Это ничего не стоит, как и твои части. Любую скриптуху можно азпустить заранее и зашить результат. Это ничего не стоит.

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

Почему фейковой? Компиляция нормальная.

Фейковая, в скриптухе нет компиляции. Там есть «компиляция». Ты уже спорил со мною на эту тему.

Также как расчёт CRC32 табличным методом.

Нет, не так же. Ещё раз, программа должна работать для любых входящих данных, либо, по крайней мере, адекватных.

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

В программу не должен быть зашит ответ. В противном случае это читы. Идёшь и делаешь тоже самое с программой, которая генерирует терабайты. Допустим с revcomp.

bajex
()
Ответ на: комментарий от monk

А понять, в какой ассемблерный код что развернётся без рекурсии в языке проще

О чем тогда спор? Да, рекурсия тяжела для понимания.

Также как нормальному водителю, начавшему ездить ещё в СССР, является излишеством автоматическая коробка передач и бортовой компьютер. Без них машину проще чинить, а ездить оно ему не помогает

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

Да, широкий класс алгоритмов становился очень труднореализуем, но на практике они были не нужны

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

Указатель на что будешь возвращать из конструкции типа (define (compose f g) (lambda (x) (f (g x)))) ? Либо придётся в программу встраивать компилятор (привет FoxBase), либо функция в программе не имеет ничего общего с CALL/RET ассемблера (как это было изначально в лиспах)

Ты мне хочешь рассказать, что в сишных программах тяжело передать указатель на функцию, что ли? Очень даже передают. И даже композицию функций можно реализовать, если у функций достаточно простые аргументы.

Указатели были ещё в PL/I. Вот Undefined Behavior до C не было. Даже в ассемблерах.

В асме нельзя было переполнить число при арифметике или попытаться разыменовать некорректный указатель? Отличные истории.

byko3y ★★★★
()
Ответ на: комментарий от iZEN

Андрей Паньгин — Мифы и факты о медленной Java (2017 год): https://www.youtube.com/watch?v=NMc8AnyhyS8

Единственный факт — это что в одноклассниках работают бездарные мудозвоны. Что подтверждает эта унылая лекция.

byko3y ★★★★
()
Ответ на: комментарий от alienclaster

Это уже вопрос к смузихлебам из гугла – почему они решили продолжать придерживаться питона, хотя есть R и Julia.

Потому что питон это язык общего назначения с достаточно приятным синтаксиса, лучше только у руби

Julia о-о-очень похожа на питон, так что аргумент не засчитан. А вот про приятность руби можно поспорить. R чуть менее приятен, но он уже был в нулевых.

Конечно упускаешь, возьми просто срез языков которые были в начале 2000х более или менее юзабельных и если отбросить лисп то остается что?

PHP, Ruby, Lua, Smalltalk.

Но как только дело вышло из академий – выяснилось, что этим инструментом целевая аудитория не может пользоваться.

Кем выяснилось?

Рыночком. Речь еще про поздние 90-е, когда индусы массово ломанулись на тот же PHP, который даже ни одна корпорация не продвигала. При том, что в это время Lisp еще был топовым языком индустрии, а про PHP знало две дюжины индусов, да и был он таким куцым, что толку с него было мало.

Руби это точно такой же питон +-, который взлетел только из-за рельсов, а так бы о нем никто не знал за пределами нипонии

Я в предыдущем треде динамикосрача приводил пруфы, что руби взлетел на крыльях Apple. Иначе бы никуда он не взлетел, с рельсами или без.

А программы пишут программисты, дата сайнс это просто не про программирование

Если инструментом пользуется больше людей, то он победит инструмент, которым пользуется меньше людей. И не важно, какие там объективные недостатки и преимущества с технической стороны.

Низкий порог входа, пиар и наличие батареек всегда уделывают все для большинства людей. А так же баблос и прочие ресурсы от корпораций

А кто мешает сделать «лисп на рельсах»? В том-то и дело, что сделать ничего подобного нельзя, ты в любом раскладе получаешь высокий порог входа... ну или теряешь все преимущества лиспа, предоставляя полностью нелисповый интерфейс программирования.

byko3y ★★★★
()
Ответ на: комментарий от alienclaster

Есть другие разновидности подобного мозговыноса, вроде функции, возвращающей функцию — во многих ранних ЯП не было этой фичи тоже (кобол, фортран, бейсик)

Наколеночные поделки умели ровно то, о чем знал их автор на момент написания

Я приводил пример с дейкстрой, там были комитеты для алгола-60 и 68, и там прекрасно уже знали про рекурсию, а все равно не хотели ее вводить. И лисп уже был к началу семидесятых, а все равно не спешили писать функции, возвращающие функции. У крестов лямбды появились только в C++11.

Чем ты отличаешь от обывателя? Какой-то илитаризм на ровном месте

Долго перечислять, и это по большей части личное. Мог бы конкретные тезисы затронуть, но только отдельные.

Lisp просто не пиарят вот и вся история, причины чисто исторические «так совпало»

Лучший пиар в индустрии — это популярность. Лисп по состоянию на конец 80-х был №1 динамическим языком в индустрии. И он потерял решительно всё, буквально за 15 лет. Посмотри на Си, который до сих пор популярен, хотя ненамного младше лиспа. Даже на фортране что-то там пишут.

byko3y ★★★★
()
Ответ на: комментарий от anonymous

взгляд из собственного контекста опрокинутый в прошлое.
по рабочим документам Уилкса да и всех конструкторов первых ЭВМ очевидно что там и гёделя на ходу использовали

Не понимаю о чем речь? Я вот понимаю, что Тьюринга использовали — до сих пор индустрия не может очухаться от этого тупикового наследия.

учитывая аппаратное наличие целого одного регистра и исходно перезаписывающийся код разнице между самодельными замыканиями и самодельными стеками меньше чем

Вся память в старых компьютерых и была оперативной. «Регистры» были просто служебными участками памяти. Причем, подобная организация есть до сих пор, если я не ошибаюсь, в PIC. Именно поэтому в 8008/8080 свободно применяли инструкции вроде «add [0x1000], 2» — это инструкция увеличения значения «регистра» под номером 0x1000 на 2.

А разница между замыканиями и рекурсиями в языке и костыльной генерацией маш кода таки есть — в первом случае код статичный.

byko3y ★★★★
()
Ответ на: комментарий от iZEN

Оптимизацию нужно проводить после исследования написанного рабочего программного кода, в котором замечены замедления, а не до

«Premature optimization is the root of all evil» — эта проблема никуда не делась.

byko3y ★★★★
()
Ответ на: комментарий от SR_team

Ошибка на C++ приводит к сегфолту в случайном месте программы

не в случайном, а там, где произошла ошибка

Я брошу все ЯП и буду писать на C++, если он позволит мне получать ошибку там, где она произошла. Но по факту ошибка либо не выдастся, либо выдастся в любом месте, кроме того, где она произошла. А потом сиди и пытайся отследить путь обратно к месту ошибки.

byko3y ★★★★
()
Ответ на: комментарий от xaizek

Это и хорошо, потому что оно с какого-то момента начало деградировать. Для меня критическим моментом было, когда они выкинули LuaJit. А LuaJit шокирует своим быстродействием, сплошь и рядом рвёт Си. Т.е. явно тут уже пошла речь о какой-то нечестной конкурентной борьбе. Потом они подмухлевали картиночки так, чтобы Ява выходила быстрее всех языков, и это уже конец. Исходники были опубликованы намного раньше. Я прямо готов заказать пиво или пиццу тому, кто поднимет этот ресурс в том виде, как он был раньше.

Более того, я слышал историю, что якобы автор этого ресурса мониторил места, где обсуждали факт выбрасывания LuaJit, встревал в эти обсуждения и катил на всех баллоны из серии «мой ресурс, что хочу - то и делаю, не нравится - заводите свой».

den73 ★★★★★
()
Последнее исправление: den73 (всего исправлений: 6)
Ответ на: комментарий от byko3y

Очень даже передают. И даже композицию функций можно реализовать, если у функций достаточно простые аргументы.

Попробуй.

Пусть

typedef int (*func)(int);

func compose(func f, func g);

Напишешь тело compose?

В асме нельзя было переполнить число при арифметике или попытаться разыменовать некорректный указатель?

В каком из этих случаев, по-твоему, был Undefined Behavior (то есть произвольное поведение)? На тех ассемблерах, что я знаю переполнение всегда возвращало определённый результат, а разыменование некорректного указателя либо данные по этому адресу (если память доступна), либо прерывание (если не доступна). В то время как в Си разыменование некорректного указателя может приводить к выкидыванию проверки после этого разыменования в совсем другом месте ниже по коду. Или возвращение всегда константы вне зависимости от реального значения по тому адресу. Или вообще всё что угодно.

monk ★★★★★
()
Ответ на: комментарий от den73

LuaJit шокирует своим быстродействием, сплошь и рядом рвёт Си

Я сам выдвигал этот ошибочный тезис, и сам же его исправлял — LuaJIT не рвет Си, оно рвет только жаву, и то не всегда.

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

Ситуация немного не так выглядит. Современная JVM представляет собой груду костылей, которые оптимизируют пусть и не паттерны, но что-то очень близкое к тому — типовые способы применения иерархий классов и интерфейсов, главным образом с применением стандартной библиотеки и самых распространенных сторонних библиотек. Хочешь оптизировать свою специализированную софтину, для которой этих костылей не хватает? «Спасибо опенсорсу, что у нас есть сорцы и мы можем их доработать».

byko3y ★★★★
()
Ответ на: комментарий от byko3y

А кто мешает сделать «лисп на рельсах»? В том-то и дело, что сделать ничего подобного нельзя, ты в любом раскладе получаешь высокий порог входа…

С чего это? Вот пример как можно сделать:

https://queue.acm.org/detail.cfm?id=2068896

Удобный DSL и возможность вызвать любую лисповую функцию.

Вопрос на самом деле в пиаре.

Я в предыдущем треде динамикосрача приводил пруфы, что руби взлетел на крыльях Apple.

Вот! Если какая-нибудь корпорация решит раскрутить лисп для веба, будем все писать на нём (по слову AutoLisp до сих пор миллион страниц в Интернете находит).

monk ★★★★★
()
Ответ на: комментарий от bajex

Что это за ’

Напиши, как на любимом си++ будет литерал со списком. По мне, так лучше '(1 2 3 4), чем std::list<int>({1,2,3,4}).

что это за нелепое определение (lambda (number1 number2) (+ number1 number2)?

Это твоё неосиляторство. Нормальный человек пишет

(map + '(1 2 3 4) '(10 100 1000 10000))
monk ★★★★★
()
Ответ на: комментарий от byko3y

Я прекрасно помню, что там были тесты, где LuaJIT рвёт Си. Не все, но их было более одного. А Ява в среднем втрое медленнее Си и плюсов по тем же тестам. Я не помню, быстрее ли по тем тестам LuaJIT в среднем, чем Ява. Изначально идея соревнования была в том, что одинаковый алгоритм идеоматичным образом реализуется на каждом из языков, и сравнивается именно быстродействие (реализаций) языков. Естественно, что поставщики примеров всё время пытались это правило обойти. Но некоторым это позволялось, а некоторым - нет, и это сразу вызывало вопросы к судье. И понятно, что микробенчмарки (точнее, маленькие кусочки кода, но с большим объёмом данных) не всё показывают. Но лучших тестов я не видел. Вот, допустим, если сравнивать IDE, то тезис «Ява тормозит» вполне очевиден. Как ещё сравнивать программы реального мира, я затрудняюсь сказать - никто не будет ради соревнования писать большую программу на разных языках.

den73 ★★★★★
()
Последнее исправление: den73 (всего исправлений: 1)
Ответ на: комментарий от byko3y

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

den73 ★★★★★
()
Ответ на: комментарий от den73

Если LuaJit в реальной жизни не рвёт Си (всё же странно было бы этого ждать от интерпретатора), но часто рвёт Яву, то версия о том, что LuaJit выкинули ради Явы, вполне с этим согласуется.

den73 ★★★★★
()
Последнее исправление: den73 (всего исправлений: 1)
Ответ на: комментарий от den73

На хабре докшоялта делали парсер и сливлку жсона. Дак вот говнораст сливал luajit, правда с ворованной сишной либой.

А по поводу уровня ресурса даже гадать ненужно - там автор явно фанатик. Достаточно посмотреть на залитый мною revcomp, когда для того, чтобы его удалить он поменял правила задним числом.

При этом, что самое интересное, он был быстрее не поэтому. В любом случа там уже давно фанатики руководствуют тем, что «можно так как в говнорасте - не осилил говнораст что-то - надо запретить».

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

bajex
()
Ответ на: удаленный комментарий

Позорище. Ты уже один раз опозорился и хочешь ещё?

Так я и прошу Великого Гуру написать литерал-список целых чисел в Си++.

monk ★★★★★
()
Ответ на: комментарий от monk

По мне, так лучше ’(1 2 3 4), чем std::list({1,2,3,4})

Ты же в курсе что написал 9 лишних символов в С++?

Вот так тоже валидно:

std::list{1,2,3,4};

https://en.cppreference.com/w/cpp/language/class_template_argument_deduction

https://gcc.godbolt.org/z/bYdhxq5vs

А ещё и от std:: можно избавиться если использовать using.

И вот уже пришли к

list{1,2,3,4};

против

'(1 2 3 4)
fsb4000 ★★★★★
()
Последнее исправление: fsb4000 (всего исправлений: 1)
Ответ на: комментарий от monk

typedef int (*func)(int);
func compose(func f, func g);

В таком виде, конечно, ничего не получится. Win API является примером того, как получится:

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

typedef int(*code)(int, void *);

typedef struct
{
	code code;
	void *data;
} func;

typedef struct
{
	code code1;
	void *data1;
	code code2;
	void *data2;
} composed_data;

int composed_func(int arg, void *data)
{
	composed_data *cdata = (composed_data *)data;
	return cdata->code1(cdata->code2(arg, cdata->data2), cdata->data1);
}

func compose(func f, func g)
{
	composed_data *data = calloc(1, sizeof(composed_data));
	*data = (composed_data) {
		.code1 = g.code, .data1 = g.data,
		.code2 = f.code, .data2 = f.data
	};
	return (func) { .code = composed_func, .data = data };
}

int test_func1(int arg, void *data)
{
	return arg + 1;
}

int test_func2(int arg, void *data)
{
	return arg * 2;
}

int main(void)
{
	func test1 = compose((func) { .code = test_func1 }, (func) { .code = test_func2 });
	func test2 = compose((func) { .code = test_func2 }, (func) { .code = test_func1 });
	printf("test1: %d\n", test1.code(1, test1.data));
	printf("test2: %d\n", test2.code(1, test2.data));
	return 0;
}

test1: 4
test2: 3

В том же Delphi для выполнения подобной задачи вполне себе генерировался машинный код функции, который сам передавал дополнительный аргумент в функцию. Естественно, такой подход непортируем.

На тех ассемблерах, что я знаю переполнение всегда возвращало определённый результат, а разыменование некорректного указателя либо данные по этому адресу (если память доступна), либо прерывание (если не доступна)

В современной многозадачной ОС с защищенным режимом доступ к битому указателю является неопределенным поведением — ты никогда не знаешь результата это операции, потому что страница могла быть высвобождена, но в ней могло оказаться байты из какой-нибудь библиотеки или страниц самой программы. И при этом сама система рандомизирует адреса загрузки модулей, так что от запуска к запуску содержимое памяти оказывается разным.

Так что ты абсолютно одни и те же операции в одном случае называешь определенным поведением, а в другом — неопределенным.

В то время как в Си разыменование некорректного указателя может приводить к выкидыванию проверки после этого разыменования в совсем другом месте ниже по коду. Или возвращение всегда константы вне зависимости от реального значения по тому адресу

Это ты сейчас про вполне конкретных поехавших, пишущих GCC. Из-за которых я свои проекты компилирую только с -fno-strict-aliasing.

byko3y ★★★★
()
Ответ на: комментарий от monk

https://queue.acm.org/detail.cfm?id=2068896
Удобный DSL и возможность вызвать любую лисповую функцию

Проблема здесь в чем... Когда в конце статьи ты получаешь свой чистый и легко читаемый DSL через reader macro — он уже совершенно не похож на Racket. Когда же ты захочешь выйти за пределы узких заранее заданных фич DSL, то ты вываливаешься в совершенно иной язык (Racket), который ты никогда не знал.

Если какая-нибудь корпорация решит раскрутить лисп для веба, будем все писать на нём

«Y Combinator» лисп раскручивало. Чот не получилось. Не получается даже свой вебсайт на лиспе допилить до приемлимого состояния.

byko3y ★★★★
()
Ответ на: комментарий от fsb4000

И вот уже пришли к

Не пришли, потому как никому эта бездарная скриптуха ненужна. В скриптухе это выглядит как [1, 2, 3, 4], потому как никакая типизация ненужна.

Зачем сравнивать нетипизированное тормозное бездарное дерьмао и С++? Кому нужен язык - это нелепое дерьмо '(1 2 3 4) не применим, очевидно.

bajex
()
Ответ на: комментарий от byko3y

Win API является примером того, как получится:

Вот это я и имел в виду. Вместо простого вызова функции получаем кучу косвенной адресации.

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

Это в терминах Си Unspecified behaviour. Оно разное, но вариантов действий всего два: получить какое-то число или получить прерывание ошибки доступа.

А вот если при наличии доступа к битому указателю программа начинает его считать равным любому числу, то это UB.

Как в примере на Си:

int table[4] = {};
bool exists_in_table(int v)
{
    // return true in one of the first 4 iterations or UB due to out-of-bounds access
    for (int i = 0; i <= 4; i++) {
        if (table[i] == v) return true;
    }
    return false;
}

Наличие доступа к table[4] позволяет считать table[4] == v истинным для любого v.

До Си такой идеи не было.

monk ★★★★★
()
Ответ на: комментарий от fsb4000

Ты же в курсе что написал 9 лишних символов в С++?

Теперь в курсе. Я на C++ давно не писал.

monk ★★★★★
()
Ответ на: комментарий от monk

В каком из этих случаев, по-твоему, был Undefined Behavior (то есть произвольное поведение)? На тех ассемблерах, что я знаю переполнение всегда возвращало определённый результат, а разыменование некорректного указателя либо данные по этому адресу (если память доступна), либо прерывание (если не доступна). В то время как в Си разыменование некорректного указателя может приводить к выкидыванию проверки после этого разыменования в совсем другом месте ниже по коду. Или возвращение всегда константы вне зависимости от реального значения по тому адресу. Или вообще всё что угодно.

Что это за нелепая позорная херня? В трактовке си любое подобное действие УБ, даже больше - никакого поведения на уровне си у ассеблера в прицнипе нет.

Опять балабол проигнорировал ответ на эту чушь и продолжил повторять одну и ту же херню.

то есть произвольное поведение

Ну и да, ты в школу уже сходил? Попроси там словарик.

В то время как в Си разыменование некорректного указателя может приводить к выкидыванию проверки после этого разыменования в совсем другом месте ниже по коду. Или возвращение всегда константы вне зависимости от реального значения по тому адресу. Или вообще всё что угодно.

Опять же, балабол перепутал жопу и палец. Си не работает на уровне указателей и ему ничег оне мешает иметь семантику ассеблера.

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

А ту херню, которую ты бездумно за кем-то повторяешь - это не свойство си, а свойство кокнретной интерпретации в компиляторе. При этом вполне себе это поведение даже на урвоне спеки компилятора может быть определено.

Оптимизатор предполагает отсутвие УБ, ты можешь реализовать его иначе и УБ будет значит тоже самое, что в асм.

bajex
()
Ответ на: комментарий от monk

Наличие доступа к table[4] позволяет считать table[4] == v истинным для любого v.
До Си такой идеи не было

Это конченное мудацтво, а не проблема языка Си. У первых реализаций Си таких проблем не было. Я называю это «некорректная оптимизация». В классическом Си чтение за пределами буфера приводит к... чтению за пределами буфера. Не больше и не меньше. Потому что программиста может захотеть приводить типы, и чтение за пределами буфера на самом деле будет чтением в пределах онного, но тупой компилятор этого еще не понимает.

byko3y ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.