Подтвердить что ты не робот

Можно ли сравнить два блока Objective-C по содержанию?

float pi = 3.14;
float (^piSquare)(void) = ^(void){ return pi * pi; };
float (^piSquare2)(void) = ^(void){ return pi * pi; };

[piSquare isEqualTo: piSquare2]; // -> want it to behave like -isEqualToString...
4b9b3361

Ответ 1

Чтобы расширить ответ Лорана.

Блок - это комбинация реализации и данных. Для того, чтобы два блока были равными, они должны были иметь как ту же самую реализацию, либо захватить одни и те же данные. Таким образом, сравнение требует сравнения как реализации, так и данных.

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

Сравнивая простые данные достаточно просто, блоки могут захватывать объекты, включая объекты С++ (которые могут когда-нибудь работать) - и сравнение может или не обязательно учитывать это. Наивная реализация просто выполнила бы сравнение уровня байтов содержимого. Однако, возможно, также захочется проверить равенство объектов с помощью компараторов уровня объекта.

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

Все это означает, что нет, в настоящее время невозможно сравнить блоки и изложить некоторые причины. Если вы считаете, что это было бы полезно, сообщите об ошибке через http://bugreport.apple.com/ и укажите пример использования.

Ответ 2

Отбрасывая проблемы с реализацией компилятора и языковым дизайном, то, что вы просите, доказуемо неразрешимо (если только вы не заботитесь об обнаружении 100% идентичных программ). Решение о том, выполняет ли две программы одну и ту же функцию, эквивалентно решению проблемы остановки. Это классическое следствие теоремы Риса: любое "интересное" свойство машин Тьюринга неразрешимо, где "интересно" просто означает, что оно истинно для некоторых машин и ложно для других.

Просто для удовольствия, здесь доказательство. Предположим, что мы можем создать функцию, чтобы решить, эквивалентны ли два блока EQ (b1, b2). Теперь мы будем использовать эту функцию для решения проблемы с остановкой. Мы создаем новую функцию HALT (M, I), которая говорит нам, что машина Тьюринга M остановится на входе я так:

BOOL HALT(M,I) {
  return EQ(
    ^(int) {return 0;},
    ^(int) {M(I); return 0;}
  );
}

Если M (I) останавливается, то блоки эквивалентны, поэтому HALT (M, I) возвращает YES. Если M (I) не останавливается, то блоки не эквивалентны, поэтому HALT (M, I) возвращает NO. Обратите внимание, что нам не нужно выполнять блоки - наша гипотетическая функция EQ может вычислить их эквивалентность, просто взглянув на них.

Мы решили проблему остановки, которая, как мы знаем, невозможна. Поэтому EQ не может существовать.

Ответ 3

Я не думаю, что это возможно. Блоки можно рассматривать как расширенные функции (с доступом к глобальным или локальным переменным). Точно так же, как вы не можете сравнивать содержимое функций, вы не можете сравнивать содержимое блоков.

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