<<<предыдущий список следующий>>>

Это - копия документа, находившегося на http://dz.ru. Авторские права, если не указано иначе, принадлежат Дмитрию Завалишину и/или Евгении Завалишиной. Все изменения, внесенные мной, находятся в этой рамочке.Пожалуйста, прочитайте disclaimer.


25 Марта 1999

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

   
From: Teodor Sigaev
Subject: Re: Небольшой комментарий к проблеме двух значений

Рассмторенные тобой варианты возврата значений:

1)

int x, y; 
thing.get_coordinates( &x, &y );
printf("pos is %d-%d", x, y );
и

2)

printf("pos is %d-%d", thing.x(), thing.y() );

К сожалению, вариант (2) не годится для многопоточных приложений, для приложений, в которых измененение объекта thing происхидит по прерыванию или по событию, поскольку вероятна ситуация, в которой последовательные вызовы thing.x() и thing.y() могут относится к разным состояниям объекта ( во временном смысле ). Поэтому в таких случаях обязательно надо возврашать одновременоо два значения ( ну или инкапсулировать их в один объект :) ).

--
Teodor Sigaev
E-mail:mailto:teodor@machaon.ru
URL: http://www.machaon.ru/~teodor/

 

Хорошее замечание. И очень кстати.

Я, безусловно, согласен - вопрос атомарности существует и требует решения. Но решением в ОО является само ОО, а не костыли в виде возврата пар значений!

(Еще раз для функционально неграмотных: тут НЕ сказано, что ОО лучше всего на свете. Тут сказано, что ЕСЛИ ты пишешь ОО-но, то задача решается не так, а вот так.)

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

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

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

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

Вот берём те же координаты. Если атрибутом объекта является координата, то ее нужно выдавать на улицу отдельным методом саму по себе и нужно брать из объекта как win_pos.x(). При этом если необходима гарантия атомарности, то делаем тупое pos copy = win_pos; printf( ..., copy.x(), copy.y() );, и нет проблем. Обращаю внимание - скопировать придется только то, что реально является единым целым, не больше и не меньше. Если при копировании объекта класса pos скопировалось лишнее, очень велика вероятность того, что оно там действительно лишнее и должно быть не в этом классе. Возврата двух значений не нужно.

Если же атрибутом объекта являются координаты, то они выражаются через объект класса pos и возвращаются только как единое целое. При этом, конечно, никаких проблем с возвратом двух значений не может быть - это одно значение. Хотя никто не мешает написать win.pos().x(). Опять же, обращаю внимание - если код писать правильно и инлайнить всю эту шушеру, то эффективность такого кода тождественно равна win.pos.x.

Итого - я показал два корректных с точки зрения ОО варианта, и в обоих понятие "возврат двух значений" не танцует. Итого - если ты возвращаешь два значения из функции, значит программа плохо сдизайнена с точки зрения ОО. Еще раз для тех, кто комплексует - ЗДЕСЬ НЕ СКАЗАНО, ЧТО ОО - ЭТО ЛУЧШЕ, ЧЕМ САМОЕ ВКУСНОЕ МОРОЖЕНОЕ.

Заодно обращаю внимание тех, кто напрягается на design patterns - это всё проистекает не от умничанья, а от того, что эклектика обходится в конкретные деньги, а стиль оборачивается конкретным выигрышем. Писать можно как угодно, но критиковать методики хорошо только после того, как в них въедешь. На примере эдак тысяч двадцати строк кода.

Увы, ОО - одна из тех вещей, которые нельзя использовать наполовину. То есть можно, но это вызывает одну тошноту. Думаю, от того оно и вызывает отторжение у массы даже весьма опытных программеров. Если не сделать всех шагов до конца, то ОО программа запросто обернется ночным кошмаром. А сделать их трудно. Для этого нужно сильно перенести упор на проектирование и не писать кода, пока не напишешь почти всех хедеров (в случае с ++). Это зачастую крайне непривычно и напрягает. Мало того, писать код нужно, глядя на него с довольно специфических позиций, использовать инструменты нужно вкупе, а не по одному.

