Size: a a a

2021 August 18

f

for(int c; (c = getc... in ru.nim.talks
К тому же я могу любой момент написать процедуру которая будет обрабатывать все подтипы, в то вместо как для ООП мне нужно ... мне кажется это невозможно, если нет метода в корневом объекте.
источник

VB

Vladimir Berezenko in ru.nim.talks
не совсем так. ты в большинстве случаев не будешь вообще знать и думать о том что тебе надо сделать выбор.
источник

f

for(int c; (c = getc... in ru.nim.talks
Как вызов функции через указатель может быть быстрее чем switch/case/goto
источник

f

for(int c; (c = getc... in ru.nim.talks
Но зато я не могу обработать несколько одинаковых подтипов в одной ветке. Точнее могу, но тогда мне нужно объединить эти подтипы в ещё один уровень иерархит
источник

f

for(int c; (c = getc... in ru.nim.talks
А если мне нужно в одном месте так сгруппировать, в другом по другому то все ещё хуже
источник

VB

Vladimir Berezenko in ru.nim.talks
конечно быстрее. там 1 взятие указателя и один call, заместо взятия типа, взятия смещения по типу, взятия указателя из таблицы смещений и перехода по нему.
источник

VB

Vladimir Berezenko in ru.nim.talks
везде есть свои минусы, но с пока с теми типами которые в ним минусов несколько больше. через извращения с генриками это решается конечно, но это прям извращения.
источник

f

for(int c; (c = getc... in ru.nim.talks
эм. я не совсем понял откуда взялось "взятия типа, взятия смещения по типу, взятия указателя из таблицы смещений и перехода по нему."
источник

f

for(int c; (c = getc... in ru.nim.talks
мы делаем

  switch (T3_.kind) {
 case ((tyEnum_En__kgtyqvXHOJz0vapOBw2jDw) 0):
 {
   nimln_(21, "/tmp/q/hello.nim");
   echoBinSafe(TM__xLHv575t3PG1lB5wK05Xqg_7, 1);
 }
 break;
 default:
 {
 }
 break;
 }
источник

f

for(int c; (c = getc... in ru.nim.talks
case Sum().kind:
 of a:
   echo 1

 else:
   discard
источник

VB

Vladimir Berezenko in ru.nim.talks
а как? строится таблица переходов и в зависимости от пришедшего значения из таблицы берётся адрес перехода. вариант с кучей if/elif ещё медленней.
источник

VB

Vladimir Berezenko in ru.nim.talks
вот как-раз этот С-код и превращается в таблицу переходов.
источник

VB

Vladimir Berezenko in ru.nim.talks
вот поэтому весьма сложно делать такие штуки со сложными типами, т.к. каким-то образом надо делать соотношение значение->адрес перехода.
источник

f

for(int c; (c = getc... in ru.nim.talks
Если использовать вариант бенчмарка из https://github.com/status-im/nimbus-eth1/wiki/Interpreter-optimization-resources#nim-implementation-benchmark , то получается что

name ............................... min time      avg time    std dv   runs
Cxx ops ........................... 10.063 ms     11.153 ms    ±0.379   x447
Nim ops ........................... 10.041 ms     11.293 ms    ±0.254   x444

через switch скорость такая же или выше чем на методах.

Код на С++ https://github.com/haxscramper/hack/blob/master/testing/nim/c_interop/cpp_tests/cxx_opcodes.hpp

Ним https://github.com/haxscramper/hack/blob/master/testing/nim/c_interop/cpp_tests/switch_vs_dispatch.nim

Бенчмарк через https://github.com/treeform/benchy

Компилировалось через

--backend:cpp
--nimcache:cache
--overflow_checks:off
-d:release
-d:danger

Если
убрать релиз/danger то цифры

name ............................... min time      avg time    std dv   runs
Cxx ops ........................... 17.738 ms     19.233 ms    ±0.445   x261
Nim ops ........................... 26.537 ms     28.248 ms    ±0.626   x177

Что понятно, так как в коде для нима добавляется куча проверок и т.д.

Если еще сравнить просто с seq[OpcNim] то получается

name ............................... min time      avg time    std dv   runs
Cxx ops ............................ 9.615 ms     10.699 ms    ±0.347   x469
Nim ops ............................ 9.896 ms     10.923 ms    ±0.355   x458
Nim ops val ........................ 8.789 ms      9.914 ms    ±0.337   x507
источник

f

for(int c; (c = getc... in ru.nim.talks
источник

f

for(int c; (c = getc... in ru.nim.talks
К вопросу о читаемости

struct Opc {
   virtual void eval(int* result) = 0;
};
struct OpcInc : Opc {
   void eval(int* result) {
       ++(*result);
   }
};
struct OpcDec : Opc {
   void eval(int* result) {
       --(*result);
   }
};
struct OpcMul2 : Opc {
   void eval(int* result) {
       (*result) *= 2;
   }
};
struct OpcDiv2 : Opc {
   void eval(int* result) {
       (*result) /= 2;
   }
};
struct OpcAdd7 : Opc {
   void eval(int* result) {
       (*result) += 7;
   }
};
struct OpcNeg : Opc {
   void eval(int* result) {
       (*result) = -(*result);
   }
};


vs

type
 OpcNimKind = enum
   Inc  # = 0x0100
   Dec  # = 0x0110
   Mul2 # = 0x0230
   Div2 # = 0x0240
   Add7 # = 0x0307
   Neg  # = 0x0400

 OpcNim = object
   kind: OpcNimKind


proc eval(opc: OpcNim, result: ptr cint) =
 case opc.kind:
   of Inc:  inc result[]
   of Dec:  dec result[]
   of Mul2: result[] *= 2
   of Div2: result[] = result[] div 2
   of Add7: inc result[], 7
   of Neg:  result[] = -result[]
источник

f

for(int c; (c = getc... in ru.nim.talks
На идеальную методику бенчмарка не претендую, но результаты мне все же кажутся логичными, так как вызов метода через vtable, несмотря на все оптимизации, все же не может быть быстрее чем просто тупая таблица переходов,
источник

f

for(int c; (c = getc... in ru.nim.talks
А так скорость практически одинаковая, и если учесть что вариант с seq[T] невозможен для вариантов с методом в общем случае то получается что над скоростью диспетчиризации все же можно не трястись так
источник

VB

Vladimir Berezenko in ru.nim.talks
ну у меня несколько по другому результаты получились:
qmaster$ ./a.out
min: 7.114ms, mean: 7.672ms (607 runs, 1 loops each)
qmaster$ ./test
name ............................... min time      avg time    std dv   runs
Cxx ops ............................ 7.758 ms      8.208 ms    ±0.280   x603
Nim ops ............................ 7.415 ms      7.844 ms    ±0.269   x630
Nim ops val ........................ 6.149 ms      6.529 ms    ±0.256   x758
источник

VB

Vladimir Berezenko in ru.nim.talks
первое чистый С++-11
источник