Здравствуйте, Qbit86, Вы писали:
Q>Нет, это параметеры дженерика. В пользовательском графе веса рёбер могут быть int'ами, decimal'ами, Complex'ами, кастомными типами — чем угодно, заранее неизвестно. Мне нужно абстрагироваться от мономорфных плюсиков.
Ну вот я ровно об этом вам и говорю — то, чего мы хотим, так это чтобы AddAll(TWeight<double>[] weights) работал не хуже, чем AddAll(double[] weights).
Не имеет никакого смысла рассуждать о том, что AddAll(TWeight<double>[] weights, Func<TWeight<double>, TWeight<double>, TWeight<double>> add, TWeight<double> zero) работает хуже, чем AddAll(TWeight<double>[] weights, IMonoid<TWeight<double>> add). Если нас беспокоит производительность, то оба — отстой. Если не беспокоит, то и первого достаточно.
S>>Ну так он же справедлив. В конце концов мы выкидываем не только делегатов, но и интерфейсы, сворачивая цепочку map/reduce в конкретный метод, который вычисляет конкретное замыкание над конкретной коллекцией. Q>Так ведь нет конкретной коллекции. Речь про написание библиотечного кода, который работает с любыми типами. В момент написания кода ещё не известны типы конечного пользователя. Нет такой альтернативы как «обычный нативный код сложения и умножения».
Вот именно об этом и речь. У нас есть чудесная библиотека, которая описывает поиск минимального пути на графе в терминах другой чудесной библиотеки универсальной агрегации и удачно описанных моноидов.
И это чудесно работает в proof of concept. А при переезде в продакшн конечные пользователи чертыхаются и заменяют всю эту кунсткамеру на плоский FindShortestPath с double и встроенными операциями; а потом ещё и переписывают на SIMD.
Потому что у них-то типы уже известны. Проблема как раз в том, что рантайм и язык плохо выполняют специализацию и её приходится выполнять вручную.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.