К примеру, множественное наследование у меня удачно применилось только после того, как я перешел на exceptions (долго рассказывать, почему так:), а exceptions потребовали переработать стиль кодирования чуть ли не от пола. Лично я потратил на въезжание в это всё несколько лет, это при том, что у меня никогда не было и тени сомнения в правильности подхода. Была куча сомнений в правильности применений конкретных инструментов.

Тупой пример. Те же исключения требуют врапперов на все "плоские" ресурсы. Нельзя написать

semaphore s;
   
   my_func()
   {
   ....
   s.lock();
   ... работаем с ресурсами ... 
   s.unlock();
   ....
   }

застрелишься за ним бегать и отпирать, в каждой функции будешь ловить все исключения и возненавидишь их, как рыбий жир. А заодно и всё ОО. Что, собственно, и наблюдается в форуме. :-) А надо всего лишь написать простой враппер. Одна строка.

class key { semaphore s; public: key( sema ) {s = sema; sema.lock();} ~key()    { s.unlock(); } }
semaphore s;
   
   my_func()
   {
   ....
   {
   key k( s );
   ... работаем с ресурсами ...
   } // Вот тут семафор отопрётся сам
   ....
   } 

Что важно. Семафор отопрётся сам, когда управление любым образом покинет блок. В частности, когда в блоке или вызванных ими методах случится exception, его не придется особо обрабатывать в данном месте. Но!! Решение чудесно тем, что не завязано на exceptions, и семафор будет освобождён при любом выходе из блока. Лично меня более всего волнует return, конечно, но есть и goto, break, continue.

Это - всего лишь одна небольшая иллюстрация одного частного аспекта. Призванная, не дай Бог, не показать, как именно что нужно делать, а показать, что поговорка "умный в гору не пойдет" весьма и весьма справедлива. Правильный подход правилен не потому, что написан в книгах, а потому, что облегчает жизнь. Сильно облегчает.

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

Меня тут спрашивали, что случилось с Уголком Дурева Соловьева. Жив ли, мёртв ли.

Отвечаю. Сольвьев с утра всё искал логотип Pentium III. Как только нашёл - сразу с ним набезобразничал. :-) Резюме: безобразничает - значит, жив. :-)

Вопрос из почты: "Насколько много в мире людей, желающих одновременно смотреть изображение на двух мониторах?".

При условии дешевизны решения - много. Один из вариантов описан в материале про G400 - когда человек купил себе монитор в 17", но старый 15"-ик никуда не девался и стоит в углу. Второй - подключение телевизора. Кроме того, существует масса профессий, для которых площадь монитора - расходный материал. Одна из них - программист. Отладчик, приложение, документация, исходники библиотек - нет проблем использовать пару мониторов по 17", уж не говорю о меньшем.

Кстати. Площадь экрана 15"-монитора - примерно 108 кв. дюймов. Цена - порядка $180 (можно найти и дешевле, но возьмем разумную). Это - 0,6 квадратного дюйма на бакс. Для 17" площадь - 138, цена - порядка 350 (это относительно недорогая модель), дюймов на тот же бакс получаем чуть менее 0,4. Это значит, что купив вместо 17" пару по 15 мы получаем примерно в 1.5 раза большую площадь экрана на ту же цену.

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

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

Кстати, для смеху - на цену дешевого 21" ($850) можно купить пять мониторов по 15, что даст площадь экранов, в 2,5 раза превышающую площадь экрана в 21". :-)

Мы давно мечтали и все никак не могли лаконично и в то же время емко сформулировать - что такое dz online? В одно предложение? Женька предложила спросить читателя. Спрашиваем. Как вам думается - что мы такое? Напишите!

Реклама, однако.

Юные и зрелые таланты из России!

Nanyang Technological University

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