Зачем проводить различие между методами, которые возвращают значение, и методами, которые этого не делают?

StackOverflow https://stackoverflow.com/questions/1018281

Вопрос

Почему некоторые языки проводят различие между методами, которые возвращают значение, и методами, которые этого не делают?

т. е.в Oracle PL / SQL, где основное различие между функцией и процедурой заключается в том, что функция должна возвращать значение, а процедура - нет.

Аналогично для языков, которые этого не делают, почему бы и нет?


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

Это было полезно?

Решение

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

ФОРТРАН обычно считается первым языком, который реализовал оба этих принципа и продемонстрировал различия.(Ранний LISP также сыграл несколько противоположную роль в этом, но он оказал небольшое влияние за пределами академических кругов).

Следуя традициям математики (частью которой CS все еще была в 60-х годах), функции рассматривались только как инкапсуляция параметризованных математических вычислений, предназначенных исключительно для возврата значения в более крупное выражение.То, что вы могли бы назвать это "голым" (F = АЗИМУТ (СЕКУНДЫ)), было просто тривиальным вариантом использования.

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

Таким образом, у них действительно не было никакой концептуальной связи, кроме инкапсуляции и параметров.

Реальный вопрос заключается в том,:"Как так много разработчиков пришли к выводу, что они одинаковы?"

И ответом на это является C.

Когда K + R изначально разрабатывали свой высокоуровневый язык макроассемблерного типа для PDP-11 (возможно, начали с PDP-8?), у них не было иллюзий аппаратной независимости.Практически каждая "уникальная" особенность языка была отражением машинного языка и архитектуры PDP (см. i++ и --i).Одним из них была реализация функций и подпрограмм, которые могли быть (и всегда были) реализованы идентично в PDP, за исключением того, что вызывающий объект просто игнорировал возвращаемое значение (в R0 [, R1]) для подпрограмм.

Так родился указатель void, и после того, как язык C захватил весь мир программирования, возникло ошибочное представление о том, что этот артефакт реализации HW / OS (хотя и верный почти на каждой последующей платформе) был таким же, как и семантика языка.

Другие советы

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

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

Приведу один крошечный пример, когда вы четко проводите различие между выражениями и утверждениями, if(x = 3), в отличие от if(x == 3) является синтаксически некорректным (для использования оператора, где ожидалось выражение), а не просто ошибкой типа (для использования целого числа, где ожидалось логическое значение).Это имеет то преимущество, что также запрещает if(x = true) что было бы разрешено правилом, основанным на типах, в контексте, где присваивания представляют собой выражения, которые имеют значение их правого операнда.

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

  • функции , которые возвращают () которые являются чистыми функциями и могут возвращать только одно бесполезное пустое значение, вызываемое () или расходятся
  • функции , которые возвращают IO () (или единица измерения в какой-либо другой монаде), которые являются функциями без "результата", за исключением эффектов в монаде ввода-вывода (или какой бы то ни было другой)

Извините, что я отвечаю на вопрос двухлетней давности, особенно с чем-то уникальным для моего родного языка Феликс http://felix-lang.org но все равно здесь все идет своим чередом :)

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

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

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

Обычно это неэффективно, так зачем же это делать?Ответ таков:Все процедуры Felix являются потенциально совместными процедурами (fibers).Они могут переключить управление на другую процедуру, обратившись к каналу.Это вызывает обмен контролем.

  • По соображениям производительности копирование машинного стека на control exchange не является вариантом.
  • По соображениям управления памятью замена указателей стека также не является вариантом.

ОС обычно меняет местами указатели стека для потоков, что выполняется достаточно быстро, но имеет фундаментальную проблему на машинах с линейными адресами:вам либо нужно ограничить максимальный размер стека смехотворно малым значением, либо ограничить количество потоков смехотворно малым значением.На 32-разрядной машине недостаточно адресного пространства, чтобы даже рассмотреть это решение.На 64-разрядной машине замена стека имеет больший потенциал, но, конечно, требования пользователей всегда растут, опережая аппаратные средства через 3 дня после ее выпуска ..:)

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top