Связанные с типом процедуры должны быть виртуальными
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 10.11.04 09:00
Оценка: -5
Для затравки: Как функции, не являющиеся методами, улучшают инкапсуляцию Скотт Мейерс (Scott Meyers) Перевод А. И. Легалова Статья опубликована в C/C++ user Journal (February, 2000) http://www.softcraft.ru/coding/sm/sm01.shtml


Скотт Мейерс предлагает следующий алгоритм:
if (f необходимо быть виртуальной)
   сделайте f функцией-членом C;
else if (f - это operator>> или operator<<)
{
   сделайте f функцией - не членом;
   if (f необходим доступ к непубличным членам C)
      сделайте f другом C;
}
else if (f необходимо преобразовывать тип его крайнего левого аргумента)
{
   сделайте f функцией - не членом;
   if (f необходимо иметь доступ к непубличным членам C)
      сделайте f другом C;
}
else if (f может быть реализована через доступный интерфейс класса)
   сделайте f функцией - не членом;
else
   сделайте f функцией-членом C;



Вопрос: а зачем так сложно? Давайте проще:
IF f необходимо быть виртуальной THEN сделайте f функцией членом ELSE сделайте f внешней функцией END


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

1) X.f(); Вызов связанной с типом "виртуальной" процедуры f()
2) g(X); Вызов не связанной с типом обычной процедуры g()
3) третьего не дано, так как все остальное излишне

С аргументами:
  X.f(a, b, c);
  g(X, a, b, c);


Пример:
PROCEDURE MovePoint(VAR p: Point; dx, dy: INTEGER);
BEGIN
  p.SetX(p.GetX() + dx); (* Вызов виртуальных методов GetX/SetX *)
  p.SetY(p.GetY() + dy); (* Вызов виртуальных методов GetY/SetY *)
END;



Короче, если метод не виртуальный, то зачем он метод? Пусть он будет не методом, а внешней процедурой. А все оставшиеся методы — все поголовно виртуальны.
Re: Связанные с типом процедуры должны быть виртуальными
От: Курилка Россия http://kirya.narod.ru/
Дата: 10.11.04 09:14
Оценка: +3
Здравствуйте, Сергей Губанов, Вы писали:

{поскипано к чертям}

СГ>Короче, если метод не виртуальный, то зачем он метод? Пусть он будет не методом, а внешней процедурой. А все оставшиеся методы — все поголовно виртуальны.


И что это даст? Какие положительные аспекты такого подхода?
Отрицательные я вот вижу сразу:
1. переполнение безымянного пространства имён излишними ф-циями (аля MoveLine, MovePoint, MoveCircle вместо объектов с простым методом Move)
2. неинтуитивность семантики работы таких методов, т.е. "не ООП-ориентированность", если можно так сказать, т.е. не понятно, к какому объекту применяется операция (e.g. почему к 1-му в списке, а не к последнему???)

Вот тебе 2 минуса (на мой взгляд), приведи хоть 1 плюс.
Re: Связанные с типом процедуры должны быть виртуальными
От: XopoSHiy Россия http://cleancodegame.github.io/
Дата: 10.11.04 09:19
Оценка: +4
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Короче, если метод не виртуальный, то зачем он метод? Пусть он будет не методом, а внешней процедурой. А все оставшиеся методы — все поголовно виртуальны.


Причины, по которым невиртуальные методы стоит делать именно методами, а не внешней подпрограммой:

1. Это логично. Невиртуальную процедуру UpdateContents удобно поместить в класс TSuperVisualControl
Иначе нам придётся иметь процедуры GridUnpdateContents(g: TGrid), TreeUnpdateContents(t: TTree), UnpdateContentsOfEdit(e: TEdit), и тд...

2. Внешние подпрограммы засоряют пространство имён. Придётся вводить всякие суффиксы, либо разносить по пакетам:
Grids.UpdateContents(grid)
Edits.UpdateContents(edit)
или
GridUpdateContents(grid)
EditUpdateContents(edit)

и тд.
Ну так это и есть какое-то убогое эмулирование методов! Лучше сразу методом и делать.

