Точечная нотация и нотация сообщений для объявленных свойств

81

Теперь у нас есть "точечная" запись свойств. Я видел различные спины и Фортов о достоинствах точечной нотации против сообщения нотации. Чтобы не запятнать ответы, я не собираюсь отвечать в этом вопросе.

Что вы думаете о точечной нотации и нотации сообщений для доступа к свойствам?

Пожалуйста, постарайтесь сосредоточить внимание на Objective-C - мое единственное предубеждение, которое я изложу, заключается в том, что Objective-C - это Objective-C, поэтому ваше предпочтение, чтобы оно было похоже на Java или JavaScript, недопустимо.

Допустимые комментарии касаются технических вопросов (порядок операций, приоритет приведения, производительность и т. Д.), Ясности (структура против характера объекта, как за, так и против!), Краткости и т. Д.

Обратите внимание: я принадлежу к школе строгого качества и удобочитаемости кода, так как работал над огромными проектами, где соглашение и качество кода имеют первостепенное значение (парадигма «запись один раз прочитала тысячу раз»).

сурок
источник
14
+1 это отличный вопрос, и вы получите много противоречивых ответов. =)
Дэйв Делонг
1
Редактор исходного кода должен подстраиваться под личные предпочтения программиста, не изменяя символы самого файла. Так каждый получит то, что ему нравится.
Арне Эвертссон

Ответы:

64

Не используйте точку для обозначения поведения. Используйте точку для доступа или установки атрибута, такого как материал, обычно атрибутов, объявленных как свойства.

x = foo.name; // good
foo.age = 42; // good

y = x.retain; // bad

k.release; // compiler should warn, but some don't. Oops.

v.lockFocusIfCanDraw; /// ooh... no. bad bad bad

Для новичков в Objective-C я бы рекомендовал не использовать точку ни для чего, кроме вещей, объявленных как @property. Как только вы почувствуете язык, делайте то, что считаете правильным.

Например, я считаю совершенно естественным следующее:

k = anArray.count;
for (NSView *v in myView.subviews) { ... };

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

бомж
источник
18
Вау, я даже не знал, что вы можете использовать синтаксис с точкой для чего-либо, кроме свойств. Цвет меня удивил! (Но я согласен, точка должна использоваться только для свойств)
jbrennan
13
Это неверно. Точечная запись является прямым синонимом вызова эквивалентного метода; ни больше ни меньше.
bbum
2
Интересно, почему точечная нотация не была ограничена аксессуарами, объявленными @ property. Похоже, что это позволило бы авторам классов разрешить серые области, в которых методы должны быть разрешены в точечной нотации, и не было бы столь неоднозначно использовать такие методы, как .uppercaseStringесли бы классу было разрешено выражать свое намерение и иметь его обеспечивается компилятором. Возможно, мне не хватает чего-то, что требует текущей реализации точечной записи.
4
Его можно было ограничить @propertyтолько, но это потребовало бы от потребителя API изучения другого логического измерения информации и от разработчиков API, которые, скорее всего, утонули в спорах о том, что должно и не должно быть @property. Обратите внимание, что Xcode предпочитает - более серьезно - @propertyподразумеваемые методы при завершении кода ... Это приветствуется, но не применяется.
bbum 05
1
@rodamn Это действительно ответ; он рекомендует использовать точку с @propertyобъявленными средствами доступа только тогда, когда вы новичок в языке. По мере того, как человек приобретает уверенность в программировании на Objective-C, делайте то, что считаете правильным. Интересно; многие из нас вернулись к очень ограниченному использованию точки.
bbum
22

Позвольте мне начать с того, что я начал программировать на Visual / Real Basic, а затем перешел на Java, поэтому я довольно привык к синтаксису точек. Однако когда я наконец перешел на Objective-C и привык к скобкам, а затем увидел введение Objective-C 2.0 и его точечный синтаксис, я понял, что мне это действительно не нравится. (для других языков нормально, потому что так катят).

У меня есть три основных недостатка с точечным синтаксисом в Objective-C:

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

something.frame.origin.x = 42;

Тогда я получу ошибку компилятора, потому что somethingэто объект, и вы не можете использовать структуры объекта в качестве lvalue выражения. Однако, если у меня есть:

something.frame.origin.x = 42;

Тогда это компилируется нормально, потому somethingчто сама структура имеет член NSRect, и я могу использовать ее как lvalue.

Если бы я использовал этот код, мне бы пришлось потратить некоторое время, пытаясь понять, что это somethingтакое. Это структура? Это объект? Однако, когда мы используем синтаксис скобок, он становится намного яснее:

[something setFrame:newFrame];

В этом случае нет никакой двусмысленности, somethingявляется ли объект объектом или нет. Введение двусмысленности - моя претензия №1.

Говядина №2: в C синтаксис с точкой используется для доступа к членам структур, а не для вызова методов. Программисты могут переопределить setFoo:и fooМетоды объектов, но до сих пор доступ к ним через something.foo. На мой взгляд, когда я вижу выражения, использующие точечный синтаксис, я ожидаю, что они будут простым назначением в ivar. Это не всегда так. Рассмотрим объект контроллера, который является посредником между массивом и табличным представлением. Если бы я позвонил , то подумал бы: «Ага, метод. Мне нужно посмотреть определение этого метода, чтобы убедиться, что я знаю, что он делает».myController.contentArray = newArray; , я ожидаю, что он заменит старый массив новым. Однако исходный программист мог setContentArray:не только установить массив, но и перезагрузить табличное представление. Судя по строке, нет никаких указаний на такое поведение. Если бы я увидел[myController setContentArray:newArray];

Итак, я думаю, что мое резюме Beef # 2 состоит в том, что вы можете переопределить значение синтаксиса точки с помощью специального кода.

Говядина №3: Я думаю, это плохо выглядит. Как программист Objective-C, я полностью привык к синтаксису в скобках, так что читать и видеть строки и строки красивых скобок, а затем внезапно ломаться с и foo.name = newName; foo.size = newSize;т.д. меня немного отвлекает. Я понимаю, что для некоторых вещей требуется точечный синтаксис (структуры C), но это единственный раз, когда я их использую.

Конечно, если вы пишете код для себя, используйте то, что вам удобно. Но если вы пишете код, который планируете использовать с открытым исходным кодом, или пишете что-то, что не ожидаете поддерживать вечно, я настоятельно рекомендую использовать синтаксис скобок. Это, конечно, только мое мнение.

Недавнее сообщение в блоге против синтаксиса точки: http://weblog.bignerdranch.com/?p=83

Опровержение вышеуказанного сообщения: http://eschatologist.net/blog/?p=226 (с оригинальной статьей в пользу синтаксиса с точкой: http://eschatologist.net/blog/?p=160 )

Дэйв Делонг
источник
5
Говядина №1 мне кажется немного простоватой. Я не понимаю, почему это беспокоит вас больше, чем вы можете попытаться отправить сообщение в структуру, а затем выяснить, что переменная на самом деле является структурой. Вы действительно видите, что многие люди, которые понимают, как это работает, на практике сбиваются с толку? Это похоже на то, что вы однажды напутаете, узнаете об lvalue, а затем сделаете это правильно в будущем - точно так же, как, скажем, не пытаться рассматривать NSNumbers как int.
Чак
2
@Chuck - это своего рода крайний случай, но я довольно много занимаюсь разработкой контрактов, которая включает в себя наследование проектов и необходимость работы с ними. Обычно something это объект, но я встречал пару мест, где оригинальные авторы создавали структуры (для скорости, меньшего использования памяти и т. Д.), И мне нужно потратить пару минут, пытаясь понять, почему код не работает. t компилировать.
Дэйв Делонг,
14

Я новый разработчик Cocoa / Objective-C, и мое мнение таково:

Я придерживаюсь нотации сообщений, хотя я начал с Obj-C 2.0, и хотя точечная нотация кажется мне более знакомой (Java - мой первый язык). Причина этого довольно проста: я до сих пор не совсем понимаю почему они добавили в язык точечную нотацию. Мне это кажется ненужным, «нечистым» дополнением. Хотя, если бы кто-нибудь мог объяснить, какую пользу это приносит языку, я был бы рад это услышать.

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

Элли П.
источник
2
+1 отличный ответ. Я действительно хотел бы знать, почему это стоит за этим. Возможно bbum или mmalc знает ответ ... (они оба работают в )
Дэйв Делонг,
11

Точечная нотация Objective-C - это синтаксический сахар, который переводится в нормальную передачу сообщений, поэтому внутренне ничего не меняет и не имеет значения во время выполнения. Точечная запись абсолютно не быстрее передачи сообщений.

После этого нужна небольшая преамбула, вот плюсы и минусы, которые я видел:

Плюсы и минусы точечной записи

  • профи

    • читаемость: точечная нотация легче читается, чем передача вложенных скобок
    • Это упрощает взаимодействие с атрибутами и свойствами: используя точечную нотацию для свойств и нотацию сообщений для методов, вы можете добиться разделения состояния и поведения на уровне синтаксиса.
    • Можно использовать составной оператор присваивания (1) .
    • используя @propertyнотацию и точечную нотацию, компилятор сделает за вас много работы, он может сгенерировать код для хорошего управления памятью при получении и установке свойства; Вот почему точечная нотация предлагается в официальных руководствах самой Apple.
  • минусы

    • Точечная запись разрешена только для доступа к заявленному @property
    • Поскольку Objective-C является уровнем выше стандарта C (расширение языка), точечная нотация на самом деле не проясняет, является ли объект, к которому осуществляется доступ, объектом или структурой. Часто кажется, что вы обращаетесь к свойствам структуры.
    • вызов метода с точечной нотацией, которую вы теряете преимущества читаемости именованных параметров
    • когда смешанная нотация сообщений и точечная нотация кажется, что вы кодируете на двух разных языках

Примеры кода:

(1) Пример кода использования составного оператора:

//Use of compound operator on a property of an object
anObject.var += 1;
//This is not possible with standard message notation
[anObject setVar:[anObject var] + 1];
алерут
источник
7

Лучшим советом здесь является использование стиля языка, соответствующего самому языку. Однако это не относится к написанию функционального кода в объектно-ориентированной системе (или наоборот), и точечная нотация является частью синтаксиса в Objective-C 2.0.

Любая система может быть использована неправильно. Существования препроцессора во всех языках, основанных на C, достаточно, чтобы делать действительно довольно странные вещи; просто посмотрите на Contest Obfuscated C если вам нужно точно понять, насколько странным он может быть. Означает ли это, что препроцессор автоматически становится плохим и вам никогда не следует его использовать?

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

Доступ к собственности может иметь побочные эффекты. Это ортогонально синтаксису, используемому для получения этого свойства. CoreData, делегирование, динамические свойства (first + last = full) - все это обязательно выполняет некоторую скрытую работу. Но это привело бы к путанице «переменные экземпляра» со «свойствами» объекта. Нет причин, по которым свойства должны обязательно храниться как есть, особенно если они могут быть вычислены (например, длина строки). Так что независимо от того, используете ли вы foo.fullName или [foo fullName], все равно будет динамическая оценка.

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

