Почему API должен возвращать 'void'? - PullRequest
23 голосов
/ 28 июня 2010

При написании API или объекта многократного использования, есть ли техническая причина, по которой все вызовы методов, которые возвращают 'void', не должны просто возвращать 'this' (* this в C ++)?

Например, используякласс строки, мы можем делать такие вещи:

string input= ...;
string.Join(input.TrimStart().TrimEnd().Split("|"), "-");

, но мы не можем сделать это:

string.Join(input.TrimStart().TrimEnd().Split("|").Reverse(), "-");

.. потому что Array.Reverse () возвращает void.

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

api.Method1();
api.Method2();
api.Method3();

.. но было бы вполне возможно написать:

api.Method1().Method2().Method3()

.. если разработчик API разрешил это.

Есть ли техническая причина для следования по этому маршруту?Или это просто стиль, указывающий на изменчивость / новый объект?

(x-ref Стилистический вопрос о возвращении void )


ЭПИЛОГ

Я принял ответ Лювиера, так как считаю, что он лучше всего представляет намерение / дизайн, но, похоже, существуют популярные примеры API, отличающиеся от этого:

В C ++ *Кажется, что 1032 * изменяет объект cout, чтобы изменить следующий вставленный элемент данных.

В .NET Stack.Pop() и Queue.Dequeue() оба возвращают элемент, но также изменяют коллекцию.

Подсказки к ChrisW и другим для получения подробной информации о фактических затратах на производительность.

Ответы [ 7 ]

26 голосов
/ 28 июня 2010

Методы, которые возвращают пустоту, более четко указывают на наличие побочных эффектов. Предполагается, что те, которые возвращают измененный результат, не имеют побочных эффектов, включая изменение исходного ввода. Возврат метода void означает, что он изменяет свои входные данные или другое внутреннее состояние API.

19 голосов
/ 28 июня 2010

Если бы вы Reverse() вернули string, то для пользователя API не было бы очевидно, возвращал ли он строку новая или ту же самую, в обратном порядке.

string my_string = "hello";
string your_string = my_string.reverse(); // is my_string reversed or not?

Именно поэтому, например, в Python, list.sort() возвращает None;это отличает сортировку на месте от sorted(my_list).

5 голосов
/ 28 июня 2010

Есть ли техническая причина для того, чтобы следовать этому маршруту?

Одно из руководящих принципов проектирования в C ++ - «не платите за функции, которые вы не используете»;возвращение this будет иметь некоторое (небольшое) снижение производительности за функцию, которой многие люди (я, например) не будут склонны использовать.

4 голосов
/ 28 июня 2010

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

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

Если функция возвращает что-то не-void, я должен остановиться и спросить почему . Что это за объект, который может быть возвращен? Почему он вернулся? Могу ли я предположить, что this это всегда возвращено, или это иногда будет нулевым? Или совершенно другой объект? И так далее.

В стороннем API я бы предпочел, чтобы такого рода вопросы никогда не возникали.

Если функция не нуждается в для возврата чего-либо, она не должна ничего возвращать.

4 голосов
/ 28 июня 2010

Технический принцип, о котором упоминали многие другие (который void подчеркивает тот факт, что функция имеет побочный эффект), известен как Разделение команд-запросов .

Несмотря на то, что у этого принципа есть свои плюсы и минусы, например (более субъективно) более четкое намерение или более лаконичный API, наиболее важной частью является согласованность .

3 голосов
/ 28 июня 2010

Если вы хотите, чтобы ваш API вызывался из F #, do верните void, если вы не уверены, что этот конкретный вызов метода будет связан с другим почти каждый раз, когда он будет использоваться.

Если вы не хотите, чтобы ваш API был легок в использовании из F #, вы можете перестать читать здесь.

F # более строг, чем C #, в некоторых областях - он хочет, чтобы вы были явновызываете ли вы метод, чтобы получить значение, или просто для его побочных эффектов.В результате, вызов метода для его побочных эффектов, когда этот метод также возвращает значение, становится неудобным, потому что возвращаемое значение должно быть явно проигнорировано, чтобы избежать ошибок компилятора.Это делает «плавные интерфейсы» несколько неудобными для использования из F #, который имеет собственный превосходный синтаксис для объединения последовательности вызовов.

Например, предположим, что у нас есть система ведения журнала с методом Log, который возвращаетthis, чтобы учесть некоторую цепочку методов:

let add x y =
    Logger.Log(String.Format("Adding {0} and {1}", x, y)) // #1
    x + y                                                 // #2

В F #, потому что строка # 1 - это вызов метода, который возвращает значение, и мы ничего не делаем с этим значением, *Считается, что функция 1015 * принимает два значения и возвращает этот экземпляр Logger.Однако строка № 2 также не только возвращает значение, она появляется после того, что F # считает оператором «return» для функции, фактически делая два оператора «return».Это приведет к ошибке компилятора, и нам нужно явно игнорировать возвращаемое значение метода Log, чтобы избежать этой ошибки, чтобы у нашего add метода был только один оператор возврата.

let add x y =
    Logger.Log(String.Format("Adding {0} and {1}", x, y)) |> ignore
    x + y

Как вы можете догадаться, выполнение большого количества вызовов «Свободного API», которые в основном связаны с побочными эффектами, становится несколько разочаровывающим упражнением, разбрасывая множество ignore операторов повсюду.

Вы, конечно, можетеимейте лучшее из обоих миров и, пожалуйста, разработчики на C # и F #, предоставляя как свободный API, так и модуль F # для работы с вашим кодом.Но если вы не собираетесь этого делать и собираетесь использовать свой API для общего пользования, , пожалуйста , дважды подумайте, прежде чем возвращать this из каждого метода.

0 голосов
/ 28 июня 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...