Быстрый оператор apply вместо функции Eval
Я уже писал про использование функции Eval. Главная её практическая польза - возможность использования (динамического встраивания) в алгоритме некоторого выражения переданного в виде объекта из другого места. Это работает, но замедляет выполнение примерно на 65%. Это происходит потому, что Eval это функция, и на её вызов уходит некоторое время. Поэтому я сделал специальный оператор apply (и apply$), который, как и Eval, выполняет выражение из переменной, но без возможности возврата значения. Переделал ранее показанный пример с Eval под apply.
int[] arr=new int[]{5, 6, 7};
object someExpr=GetExpr(); //получаем выражение
ForAllElements(arr, someExpr); //передаём в функцию массив, который нужно изменить, и выражение
WriteLine(Join(' ', arr)); //15 16 17 - к каждому элементу прибавилось 10
ReadKey();
int[] ForAllElements(int[] arr, object e){
//эта функция для каждого индекса элемента массива выполняет выражение, которое меняет значение элемента
foreach(int index in Range(arr.Length()))
apply$ e; //apply$ выполняет выражение arr[index]+=10 в текущем контексте
//можно и apply использовать, но в цикле будет работать медленнее
}
object GetExpr(){
//эта функция создаёт выражение с массивом и индексом
int[] arr;
int index;
return Expr(arr[index]+=10); //суть выражения - прибавление к элементу числа 10
}
Отличаются apply и apply$ тем, что последний кеширует значение переменной с выражением (не результат вычисления, а только ссылку на выражение), а apply каждый раз считывает его заново. Поэтому apply$ работает быстрее, когда применяется в цикле. Если apply замедляет работу на 29%, то apply$ всего на 3%. Но нужно понимать, что apply$ всегда выполняет то выражение, которое выполнил в первый раз, и изменение выражения в переменной-аргументе не повлияет на его работу. Вне циклов лучше apply потому, что при одиночном вызове кэширование является лишним.
Я называю apply оператором, но это не такой оператор как + и другие, а более низкоуровневый, как if, for, goto, throw. Это всё statements (инструкции), которые работают на уровне логической строки кода, и их нельзя использовать в выражениях.