В конечном итоге, все сводится к вопросу «похоже ли это на структуру». Это, вероятно, основная разница в дебатах до сих пор; если у вас есть структура, она работает иначе, чем если бы у вас есть объект. Но это всегда было правдой; вы не можете отправить структуру сообщения, и вам нужно знать, на основе стека или ссылки / malloc. Уже существуют ментальные модели, которые различаются по использованию ([[CGRect alloc] init] или struct CGRect?). Они никогда не были едины в поведении; вам нужно знать, с чем вы имеете дело в каждом конкретном случае. Добавление обозначения свойств для объектов вряд ли запутает любого программиста, который знает, каковы их типы данных; а если нет, то у них проблемы посерьезнее.

Что касается последовательности; (Цель-) C противоречиво внутри себя. = используется как для присваивания, так и для равенства в зависимости от лексической позиции в исходном коде. * используется для указателей и умножения. BOOL - это символы, а не байты (или другое целочисленное значение), несмотря на то, что YES и NO равны 1 и 0 соответственно. Последовательность или чистота - это не то, для чего был разработан язык; это было о том, чтобы добиться цели.

Так что, если вы не хотите его использовать, не используйте его. Сделайте это по-другому. Если вы хотите его использовать и понимаете, это нормально, если вы им воспользуетесь. Другие языки имеют дело с концепциями общих структур данных (карты / структуры) и типов объектов (со свойствами), часто используя один и тот же синтаксис для обоих, несмотря на то, что один является просто структурой данных, а другой - многофункциональным объектом. Программисты на Objective-C должны иметь эквивалентные способности, чтобы иметь дело со всеми стилями программирования, даже если они вам не нравятся.

AlBlue
источник
6

Я использую его для свойств, потому что

for ( Person *person in group.people){ ... }

читать немного легче, чем

for ( Person *person in [group  people]){ ... }

во втором случае читаемость прерывается, когда ваш мозг переводится в режим отправки сообщений, тогда как в первом случае ясно, что вы получаете доступ к свойству people объекта группы.

Я также буду использовать его при изменении коллекции, например:

[group.people addObject:another_person];

немного читабельнее, чем

[[group people] addObject:another_person];

Акцент в этом случае должен быть сделан на добавлении объекта в массив вместо объединения двух сообщений.

ребо
источник
5

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

Мне также нравится точечный синтаксис, потому что он заставляет меня чувствовать, что я обращаюсь к свойству объекта, а не просто отправляю ему сообщение (конечно, точечный синтаксис действительно переводится в отправку сообщения, но для внешнего вида , точка ощущается иначе). Вместо того, чтобы «вызывать геттер» по старому синтаксису, мне кажется, что я напрямую получаю что-то полезное от объекта.

Некоторые дискуссии по этому поводу связаны с тем, что «Но у нас уже есть точечный синтаксис, и он для structs!». И это правда. Но (и опять же, это чисто психологически) я чувствую то же самое. Доступ к свойству объекта с использованием точечного синтаксиса ощущается так же, как доступ к члену структуры, что более или менее является предполагаемым эффектом (на мой взгляд).

**** Изменить: как указал bbum, вы также можете использовать точечный синтаксис для вызова любого метода объекта (я не знал об этом). Поэтому я скажу, что мое мнение о синтаксисе точек предназначено только для работы со свойствами объекта, а не для повседневной отправки сообщений **

Джбреннан
источник
3

Я предпочитаю синтаксис обмена сообщениями ... но только потому, что я этому научился. Учитывая, что многие из моих классов и те, что не относятся к стилю Objective-C 1.0, я бы не хотел смешивать их. У меня нет реальной причины, кроме «того, к чему я привык», чтобы не использовать точечный синтаксис ... КРОМЕ этого, это сводит меня с ума

[myInstance.methodThatReturnsAnObject sendAMessageToIt]

Не знаю почему, но меня это действительно бесит, без уважительной причины. Я просто думаю, что делаю

[[myInstance methodThatReturnsAnObject] sendAMessageToIt]

читабельнее. Но каждому свое!

Микму
источник
3
Я делаю это время от времени, но только если получаю доступ к собственности. Например: [self.title lowercaseString]что ли. Но стилистически я вижу, почему смешивать и согласовывать синтаксис утомительно. Единственная причина, по которой я это делаю, - это четко понимать, что такое свойство, а что метод, возвращающий объект (я знаю, что свойства - это всего лишь свойства, но, надеюсь, вы понимаете, о чем я).
jbrennan 08
3

Честно говоря, я думаю, дело в стиле. Я лично против точечного синтаксиса (особенно после того, как только узнал, что вы можете использовать его для вызовов методов, а не только для чтения / записи переменных). Однако, если вы собираетесь его использовать, я настоятельно рекомендую не использовать его для чего-либо, кроме доступа к переменным и их изменения.


источник
3

Одним из основных преимуществ объектно-ориентированного программирования является отсутствие прямого доступа к внутреннему состоянию объектов.

Мне кажется, что точечный синтаксис - это попытка создать впечатление, будто к состоянию осуществляется прямой доступ. Но на самом деле это просто синтаксический сахар над поведением -foo и -setFoo :. Лично я предпочитаю называть вещи своими именами. Точечный синтаксис способствует удобочитаемости в той степени, в которой код более лаконичен, но он не помогает пониманию, потому что игнорирование того, что вы действительно вызываете -foo и -setFoo:, может означать проблемы.

Мне кажется, что синтезированные аксессоры - это попытка упростить запись объектов, к состоянию которых осуществляется прямой доступ. Я считаю, что это способствует созданию именно такого типа программ, для предотвращения которого создавалось объектно-ориентированное программирование.

В целом, я бы предпочел точечный синтаксис и свойства, которые никогда не вводились. Раньше я мог говорить людям, что ObjC - это несколько чистых расширений для C, чтобы сделать его более похожим на Smalltalk, и я больше не думаю, что это правда.

шляпник
источник
2

На мой взгляд, точечный синтаксис делает Objective-C менее похожим на Smalltalk. Код может выглядеть проще, но добавляет двусмысленности. Это struct, unionили объект?

мечта
источник
2

Многие люди, кажется, путают «свойства» с «переменными экземпляра». Я думаю, что смысл свойств состоит в том, чтобы сделать возможным изменение объекта без необходимости знать его внутреннее устройство. Переменная экземпляра в большинстве случаев является «реализацией» свойства (которое, в свою очередь, является «интерфейсом»), но не всегда: иногда свойство не соответствует ivar, а вместо этого вычисляет возвращаемое значение. на лету'.

Вот почему я считаю, что идея о том, что «точечный синтаксис обманывает вас, заставляя думать, что вы обращаетесь к переменной, так что это сбивает с толку», неверна. Точка или скобка, вы не должны делать предположений о внутреннем устройстве: это свойство, а не ivar.

Николас Миари
источник
В качестве побочного примечания, ссылки на объекты Objective-C не являются прямыми переменными структур C, а скорее похожи на «указатели на структуры», поэтому точечный синтаксис не имеет смысла для прямого доступа к членам; это оператор стрелки, ->который выполняет эту роль (конечно, если доступ к указанным ivars не ограничен).
Николас Миари
1

Я думаю, что мог бы переключиться на обмен сообщениями вместо точечной нотации, потому что в моей голове object.instanceVar - это просто instanceVar , принадлежащий объекту , для меня это совсем не похоже на вызов метода , что есть, поэтому может быть что-то on в вашем методе доступа и от того, используете ли вы instanceVar или self.instanceVar, может быть гораздо больше различий, чем просто неявное или явное. Просто мои 2 цента.

mk12
источник
1

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

NSView *myView = ...;
myView.frame.size.width = newWidth;

Выглядит хорошо. Но нет. Это то же самое, что и

[myView frame].size.width = newWidth;

что не работает. Компилятор принимает первое, но по праву не принимает второе. И даже если он сначала выдал ошибку или предупреждение, это просто сбивает с толку.

Свен
источник
1

Назовите меня ленивым, но если бы мне пришлось напечатать сингл '.' по сравнению с двумя [] каждый раз, чтобы получить те же результаты, я бы предпочел сингл. Я ненавижу многословные языки. () В lisp сводил меня с ума. Элегантный язык, такой как математика, краток и эффективен, все остальные не оправдывают ожиданий.

Джо
источник
1
Проблема в том, что математика, хотя и краткая и эффективная, не является обычным языком, и поэтому мы не можем ее проанализировать и скомпилировать. Обратите внимание, например, что в математических функциях их часто пишут в круглых скобках, потому что без них было бы намного труднее следовать.
jbrennan
1

Используйте точечную нотацию (когда можете)

В методах экземпляра, возвращающих некоторое значение

Не используйте точечную нотацию

В методах экземпляра, возвращающих void, в методах инициализации или в методе класса.

И мое личное любимое исключение

NSMutableArray * array = @[].mutableCopy;
Николя Манзини
источник
0

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

Причина, по которой я не использую их в коде, заключается в том, что точечная нотация скрывает семантику установщика. Установка свойства в точечной нотации всегда выглядит как присваивание независимо от семантики установщика (присваивать / сохранять / копировать). Использование нотации сообщения делает видимым, что принимающий объект имеет контроль над тем, что происходит в установщике, и подчеркивает тот факт, что эти эффекты необходимо учитывать.

Я все еще обдумываю, могу ли я использовать точечную нотацию при извлечении значения KVC-совместимого или объявленного свойства, потому что оно, по общему признанию, немного более компактно и читабельно и не имеет скрытой семантики. Сейчас я придерживаюсь обозначения сообщений для единообразия.

VoidPointer
источник
1
Там все еще могут быть скрытые вещи. Получатель может делать и другие вещи, кроме простого возврата переменной экземпляра. Даже если это объявленное свойство, геттер не нужно синтезировать, иначе он мог быть переопределен в подклассе.
Sven
-1

Хорошо, точечная запись в Objective-C действительно выглядит странно. Но без него я до сих пор не могу:

int width = self.frame.size.width;

Работает нормально, но:

int height = [[[self frame] size] height];

Выдает мне «Невозможно преобразовать в тип указателя». Однако мне бы очень хотелось, чтобы мой код выглядел согласованным с нотацией сообщений.

Vegetus '78
источник
5
-frame возвращает NSRect, который является структурой C, а не объектом Objective-C. Вот почему второй пример вызывает ошибку компилятора. Это должно быть: int height = [self frame] .size.height;
1
Согласовано. Но точка после скобки выглядит ужасно! Обычно я сначала сохраняю прямоугольник в локальной переменной.
Николас Миари
-2

Это отличный вопрос, и я вижу много разных ответов на него. Хотя многие затронули эти темы, я постараюсь ответить на это под другим углом (некоторые могли сделать это неявно):

Если мы используем нотацию «точка», разрешение цели для метода выполняется во время компиляции. Если мы используем передачу сообщений, разрешение цели откладывается до выполнения во время выполнения. Если цели решаются во время компиляции, выполнение происходит быстрее, так как разрешение целей во время выполнения включает несколько накладных расходов. (Не то чтобы разница во времени будет иметь большое значение). Поскольку мы уже определили свойство в интерфейсе объекта, нет смысла отличать разрешение цели для свойства от времени выполнения, и, следовательно, точечная нотация - это обозначение, которое мы должны использовать для доступа к свойству.

Jas
источник
Знаете ли вы, что в ObjectiveC селекторы в любом случае оцениваются, разрешаются и вызываются во время выполнения? Следовательно, точечная запись - это чистый синоним старого стиля скобок. Никаких технических отличий нет. Ваши предположения о скорости совершенно неверны - попробуйте, используйте инструменты и убедитесь сами.
до