Почему API должен возвратиться 'пусто'?

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

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

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

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

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

.. потому что Массив. Реверс () возвращается пусто.

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

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

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

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

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

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

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


ЭПИЛОГ

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

В C++ cout << setprecision(..) << number << setwidth(..) << othernumber; кажется, изменяет объект суда для изменения следующей вставленной данной величины.

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

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

23
задан Community 23 May 2017 в 12:13
поделиться

7 ответов

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

26
ответ дан 29 November 2019 в 01:10
поделиться

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

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

4
ответ дан 29 November 2019 в 01:10
поделиться

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

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

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

19
ответ дан 29 November 2019 в 01:10
поделиться

Если вы хотите, чтобы ваш API вызывался из F #, пожалуйста, верните return 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 - это вызов метода, который возвращает значение, и мы ничего не делаем с этим значением, функция add , как считается, принимает два значения и возвращает этот экземпляр Logger. Однако строка №2 не только возвращает значение, она появляется после того, что F # считает оператором «return» для функции, фактически делая два оператора «return».Это вызовет ошибку компилятора, и нам нужно явно игнорировать возвращаемое значение метода Log , чтобы избежать этой ошибки, чтобы наш метод add имел только один оператор возврата.

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

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

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

3
ответ дан 29 November 2019 в 01:10
поделиться

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

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

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

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

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

4
ответ дан 29 November 2019 в 01:10
поделиться

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

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

5
ответ дан 29 November 2019 в 01:10
поделиться

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

0
ответ дан 29 November 2019 в 01:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: