Точечная запись и запись сообщения для объявленных свойств - PullRequest
81 голосов
/ 08 августа 2009

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

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

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

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

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

Ответы [ 19 ]

64 голосов
/ 08 августа 2009

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

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) { ... };

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

22 голосов
/ 08 августа 2009

Позвольте мне начать с того, что я начал программировать на 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.

Beef # 2: В C точечный синтаксис используется для доступа к членам структур, а не к вызовам методов. Программисты могут переопределять методы setFoo: и foo объектов, но при этом получать к ним доступ через something.foo. По-моему, когда я вижу выражения, использующие точечный синтаксис, я ожидаю, что они будут простым назначением в ивар. Это не всегда так. Рассмотрим объект контроллера, который является посредником массива и табличного представления. Если я вызову 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)

14 голосов
/ 08 августа 2009

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

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

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

11 голосов
/ 29 апреля 2012

Точечная запись 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 голосов
/ 09 августа 2009

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

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

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

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

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

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

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

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

6 голосов
/ 10 августа 2009

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

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

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

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

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

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

[group.people addObject:another_person];

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

[[group people] addObject:another_person];

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

5 голосов
/ 08 августа 2009

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

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

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

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

3 голосов
/ 23 августа 2009

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

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

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

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

3 голосов
/ 09 августа 2009

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

3 голосов
/ 08 августа 2009

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

[myInstance.methodThatReturnsAnObject sendAMessageToIt]

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

[[myInstance methodThatReturnsAnObject] sendAMessageToIt]

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

...