Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Потрепаться";
Текущий архив: 2004.11.21;
Скачать: [xml.tar.bz2];

Вниз

Объявление процедуры внутри процедуры   Найти похожие ветки 

 
peypivo ©   (2004-11-02 11:18) [0]

Поспорил с коллегой хорошо ли это. Каких то особых аргументов ни у него ни у меня нет. Рассудите нас.


 
panov ©   (2004-11-02 11:22) [1]

Не то что хорошо, а иногда может быть необходимо.
Но читабельность кода снижается однозначно.


 
TUser ©   (2004-11-02 11:28) [2]

А сардельки как жарить положено, а? Ответ на эти вопросы одназначен и содержится во фразе

> Каких то особых аргументов ни у него ни у меня нет


 
SPeller ©   (2004-11-02 11:28) [3]

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


 
Гаврила ©   (2004-11-02 11:29) [4]

Зависит от ситуации


 
PVOzerski ©   (2004-11-02 11:30) [5]

Вот насчет CallBack"a - не уверен. Могут быть проблемы со стеком, хотя компилятор, пожалуй, и скушает.


 
DiamondShark ©   (2004-11-02 11:30) [6]

О чём спорили, если аргументов нет?
Как можно рассудить, если аргументов нет?


 
Sergey_Masloff   (2004-11-02 11:31) [7]

peypivo ©   (02.11.04 11:18)  
>Поспорил с коллегой хорошо ли это.
>Каких то особых аргументов ни у него ни у меня нет.
Оба ослы. Чего тут судить-то.
P/S Ничего личного


 
DiamondShark ©   (2004-11-02 11:37) [8]


> Потому что такую функцию можно передавать в Callback api-функциям

Нельзя передавать.


> Могут быть проблемы со стеком, хотя компилятор, пожалуй,
> и скушает.

Если она передаётся как параметр pointer, то, конечно, скушает.
А вот если как процедурный тип, то нет.


 
peypivo ©   (2004-11-02 11:40) [9]

> О чём спорили

Он говорит - некрасиво, потому что всегда такие ситуации можно
обойти. Я говорю что иногда обход намного более некрасивый но  примера привести не могу.


 
Sergey_Masloff   (2004-11-02 11:41) [10]

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


 
msguns ©   (2004-11-02 11:43) [11]

>peypivo ©   (02.11.04 11:40) [9]
>Он говорит - некрасиво, потому что всегда такие ситуации можно
обойти. Я говорю что иногда обход намного более некрасивый но  примера привести не могу.

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


 
Sandman25 ©   (2004-11-02 11:47) [12]

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


 
Sandman25 ©   (2004-11-02 11:50) [13]

Резюмируя, в других языках типа Java в таких случаях заводят дополнительный класс, который выполняет требуемые функции в private методах. В Delphi ленивым программистам позволяют использовать более быстрый прием :)


 
DiamondShark ©   (2004-11-02 11:55) [14]


> peypivo ©   (02.11.04 11:40) [9]
> Он говорит - некрасиво, потому что всегда такие ситуации
> можно обойти.

Можно многое обойти. Даже использование процедур можно обойти ;)


> Я говорю что иногда обход намного более некрасивый
> но  примера привести не могу.

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


 
DiamondShark ©   (2004-11-02 12:03) [15]


> Sandman25 ©   (02.11.04 11:50) [13]

Как-то у тебя всё с ног на гойлову перевёрнуто.

Использование классов в "языках типа java" (всё семейство сиобразных уродцев) -- это как раз костыли для обхода имеющейся несуразности.


 
Piter ne doma   (2004-11-02 12:14) [16]

>Оба ослы. Чего тут судить-то.
>P/S Ничего личного

прикольно :)

P.S. "Встала и пошла отсюда! Ничего личного..." :)


 
Sandman25 ©   (2004-11-02 12:18) [17]

[15] DiamondShark ©   (02.11.04 12:03)

Не согласен. Вложенные процедуры - неструктурно, они нарушают ясность и простоту Паскаля. Локальные переменные должны быть именно локальными, а не так:
var varGlobal: byte;
procedure A;
var varA: byte;
 procedure B;
 var varB: byte;
   procedure C;
   var varC: byte;
   begin
     varC := varGlobal + varA + varB;
   end;
...


 
Digitman ©   (2004-11-02 12:22) [18]


> peypivo


локальные п/программы следует использовать именно там, где их следует применять .. все остальное - пустая болтовня


 
DiamondShark ©   (2004-11-02 12:45) [19]


> Sandman25 ©   (02.11.04 12:18) [17]
> Не согласен. Вложенные процедуры - неструктурно

Дать определение "структурности", и показать, что вложенные процедуры ему противоречат тебя после такого заявления не затруднит.


> Локальные переменные должны быть именно локальными,

А масло должно быть, без сомнения, маслянистым.

Выше ты предлагал использовать класс с приватными полями и методами, и тебя нисколько не смущало, что методам придётся работать с полями класса.
Что понятно: поля представлят внутреннее состояние некоторого вычислительного процесса.
Теперь, внимание!, вопрос: в чём принципиальная разница в представлении внутреннего состояния процесса в виде полей объекта и в виде локальных переменных процедуры?


 
Sandman25 ©   (2004-11-02 12:53) [20]

[19] DiamondShark ©   (02.11.04 12:45)

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

Теперь, внимание!, вопрос: в чём принципиальная разница в представлении внутреннего состояния процесса в виде полей объекта и в виде локальных переменных процедуры?

Если я изучаю метод класса, я могу предположить, что он может использовать поля и свойства класса. Если я изучаю вложенную процедуру, я не хочу проверять секцию объявлений всех внешних к данной процедуре процедур. Другими словами, при использовании структурного программирования мы имеем:
1) предельно малый контекст - мало мест, где описаны используемые переменные
2) максимальная независимость - нет зависимости от вызывающего кода


 
SPeller ©   (2004-11-02 13:05) [21]

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

procedure SomeProc1(Prams);
var
 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10: SomeType;

 procedure Process1;
 begin
   ...
   // 200 строк кода по обработке значений переменных v1-v10
 end;

 procedure Process2;
 begin
   ...
   // ещё 200 строк по обработке этих же переменных
 end;

begin
 // А дальше что-то вроде такого
 for I := 0 to N do begin
   if SomeExpr then
     Process1
   else
     Process2;
   ...
   if SomeExpr2 then
     Process2
   else
     Process1;
 end;
 ...
 Process1;
 ...
 Process2;
 ...
 for I := 0 to N do
   Process1;
 ...
 Process2;
end;


 
Sandman25 ©   (2004-11-02 13:08) [22]

[21] SPeller ©   (02.11.04 13:05)

Process1 и process2 - private методы класса с полями v1...v10, SomeProc - public метод того же (или другого!) класса. Неужели трудно было догадаться :)


 
Думкин ©   (2004-11-02 13:10) [23]

>  [21] SPeller ©   (02.11.04 13:05)
> А теперь скажите, уважаемые противники вложенных процедур,
> как можно сделать данный пример оптимальнее без использования
> вложенных процедур:
>
> procedure SomeProc1(Prams);
> var
>  v1, v2, v3, v4, v5, v6, v7, v8, v9, v10: SomeType;
>
>  procedure Process1;
>  begin
>    ...
>    // 200 строк кода по обработке значений переменных v1-v10
>  end;
>
>  procedure Process2;
>  begin
>    ...
>    // ещё 200 строк по обработке этих же переменных
>  end;

Я не сторонник. Я считаю, в свое время можно и бубном спину почесать - если нечем иным. Но что касается приведенного:
1. Что значит опитмальнее?
2. // 200 строк кода по обработке значений переменных v1-v10  - Я бы повесился. Может чего-то в оптимальности не понимаю, но руки даже не глядя кода уже чешутся сделать рефакторинг.


 
panov ©   (2004-11-02 13:10) [24]

Sandman25 ©   (02.11.04 13:08) [22]

И что, для 2-х процедур класс писать?


 
panov ©   (2004-11-02 13:13) [25]

Думкин ©   (02.11.04 13:10) [23]

Рефакторинг надо делать в конкретной задаче, а не в примере.
200 строк кода смущает?

Sandman25 ©   (02.11.04 13:08) [22]

К тому же, как я понимаю, технология ООП не для замены процедур классами предназначена.


 
Sandman25 ©   (2004-11-02 13:17) [26]

[21] SPeller ©   (02.11.04 13:05)

Другое решение - параметр типа record(или class) с передачей по ссылке.

[24] panov ©   (02.11.04 13:10)

А в чем принципиальное отличие от класса с 20 методами??? Java недавно заставила написать класс для передачи одного указателя на метод, и ничего - понравилось :)

[25] panov ©   (02.11.04 13:13)

ИМХО код без вложенных процедур проще для понимания, изменения и повторного использования. То есть как раз для того, для чего и придумывалось ООП


 
Думкин ©   (2004-11-02 13:17) [27]

> [25] panov ©   (02.11.04 13:13)
> Думкин ©   (02.11.04 13:10) [23]
> 200 строк кода смущает?

В одной процедуре? Да.


 
SPeller ©   (2004-11-02 13:20) [28]

Sandman25 ©   (02.11.04 13:08) [22]
А если SomeProc будет уже методом класса? Тогда, как говорит panov, писать ещё один класс ради того чтобы  всунуть туда две функции? Это уже будет хуже по быстродействию, поскольку уйдет куча времени на копирование данных в этот класс.

Думкин ©   (02.11.04 13:10) [23]
1. Что значит опитмальнее?

Оптимальнее - я имел ввиду повысить быстродейстиве, и читабельность. Но только не так чтобы читабельнее, но медленнее.

> 2. // 200 строк кода по обработке значений переменных
> v1-v10  - Я бы повесился. Может чего-то в
> оптимальности не понимаю, но руки даже не глядя кода
> уже чешутся сделать рефакторинг.

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


 
Sandman25 ©   (2004-11-02 13:24) [29]

[28] SPeller ©   (02.11.04 13:20)

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


 
SPeller ©   (2004-11-02 13:26) [30]

Sandman25 ©   (02.11.04 13:17) [26]
Другое решение - параметр типа record(или class) с передачей по ссылке

А потом в 100 строках из 200 писать MyRecord.MyField вместо имени переменной? Или использовать with, которого не понимает отладчик и париться с отладкой? В любом случае другое решение вызовет накладные расходы, связанные с обращением к полям записи/класса.


 
SPeller ©   (2004-11-02 13:31) [31]

Sandman25 ©   (02.11.04 13:24) [29]
Тогда можно будет подключать разные классы, реализующие данную задачу по разному.

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

> Максимальное быстродействие и понятный человеку код
> несовместимы.

Ну не то чтобы совсем...


 
Sandman25 ©   (2004-11-02 14:30) [32]

[30] SPeller ©   (02.11.04 13:26)

Для чего записи придумали? Ускорения от них нет, префикс переменной перед именем поля еще зачем-то писать надо.

[31] SPeller ©   (02.11.04 13:31)

Если что-то используется только один раз, то главное - чтобы работало???


 
DiamondShark ©   (2004-11-02 16:00) [33]


> Sandman25 ©   (02.11.04 12:53) [20]
>
> Структурность заключается в том, чтобы не решать в одной
> сущности несколько несвязанных задач.

Да? Ладно. Вот только так и не понятно, как локальные переменные этому противоречат.

Есть задача, решается какой-то процедурой. У процесса решения есть какое-то внутреннее состояние, которое изменяется частями внутренней структуры.
Здесь что-то не так?

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


> Для каждой независимой
> задачи нужно создавать отдельный класс.

Смелое утвердение. Главное, обосновано сильно ;)


> В таком случае мы
> имеем максимальную простоту повторного использования.

В случае процедур мы имеем какие-то сложности с повторным использованием?


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

Смешно, чесслово. Давай я напишу что-то вроде:
Когда я изучаю процедуру, я могу предположить, что она может использовать переменные верхнего уровня. Если я смотрю метод, то я не хочу проверять описание полей, которые, могут быть далеко от метода, могут быть в классе-предке, или вообще в другом файле.


> Другими словами,
> при использовании структурного программирования мы имеем:
> 1) предельно малый контекст - мало мест, где описаны используемые
> переменные
> 2) максимальная независимость - нет зависимости от вызывающего
> кода

Замечательно.
1) Контекст в случае локальных переменных минимален. Они описаны только там и только на том уровне, где они реально нужны.
Пусть есть:
Процедура_1
 Контекст_1
 Процедура_2
   Контекст_2
     Процедура_3
       Контекст_3
Если Процедуре_3 понадобится доступ к Контексту_2, то в твоём случае с классом, тебе придётся вынести его описание на уровень членов класса (т.е. на самый верхний), хотя никому больше он на этом уровне не нужен. Либо копировать его в параметрах. Тогда процедуры вообще становятся не связанными, и не понятно, на каком основании они вообще объединены в класс.
Т.е. в твоём случае нарушается твоё же требование.

2) На каком основании тогда процедуры объединяются в класс?


 
Sandman25 ©   (2004-11-02 16:28) [34]

[33] DiamondShark ©   (02.11.04 16:00)

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

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

Да? Ладно. Вот только так и не понятно, как локальные переменные этому противоречат.


Пример (не слишком правдоподобный).

Нам нужно найти минимум из трех чисел. Имеем
function Min(const X1, X2, X3: Integer): Integer;
var
 A, B: Integer;
 function Min2: Integer;
 begin
   if A < B then
     Result := A
   else
     Result := B
 end;
begin
 A := X1;
 B := X2;
 A := Min2;
 B := X3;
 Result := Min2
end;

Так вот. С моей точки зрения следует вынести Min2 в отдельную сущность, потому как нахождение минимума из 2 значений и обработка 3 значений являются независимыми задачами. Например, для получения максимума из 3 значений внешняя процедура не изменится, нужно будет только использовать другую реализацию внутренней функции.

У процесса решения есть какое-то внутреннее состояние, которое изменяется частями внутренней структуры.
Здесь что-то не так?


Так. Но внутренняя структура для процесса решения вложенной процедуры в общем виде отлична (и поэтому должна быть изолирована) от внутренней структуры для внешней процедуры. Почему внешняя процедура должна "заботиться" о чужой структуре?

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

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

В случае процедур мы имеем какие-то сложности с повторным использованием?

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

Смешно, чесслово. Давай я напишу что-то вроде:

Аршумент принимается. Мне очень нравится возможность C-подобных языков объявлять новые переменные где угодно, кстати :)

Замечательно.
1) Контекст в случае локальных переменных минимален. Они описаны только там и только на том уровне, где они реально нужны.


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


 
Sandman25 ©   (2004-11-02 16:36) [35]

[33] DiamondShark ©   (02.11.04 16:00)

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

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

Да? Ладно. Вот только так и не понятно, как локальные переменные этому противоречат.


Пример (не слишком правдоподобный).

Нам нужно найти минимум из трех чисел. Имеем
function Min(const X1, X2, X3: Integer): Integer;
var
 A, B: Integer;
 function Min2: Integer;
 begin
   if A < B then
     Result := A
   else
     Result := B
 end;
begin
 A := X1;
 B := X2;
 A := Min2;
 B := X3;
 Result := Min2
end;

Так вот. С моей точки зрения следует вынести Min2 в отдельную сущность, потому как нахождение минимума из 2 значений и обработка 3 значений являются независимыми задачами. Например, для получения максимума из 3 значений внешняя процедура не изменится, нужно будет только использовать другую реализацию внутренней функции.

У процесса решения есть какое-то внутреннее состояние, которое изменяется частями внутренней структуры.
Здесь что-то не так?


Так. Но внутренняя структура для процесса решения вложенной процедуры в общем виде отлична (и поэтому должна быть изолирована) от внутренней структуры для внешней процедуры. Почему внешняя процедура должна "заботиться" о чужой структуре?

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

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

В случае процедур мы имеем какие-то сложности с повторным использованием?

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

Смешно, чесслово. Давай я напишу что-то вроде:

Аршумент принимается. Мне очень нравится возможность C-подобных языков объявлять новые переменные где угодно, кстати :)

Замечательно.
1) Контекст в случае локальных переменных минимален. Они описаны только там и только на том уровне, где они реально нужны.


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


 
злобный сишник   (2004-11-02 19:43) [36]

как известно, в с++ нет локальных функций, нет и все тут.

> Для каждой независимой
> задачи нужно создавать отдельный класс.


как не странно, но в этом и состоит идеология срр
(кто не верит - читайте Страуструпа)

оцените ( анаог кода из Sandman25 ©   (02.11.04 16:28) [34]):

class GetMin3
{
public:
GetMin3(int x1, int x2, int x3)
{
  res = my_min(x1, my_min( x2, x3));
}
int result() const {return res;}
private:
int res;
int my_min(int a, int b)
{
  return (a<b) ? (a) : (b);
}
};

//использование
GetMin3 gm (1, 2, 3);
result = gm.result();


хуже ли это, чем код в [34]? не думаю.. накладных расходов на класс в данном случае нет никаких.. в делфи классы создавать можем только динамически, что уже ограничение. вы скажете можно использовать object или record? да, можно.. если неохота связываться с динамич памятью - нужно

если бы я писал на паскале нечто подобное (я иногда пишу и на паскале) - использовал бы object

ЗЫ
>всё семейство сиобразных уродцев
по-легче, приятель !
;)



Страницы: 1 вся ветка

Форум: "Потрепаться";
Текущий архив: 2004.11.21;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.58 MB
Время: 0.042 c
14-1099481328
Mike Kouzmine
2004-11-03 14:28
2004.11.21
Буш победил


1-1099568054
TUser
2004-11-04 14:34
2004.11.21
sharing violation


3-1098452211
nv
2004-10-22 17:36
2004.11.21
Вопрос о SQL "INSERT INTO"


1-1099571574
тт
2004-11-04 15:32
2004.11.21
Можно-ли dll интегрировать в exe?


3-1098442217
Олеся
2004-10-22 14:50
2004.11.21
Добавление записей в БД





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский