Можно ли сравнить два блока Objective-C по содержимому? - PullRequest
18 голосов
/ 30 января 2010
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...

Ответы [ 3 ]

26 голосов
/ 30 января 2010

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

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

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

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

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

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

13 голосов
/ 01 февраля 2010

Оставляя в стороне вопросы реализации компилятора и языкового дизайна, вы просите: доказуемо неразрешимо (если только вы не заботитесь только об обнаружении 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 может вычислить их эквивалентность, просто взглянув на них.

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

4 голосов
/ 30 января 2010

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

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

...