3. Во многих языках нет такого понятия, как friend! Тогда ничего не остаётся, как делать подпрограмму методом, если нужен доступ к закрытым полям и методам класса.

Наверное ещё придумать можно... Но уже и этих трёх достаточно.

Просто так рубить с плеча — нехорошо... Вот Мейерс более аккуратен, хотя я бы и с ним поспорил, была бы возможность
---
http://twitter.com/xoposhiy
http://xoposhiy.moikrug.ru
Re: Связанные с типом процедуры должны быть виртуальными
От: AndreyFedotov Россия  
Дата: 10.11.04 09:24
Оценка:
Ну уж если упрощать, то так как язык-таки ООП — надо к бабушке выкинуть обычные функции
Я не вижу — что мы упростим — выкинув не-виртуальные функции. Не надо будет писать слово virtual? По-моему главным результатом такого упрощения станет то, что всякий раз, когда не виртуальный изначально метод будет становиться виртуальным (или наборот) — придётся править код. Кроме того в силу этого усложнится написание шаблонов. Ну а количество ошибок как минимум не уменьшится.
Re[2]: Связанные с типом процедуры должны быть виртуальными
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 10.11.04 09:27
Оценка: -2
Здравствуйте, Курилка, Вы писали:

К>Отрицательные я вот вижу сразу:

К>1. переполнение безымянного пространства имён излишними ф-циями

Извините, но еще со времен Модулы (70-тые годы) "безымянных пространств имен" не существует. Все процедуры пишутся внутри модулей. Так что Ваше замечание относится только к еще более древним языкам программирования чем Модула.

К>2. неинтуитивность семантики работы таких методов, т.е. "не ООП-ориентированность", если можно так сказать, т.е. не понятно, к какому объекту применяется операция (e.g. почему к 1-му в списке, а не к последнему???)


Не совсем понял, можно поподробнее?
IMPORT Lists;

VAR L: Lists.List;
...

  Lists.FirstElementUpdate(L);
  Lists.BackElementUpdate(L);
Re[2]: Связанные с типом процедуры должны быть виртуальными
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 10.11.04 09:32
Оценка:
Здравствуйте, XopoSHiy, Вы писали:

XSH> Невиртуальную процедуру UpdateContents удобно поместить в класс TSuperVisualControl

XSH>Иначе нам придётся иметь процедуры GridUnpdateContents(g: TGrid), TreeUnpdateContents(t: TTree), UnpdateContentsOfEdit(e: TEdit), и тд...

Вы сами дали ответ на свой вопрос:
Grids.UpdateContents(grid)
Edits.UpdateContents(edit)




XSH>2. Внешние подпрограммы засоряют пространство имён. Придётся вводить всякие суффиксы, либо разносить по пакетам:


Какое еще пространство имен засоряет? Ничего не засоряет! Есть модуль Grids в котором определена процедура:
MODULE Grids;

PROCEDURE UpdateContents(grid: Grid);
...


Вызов:
Grids.UpdateContents(grid)



XSH>3. Во многих языках нет такого понятия, как friend! Тогда ничего не остаётся, как делать подпрограмму методом, если нужен доступ к закрытым полям и методам класса.


А в других многих языках инкапсуляция осуществляется на уровне модуля. Все описанное внутри одного модуля "дружит" друг с другом.
Re: Связанные с типом процедуры должны быть виртуальными
От: Sinclair Россия https://github.com/evilguest/
Дата: 10.11.04 09:33
Оценка: 37 (4) +5
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Вопрос: а зачем так сложно? Давайте проще:

Очень странный вопрос для программиста на С++. Методы отличаются от функций прежде всего тем, какой доступ они имеют к содержимому класса.
Поэтому просто "вынести" невиртуальный метод, использующий приватную часть, за пределы класса не выйдет — придется сделать его другом. А это ничем, кроме синтаксической путаницы, не отличается от нормального метода класса.
Мейерс предлагает выносить за пределы класса те методы, которым достаточно доступа через его публичный интерфейс. Их можно назвать утилитными, т.к. клиент класса может и сам воспроизвести их функциональность, и их применение — не более чем вопрос удобства.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Связанные с типом процедуры должны быть виртуальными
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 10.11.04 09:37
Оценка:
Здравствуйте, AndreyFedotov, Вы писали:


AF> По-моему главным результатом такого упрощения станет то, что всякий раз, когда не виртуальный изначально метод будет становиться виртуальным (или наборот) — придётся править код.


Это как это? Что за мутация такая виртуальный в невиртуальный или наоборот? Это такая последняя мода проектировать надежные системы?
Re[2]: Связанные с типом процедуры должны быть виртуальными
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 10.11.04 09:42
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Сергей Губанов, Вы писали:


СГ>>Вопрос: а зачем так сложно? Давайте проще:

S>Очень странный вопрос для программиста на С++. Методы отличаются от функций прежде всего тем, какой доступ они имеют к содержимому класса.
S>Поэтому просто "вынести" невиртуальный метод, использующий приватную часть, за пределы класса не выйдет — придется сделать его другом. А это ничем, кроме синтаксической путаницы, не отличается от нормального метода класса.

Это исключительно проблемы языков С++ family. В модульных языках программирования инкапсуляция осуществляется на уровне модуля. Внутри модуля все друг с другом "дружат".
Re[3]: Связанные с типом процедуры должны быть виртуальными
От: AndreyFedotov Россия  
Дата: 10.11.04 09:49
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Здравствуйте, AndreyFedotov, Вы писали:



AF>> По-моему главным результатом такого упрощения станет то, что всякий раз, когда не виртуальный изначально метод будет становиться виртуальным (или наборот) — придётся править код.


СГ>Это как это? Что за мутация такая виртуальный в невиртуальный или наоборот? Это такая последняя мода проектировать надежные системы?


А что тебя удивляет — если в одном классе метод виртуальный, а в другом — нет — но при этом они оба используются в одном и том же шаблоне? И то, что результатом станет комбинаторный рост числа шбалонов и как следствие такого "упрощения" — бессмысленность использования шаблонов вообще?
Или то, что код не проектируется разом от начала и до конца?
Re: Ну ты посмотри - его через дверь так он в окно лезет...
От: AndreyFedotov Россия  
Дата: 10.11.04 09:51
Оценка: :))) :))
Со своим Обероном...
Re[3]: Связанные с типом процедуры должны быть виртуальными
От: XopoSHiy Россия http://cleancodegame.github.io/
Дата: 10.11.04 09:52
Оценка: +1
Здравствуйте, Сергей Губанов, Вы писали:


XSH>>2. Внешние подпрограммы засоряют пространство имён. Придётся вводить всякие суффиксы, либо разносить по пакетам:


СГ>Какое еще пространство имен засоряет? Ничего не засоряет! Есть модуль Grids в котором определена процедура:

СГ>
СГ>MODULE Grids;

СГ>PROCEDURE UpdateContents(grid: Grid);
СГ>...
СГ>


СГ>Вызов:

СГ>
СГ>Grids.UpdateContents(grid)
СГ>


Ну да! Вместо того, чтобы писать

grid.UpdateContents;

Вы предлагаете

Grids.UpdateContents(grid)

Что-то мне это напоминает...

Методы в Perl-e реализованны именно с помощью такой конструкции!
Я к тому, что то, что вы предлагаете, это всего лишь способ эмулировать работу с методами.
И способ вполне жизнеспособный, как показал Perl

XSH>>3. Во многих языках нет такого понятия, как friend! Тогда ничего не остаётся, как делать подпрограмму методом, если нужен доступ к закрытым полям и методам класса.


СГ>А в других многих языках инкапсуляция осуществляется на уровне модуля. Все описанное внутри одного модуля "дружит" друг с другом.


Много бы я отдал, чтобы этого не было в Delphi. Все ноги переломаешь, пока разберёшься в таком "дружественном" коде...
Frien-ы — вообще ненужная вещь
---
http://twitter.com/xoposhiy
http://xoposhiy.moikrug.ru
Re: Связанные с типом процедуры должны быть виртуальными
От: Mr. None Россия http://mrnone.blogspot.com
Дата: 10.11.04 09:58
Оценка: 29 (3)
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Для затравки: Как функции, не являющиеся методами, улучшают инкапсуляцию Скотт Мейерс (Scott Meyers) Перевод А. И. Легалова Статья опубликована в C/C++ user Journal (February, 2000) http://www.softcraft.ru/coding/sm/sm01.shtml


Для затравки прочитайте ещё его же книги "Эффективное использование C++" и "Более эффективное использование C++". В данной статье Мейерс продолжает свою теорию относительно минимальности и достаточности интерфейса:
интерфейс класса должен быть минимальным, но полным, то есть набор открытых методов класса должен быть минимальным, ограниченный абсолютно необходимыми, но при этом точно покрывать всю доступную открытую функциональность класса. Согласно этому подходу, если интерфес класса удовлетворяет свойству минимальности и полноты, любой новый метод, будет реализовываться через уже имеющиейся методы, и это нарушит данный принцип. Именно такие "методы" Мейерс и предлагает делать внешними. Чувствуете разницу между этими словами и вашим предложением?
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Re[4]: Связанные с типом процедуры должны быть виртуальными
От: hrg Россия  
Дата: 10.11.04 10:04
Оценка: :)
XopoSHiy -> "Re[3]: Связанные с типом процедуры должны быть виртуальными"

Grids.UpdateContents(grid)

X> Методы в Perl-e реализованны именно с помощью такой конструкции!

X> Я к тому, что то, что вы предлагаете, это всего лишь способ
X> эмулировать работу с методами.
X> И способ вполне жизнеспособный, как показал Perl

"Не позволю с Вами согласится"(с) хз чей

$grid->UpdateContents();

без всяких лишних телодвижений и лишних параметров.

Yury Kopyl aka hrg | Только взял боец гитару, сразу — видно гармонист
Posted via RSDN NNTP Server 1.9 gamma
Re[3]: Связанные с типом процедуры должны быть виртуальными
От: Sinclair Россия https://github.com/evilguest/
Дата: 10.11.04 10:06
Оценка: 2 (2) +3 :)
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Это исключительно проблемы языков С++ family.

Пардон, ты берешся критиковать фрагмент, посвященный эффективному программированию на плюсах. Это что, такое раздвоение сознания?
СГ>В модульных языках программирования инкапсуляция осуществляется на уровне модуля. Внутри модуля все друг с другом "дружат".
Ну, я бы на твоем месте избегал столь широких обобщений. В виртовских языках — да. А вообще нет никакого определения "модульного языка", которое бы требовало дружбы всего подряд внутри модуля.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Связанные с типом процедуры должны быть виртуальными
От: bkat  
Дата: 10.11.04 10:06
Оценка: 6 (2)
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Это исключительно проблемы языков С++ family. В модульных языках программирования инкапсуляция осуществляется на уровне модуля. Внутри модуля все друг с другом "дружат".


Нафиг нафиг такую дружбу всех со всеми, хоть и в пределах одного модуля...
Re[3]: Связанные с типом процедуры должны быть виртуальными
От: Курилка Россия http://kirya.narod.ru/
Дата: 10.11.04 10:26
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Здравствуйте, Курилка, Вы писали:


К>>Отрицательные я вот вижу сразу:

К>>1. переполнение безымянного пространства имён излишними ф-циями

СГ>Извините, но еще со времен Модулы (70-тые годы) "безымянных пространств имен" не существует. Все процедуры пишутся внутри модулей. Так что Ваше замечание относится только к еще более древним языкам программирования чем Модула.


Вот не надо, Сергей, только опять навязывать все вирт. языки как "единственно верные"...
Скажи мне, где в Java, к примеру, есть модули?
Или на каждый класс нужно в пр-во имён заворачивать? А потом указывать именно пр-во имён вместо класса?

К>>2. неинтуитивность семантики работы таких методов, т.е. "не ООП-ориентированность", если можно так сказать, т.е. не понятно, к какому объекту применяется операция (e.g. почему к 1-му в списке, а не к последнему???)


СГ>Не совсем понял, можно поподробнее?

СГ>
СГ>IMPORT Lists;

СГ>VAR L: Lists.List;
СГ>...

СГ>  Lists.FirstElementUpdate(L);
СГ>  Lists.BackElementUpdate(L);
СГ>


При чём тут этот псевдокод?
Что я имел в виду:

X.f(a, b, c);
/* 1-й элемент */
g(X, a, b, c);
/* последний элемент */
g(a, b, c, X);


так понятней?
Re[2]: Связанные с типом процедуры должны быть виртуальными
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 10.11.04 10:28
Оценка: -1
Здравствуйте, Mr. None, Вы писали:

MN>...любой новый метод, будет реализовываться через уже имеющиейся методы, и это нарушит данный принцип. Именно такие "методы" Мейерс и предлагает делать внешними. Чувствуете разницу между этими словами и вашим предложением?


Да, чувствую. Слово интерфейс — широко в своем значении. У того что обозначается interface в Delphi, C#, Java — у него все методы "виртуальные". Не виртуальных методов в таком интерфейсе нет. Вот и Вы тоже почувствуйте разницу.
Re[4]: Связанные с типом процедуры должны быть виртуальными
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 10.11.04 10:38
Оценка: -1
Здравствуйте, Курилка, Вы писали:

К>Вот не надо, Сергей, только опять навязывать все вирт. языки как "единственно верные"...

К>Скажи мне, где в Java, к примеру, есть модули?
К>Или на каждый класс нужно в пр-во имён заворачивать? А потом указывать именно пр-во имён вместо класса?

Как одновременно: "1) Вот не надо, Сергей, только опять..." и "2) Скажи мне, где в Java..."? На второй пункт я бы мог ответить, но первый пункт запрещает это сделать. Вот если бы он не запрещал, то я бы ответил, что пространства имен — тупиковая ветвь в развитии языков программирования появившаяся из-за отсутсвия модульности. Куда ни ткни везде с модульностью — ни каких проблем, а с пространствами имен сплошные грабли. Вот и тут опять же такие грабли они подложили. Из-за namespace выходит нельзя делать методы обычными не связанными с типом процедурами...


К>
/* 1-й элемент */
g(X, a, b, c);
/* последний элемент */
g(a, b, c, X);

К>так понятней?

Так понятней. А какая разница-то? Можно и так: g(a, X, b, Y, c, Z); — для трех объектов X, Y, Z...
Re[5]: Связанные с типом процедуры должны быть виртуальными
От: XopoSHiy Россия http://cleancodegame.github.io/
Дата: 10.11.04 10:46
Оценка:
Здравствуйте, hrg, Вы писали:

X>> Методы в Perl-e реализованны именно с помощью такой конструкции!

hrg>"Не позволю с Вами согласится"(с) хз чей

hrg>$grid->UpdateContents();

hrg>без всяких лишних телодвижений и лишних параметров.

Это синтаксические навороты языка. Фактически это эквивалентно следующей записи:
GridsPackage::UpdateContents($grid);

То есть стрелка "->" интерпретируется именно так! Она подыскивает нужный пакет и вызывает оттуда указанную функцию с объектом в качестве первого параметра. При этом, как Вы наверное знаете, в самой функции придется таки писать так:

sub UpdateContents
{
  my $self = shift;
  ...

}


Что эквивалентно следующему коду на Паскале:

procedure UpdateContents(self: TObject);
begin

end;


// и вызов:
UpdateContents(grid);


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

Собственно там даже метод класса (статический в терминах С++) не отличается от обычных методов: если первым параметром пришёл объект, то метод обычный, если первым параметром пришёл пакет — то это метод класса.


К слову, Перл позиционируется как язык не скрывающий от программиста ничего! Там крайне сложно (если вообще возможно) создать private или protected метод. Видимо, из-за такой идеологии языка, и появилась возможность реализовать методы именно так — в методах есть полный доступ ко всем членам и методам класса.
---
http://twitter.com/xoposhiy
http://xoposhiy.moikrug.ru
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.