Объектно Ориентированные Монстры


А я вот хочу опять к программированию вернуться. Кто мне может объяснить популярно концепцию объектного программирования? когда она на Паскале для PC появилась, было много шума, но никто толком мне не растолковал, чем это хорошо и вообще что это такое. Так до сих пор и не знаю.

Мах


Мах, тебя обманули. Объектно-ориентированное программирование появилось в Симуле-67 и впоследствии было развито в языке Smalltalk. Паскаль тут вовсе ни при чем. Более того, объектный Паскаль появился, когда уже был С++.

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

процедурный язык: Процедура Sort! Выполнись над массивом A!
объектный язык: Объект A! Посылаю тебе сообщение "Sort" и чтоб ты отсортировался!

ООП держится на двух основаниях: упрятывание данных и наследование. Упрятывание данных предполагает работу со всеми данными через процедуры. Соответственно, о реальном внутреннем устройстве данных знает только само данное (объект), но не тот, кто этим данным пользуется. В строгих, динамических ОО-языках вызов операций происходит путем посылки сообщений и является полностью динамической вещью. Есть у тебя объект А, ты шлешл ему сообщение Sort. Если он его понимает, он сортируется, как умеет. Таким образом, у тебя может быть два объекта, А и Б, один - массив, другой - список, а ты их сортируешь, не зная, каковы они.

Еще одна важная вещь - наследование. Это когда ты говоришь - объект А это такой же объект, как и Б, но вот эта операция делается по-другому. Весь остальной код переиспользуется, а вот эту операцию ты переопределяешь.

Соответственно, бывают классы, заранее заточенные под то, что их будут наследовать. Например, класс "геометрическая фигура" (это классический пример - все в ООП объясняется на геометрических фигурах, просто больше ни для чего ООП не годится) может иметь общие методы - передвинь, раскрась, еще что-нибудь, а также метод "нарисуйся", который ничего не делает. Мы пишем класс "круг", наследующий фигуру, и пишем в нем метод "нарисуйся", который рисует круг. Теперь если у нас есть объект-фигура, неважно какая, мы можем ей сказать "передвинься", и она сотрется на старом месте, передвинется и нарисуется на новом, независимо от того, круг она или квадрат.

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

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

То есть есть, допустим, класс "сортирующийся", а в нем ссылка на таблицу, а там, допустим, 20 методов, и, например, десятый из них - "Sort". Мы пишем клсаа "список", говорим, что он наследует "сортирующийся", у него тоже есть таблица, первые 20 входов в которую соответствуют методам базового класса (а в конец можно дописать и свои). Они могут совпадать с этими базовыми методами, а можно их и переопределить. В классе "список" метод "Sort" будет переопределен. Вот, в общем-то, и все. На самом деле, объектно можно писать на любом языке, даже на Фортране. ООП-языки просто берут часть работы на себя, упрощая синтаксис и создавая за тебя таблицы.

Бывают и системы, в которых ООП-языка нет, но объектная ориентированность присутствует. Например, Windows. Там реально летают сообщения, которые надо ловить и обрабатывать. И можно взять готовый класс окон и переопределить в нем реакцию на сообщение. Вот, в общем-то и все. Достоинства есть, недостатки тоже есть. Понять ОО-программу можно, только если ее автор очень аккуратен (как, впрочем, и не-ОО программу). Хотя в среднем ОО-программу понять сложнее, потому что никогда неясно, куда попадет управление. ООП несколько менее эффективно из-за функций доступа и косвенных вызовов. Но главное - пропагандисты ООП считают, что это - Великая Истина, Великое Новое Слово, и оно разом решит все наши проблемы, а на самом деле это, мягко говоря, не так. Это просто прием, которые может быть полезен в одних случаях, а в других вреден.

Африканец


Мах,
Еще про ООП. Рассмотрим такую проблему. Есть N операций (например, вставь вперед, вставь взад, отсортируй, напечатай) над M типами данных (массив, список, двусвязный список). Причем тип данных статически неизвестен - у тебя есть указатель на объект, который может быть любого из этих типов. Надо реализовать все эти операции. Ясное дело, обойтись без написания MxN кусков кода не получится. А проблема в том, как их организовать.

1) Пишем N процедур - sort, insert, etc. а в каждой стоит оператор CASE по типу параметра (разумеется, надо уметь у параметра узнать его тип), в этом CASE M альтернатив с соответствующим кодом. Вызоы будет таков:
sort (a);

2) иметь CASE не в процедуре, а в объекте. Простейший вариант - иметь при каждом объекте одну процедуру do, в которую передавать, что нужно сделать, а в ней иметь CASE по типу операции. Вызов будет таков:
a.do ("sort");

Вот первый подход называется процедурным, а второй - объектно-ориентированным. Именно этот способ - с одной процедурой и явным CASE в нем - и используется в Windows.

Можно второй способ чуть видоизменить - в отличие от CASE по типам, CASE по процедурам можно удобно сделать с помощью таблицы функций. Тогда на ОО-языке будет запись вроде
a.sort ();

а на неОО-языке - как-то так:
a.function_table[1]();

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

Реально ООП хорошо для пользовательских интерфейсов, всяких манипуляций окнами и т.д. я пока не встретил ситуации, где еще оно хорошо.

Африканец


Африканец, мне кажется, что Мах сказал не "ООП появилось в природе и на Турбо Паскале одновременно", а что-то вроде "Вот и до Паскаля под ДОС доползла гидра ООП".

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

Пингвин


А в общем, Мах, возьми почитать книжку по Жабе где-нибудь. Там сам все и увидишь. Сейчас этих книг миллион. Все равно скоро кто Жабы не знает - будет как бы и не человек. И даже ученых при приеме на работу будут спрашивать: "Жабу знаешь?" и ставить жирный плюс, если да. Это же великое, общемировое сумасшествие.

Африканец


Африканец, спасибо. В общем, я так понял, что это очередное втюривание, которое может быть - а может и не быть - полезно. То есть концепцию подпрограммы я понимаю, знаю, как она работает, и полностью признаю. А вот с этим ООП - проблема. Не видел я еще случая, что б оно давало ощутимые преимущества. Но у меня и задачи спесфические, я ж таки не программист. Так, ежели посчитать что простенькое - так пишу сам на паскале (си в принципе знаю, но реально пользовать умею не очень). А простенькое - это там данные в АЦП ввести, шаговик повернуть, по быстрому фурье что посчитать или решить систему из 6-ти дифференциальных уравнений. Последние два - так это просто берешь книжку Численные методы и оттуда все сдуваешь. Вот был еще великий язык - ФОРТРАН, поскольку умел по умолчанию с комплексными числами управлятся. Так нет, пришли всякие программисты, сказали: язык - говно, на нем системно программировать неудобно, - и захирел язык.

Про Жабу - типун тебе на язык. Да и сейчас можно встретить объявы типа: знание Си++ и умение программировать под Windows являются преимуществами. Я такие места аакуратно обхожу стороной.

Мах


Африканец - а разве не проще при ООП писать всякие игры, где есть какой нибудь объект типа монстр, который реагирует н внешние воздействия? И задавать всякие процедуры типа

if not монстр.окочурился then
герой.тикать_отседова
end if

Так и быстрее должно быть.

"Я"


Мах - вот как раз комплексные числа на C++ (но не Жабе) удобно реализуются (и наверняка уже кем-нибудь реализованы). Заводишь класс complex и в нем переопределяешь операторы +, -, *, =, и другие, и функции sin, cos, и тоже и другие. Чтобы все сделать чисто и аккуратно, переопределять придется довольно много. После этого текст программы становится очень симпатичный, с операторами типа a=b+c, независимо от того, действительные у тебя a,b,c или комплексные.

Итальянец


Мах,
Во-первых, никуда Фортран не делся и не захирел. И, думаю, не захиреет. И для численных расчетов лучше языка пока что нет. Более того, все новые версии Фортрана продолжают появляться. Фортран-77, затер 80, затем 9X... Всякие векторные и параллельные вычислители всю дорогу на нем программировались, потому что его удобнее векторизовать и параллелизовать.

Африканец


Мах,
Еще комплексные числа есть в ISO Modula-2. Ну и в PL/1, естественно.

Африканец


С Фортраном все ж таки проблема. На PC стоят громоздкие трансляторы. Как это было давным-давно? надо сначала написать программу в редакторе, потом прогнать ее через транслятор, потом исправить ошибки, потом снова транслятор, потом линковщик, потом опять ошибки, потом запустили, получили деление на нуль где-то (а где - неясно), и поехали по новой. Сред, вроде как есть для Паскаля и Си, я не встречал. То есть у Си (или Паскаля) есть явное преимущество: я отлаживаю программу на PC, а потом заменяю пару операторов ввода-вывода, и гоню все на 32-процессорный Крей. В моем случае все еще более идиотически: изначально текст пишеться на Паскале, отлаживается, потом переводится на Си (есть, есть такие трансляторы!), и запускается на Крее. В сумме получается гораздо удобнее, чем все делать на Крее с самого начала.

Мах


Я",
Херовые игры - да, проще. Те, в которых все ортогонально. Монстр есть или нету, тикать или не тикать, и объект с объектом всегда взаимодействует через выделенный, довольно узкий, интерфейс. А в хороших игрушках от одного монстра можно так тикать, от другого - по-другому, в общем, много частных случаев и учета особенностей обстановки. Как в жизни.

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

Африканец


Мах,
срееед тебе... заелся... Никогда С из командной строки не запускал? Вот уж, приделать Фортран к какой-нибудь оболочке - плевое дело, и оболочек таких, к которым можно компиляторы приделывать - множество. Я сам одну написал. Тебе всего-то надо чтобы оболочка умела сообщения компилятора об ошибках понимать и в исходный текст тыкать. Это запросто. Можно к МультиЕдиту макрос приделать, или, скажем, к Емаксу.

Африканец


"Я" - не будучи специалистом-игрописцем, я бы игру примерно так и писал. На самом же деле подозреваю что у серьезных игр некое ядро, включая это твое if монстр.окочурился, написано на ассемблере или на смеси ассемблера с C, причем оно практически одинаково скажем у Doom и Quake, а все остальное - на некоем специализированном языке супервысокого уровня. Типа пишут просто монстр(картинка, скорость передвижения, оружие, количество жизней), и вот он стоит, как живой. В самом объекте "монстр" кода нет или очень мало, то есть скорее всего он - структура, а не объект. Например, совершенно не нужен метод монстр.окочурился. Потому что все монстры имеют счетчик здоровья или еще что. Не нужно монстр.попала(пуля), потому что у всех монстров есть координаты и размеры, и есть одна на всех функция попала(пуля, монстр). Плюс этого - программист пишет ядро и уходит писать следующую игру или вообще в другую фирму. Далее он не нужен.

Кусок ядра:

if (действие = выстрелил)
{ for (все монстры)
if (попал(действие, монстр))
{if (!(--монстр.жизни)) DeleteMonster(монстр); }
}

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

When герой_наступил_на(координаты),
{СоздатьМонстра("ujebische", 100);}
When монстр_сдох("ujebische")
{СыгратьПесенку("калинка-малинка");}

Итальянец


Африканец - дык для Duke как раз объектность полезней, чем для Doom. В думе, где правила для всех одни - зачем объектность? Полиморфизму там нет. А в дюке - типа - все комнаты - класс room, а где деньги девушке дать - там class room_with_a_girl: public room с одним лишним методом (который возможно создает объект girl). А где в биллиард поиграть - там room_with_billiard, где этот метод создает класс billiard, который с тобой взаимодействует. Интерфейс что у girl что у billiard, что у door - на самом деле один и тот же - KeyDown да MouseDown.

Итальянец


Маху дал. Конечно, не Room_with_a_girl, а просто

class Room {
...
thing list_of_things [];
}

и каждой thing сообщать, мол, я нажал на кнопку.

Итальянец


Насчет монстров.
Ну представьте себе - есть монстр, ведет себя стандартно. У него есть совершенно стандартный набор методов - "в тебя попали гранатой", "в тебя попали из пулемета". И так далее. А теперь представьте, что мы хотим добавить мелкуб деталь - если конкретно этому монстру конкретный вид персонажа ударит кочергой в левое ухо, то монстр скажет "Твою мать!". Вот тут-то и накроется ваше ООП медлым тазом. Будете всем монстрам метод писать - "Тебе вон тот ударил кочергой в ухо". Ну или, хотя бы, вставлять разборки, куда именно его ударили и чем. При том, что для остальных монстров неважно, куда попали и чем. Вот это я и называю "жертва структурности" - для того, чтобы реализовать один частный случай, заточки на него вставляются всюду. И потом они из всех щелей начинают выползать.
Вообще аккуратное программирование - это тщательный учет всех частных случаев. Попытки число этих случаев сократить за счет какой-то унификации приводят к тем программам, которые мы видим. К тем, что кипятят чайник, сливая воду и наполняя вновь, к тем, что выдают сообщения вроде "Ошибка при выполнении операции: операция закончилась успешно", к компиляторам, выдающим дубовый, неэффективный код.

Африканец


Африканец - а очему же ООП накроется медным тазом? Ну создаст еще один тип монстра с дополнительным методом. А скорее всего просто будет у всех монстров функция или метод
Монстр№$нутый(ТипОружия, Куда$#нули). Ну а у данного конкретного монстра так это того Изоморфизьм

"Я"


Африканец - ну ты же знаешь, что это не единственный способ. В Windows же нет событий WM_KEY_A_PRESSED, WM_KEY_B_PRESSED, WM_KEY_CTRL_SHIFT_F7_PRESSED. Есть просто WM_KEYPRESSED. Так и здесь. Пусть у всех монстров будет метод
void poluchil(coord куда, weapon чем, hero от_кого)
И у монстра Monster параметр weapon игнорируется. Получил и получил. Ну, лишний параметр передали (если жаба душит из-за этого, можно и не передавать - пускай он сам спросит). А у монстра Monster_S_Nezhnym_Uhom будет примерно так:
void poluchil(coord куда, weapon чем, hero от_кого)
{
if (куда==ухо && чем==кочерга && от_кого==африканец)
say("твою мать, африканец");
else //или не else
Monster.poluchil(куда, чем, от_кого);
}
А у объекта Monster_S_Nezhnym_Zadom этой разборки не будет, а будет другая. А еще у кого-то poluchil вообще не будет переопределен, а будет переопределен pobezhal или sozhral.
Ну допустим мы это пишем не объектно. Тогда что? Все равно ведь будет Monstr_S_Nezhnym_Uhom_Poluchil(...)
{
if (в ухо)
say("твою мать")
else
Obychnyj_Monstr_Poluchil(...)
}
Ничем ведь не лучше.

Итальянец


Ну вот - Я написал про процедуру в 16-01, а Итальянец в 16-02, введя дополнительный параметр "чем". В итоге делаем вывод, что количество параметров у этой функции будет увеличиваться со скоростью 1 параметр в минуту. Представляю сколькими параметрами обрастет эта функция через день!

"Я"


Итальянец, "Я",
Вот видите - первоначально не планировалось различать, куда конкретно получил. Теперь пришлось. Базовый класс монстра модифицирован. А всего-то надо в процедуре удара того, кто бьет, проверить, не нужного ли монстра он бьет, и посмотреть куда. Хорошо, другой пример. Один персонаж, и только он, видит одного монстра, и только его, полупрозрачным и красным, когда тот монстр находится на фоне Эйфелевой Башни, в радиусе 1км от него находится хотя бы один "Феррари" и этот персонаж имеет в распоряжении прибор "монстроскоп" с количеством энергетических кристаллов, не меньшим семи?

Вы же понимаете, что все это можно продолжать до бесконечности. Сложность взаимодействия можно увеличивать, и каждый раз вам потребуется брать superset всех возможных взаимодействий и предусматривать их в каждом случае. А зачем?

Африканец


Африканец - погоди. Нет нужды делать все возможные данные параметрами метода базового класса. Только то, что используется всегда или часто. Опять таки, по аналогии с клавой - в момент получения WM_KEYPRESSED тебя может интересовать количество свободной памяти. Но оно же не передается как параметр события. Надо будет - спросишь.

Так и здесь. Объединив твое первое задание со вторым - допустим мы написали в базовом классе poluchil(куда, чем, от_кого). А тут эти твои - Эйфелева башня с энергетическими кристаллами, и т.п. Значит, в подклассе, и только в нем, мы пишем
void poluchil(куда, чем, от_кого)
if (в ухо)
{
Point ГдеЯ = GetCurrentCoordinates();
Thing * феррари=FindNearestObject(ГдеЯ, "феррари");
Monstroscope * монстроскоп=
(Monstroscope *)от_кого.GetWeapon("монстроскоп");
if ( монстроскоп && монстроскоп->кристаллы>7 &&
феррари && ГдеЯ.Distance(феррари->GetCoordinates())<1)
say("merde")
else
say("твою мать")
}
else
{
Monster.poluchil();
}
}
Если тебя заинтересовал еще и цвет монстроскопа - добавляем здесь же еще одно условие в if. Ничем это принципиально не отличается от того же кода без объектов. Кроме дисциплины - код этого монстра - здесь. Код другого монстра - в другом месте.

Итальянец


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

"Я"


Так в том-то и дело, Итальянец, что может оказаться код этого монстра (часть этого кода) разместить вовсе не у монстра, а у того, кто с монстром взаимодействует - у персонажа.
Вообще, мы имеем бинарное (в простейшем случае) взаимодействие:
что-то (монстр, персонаж)
С равным успехом мы можем разместить код:
- при монстре
- при персонаже
- при уровне
- при монстроскопе
- при феррари
- при эйфелевой башне
- где-то еще
Так вот, размещать надо там, где удобнее, и где придется модифицировать минимум уже написанного кода. Надо где-то еще - будем где-то еще. Любые, я подчеркиваю, любые внешние ограничения ("только у монстра и больше нигде!") только наносят вред. Все должно делаться, исходя из здравого смысла, а не идеологии.

Африканец


Африканец - дык на это есть хорошая поговорка - насчет заставь дурака богу молиться. Естественно, надо там где удобно и только там. Разработчику и тем, кто после него будет дописывать и поддерживать. Где ж я утверждал обратное? Любой СНОП (самый настоящий объектный программист) с моим этим кодом знаешь что сделал бы?
Если человек пишет объектно, потому что так у него (или его фирмы) лучше получается, то он действительно напишет эту проверку там, где удобнее. Может и в феррари. Может и вне всяких классов. Может и в монстре. Может даже отдельный класс создать. Мне удобней было бы большинсто таких вещей инкапсулировать куда либо. Но, возможно не все. И - ты прав - надо еще подумать куда. Так на то человеку мозги даны, чтоб думать. И конечно, писать без мозгов объектно так же плохо, как и процедурно.
А если человек пишет объектно, потому что это модно, да еще и не умеет при этом писать ни процедурно, ни объектно, то результат, конечно, будет тот еще. То есть я за объектность как еще одно средство программирования, а не как ограничение - пишем объектно и больше никак. Из того, что есть придурки, которые неправильно используют ООП, не следует, что идея плоха. Есть ведь и которые хорошо используют.

Итальянец


"Я",
Правила идиотскими не бывают. Программист для разработчика, а не наоборот. Он задумал - ты будь добр, напиши. Если мы будем упрощать правила, чтобы попроще было написать программу, то вместо программы для преферанса сделаем "пьяницы".
Насчет же ООП ты прав. Действительно, можно писать с, а можно без. Разницы почти не будет. ООП - не чудо, а просто технологический прием. К сожалению, мэнеджеры этого не очень понимают, и кричат "ООП! ООП!", полагая, что это им резко поможет. Я, в сущности, именно против этого и выступаю. Не надо нам идолов. Между прочим, легкость понимания и модификации ОО-программ преувеличена. Читать программу с неизвестной структурой управления крайне тяжело, а изменять ОО-программу очень легко только в направлениях, в которых она была специально заточена на изменение. Во всех остальных направлениях ее изменять ОЧЕНЬ СЛОЖНО - гораздо сложнее, чем не-ОО программу.

Африканец


Африканец - а, я понял. Тебе мое "дисциплина" не понравилось, и возможно, я себе противоречу слегка. В общем, я так это понимаю. Допустим, дисциплина нам говорит - в большинстве случаев поведение монстра определяется внутри его. Но возводить это в абсолют и принимать к нарушителям дисциплинарные меры нельзя. Если нам где-то удобнее им поуправлять из другого класса или извне класса - пожалуйста. Но если человек _постоянно_ лазит в монстра из объекта феррари, то что-то не так или с этим человеком, или с тем, кто ему приказал так делать, или с тем, кто определил интерфейсы так, что иначе не получается.
Мой любимый язык программирования - С с очень маленькими плюсами. То есть что-то в объектах, что-то нет. Уверен, если б меня заставили чтоб все всегда было в классах да еще предписали бы, в каких именно, я бы завыл.

Итальянец


ах - при том, что у нормального монстра, а не этого с больным ухом в методе poluchil написано примерно следующее
if (!(--lifes))
Die();
else
Cry();
При этом Die, Cry, и lifes - соответственно методы и элемент класса монстр. Другие их не знают (это инкапсуляция). Монстр с больным ухом имеет те же методы и элемент. Но плюс к тому он сначала проверяет свое ухо, потом вызывает тот же код. При этом нам не надо ничего делать для того, чтобы у него работали скажем методы Shoot или Roar - он их наследует у обычного монстра. Таким образом, для монстра с чувствительным ухом мы дописываем только код, относящийся к его уху (это наследование). Данные общие для всех монстров пишутся один раз. Далее. Где-то в программе мы говорим. monster.poluchil(от меня, в ухо). Не зная, с ухом он или с носом или обычный. И он сделает то, что надо (это полиморфизм).
Но ты наверное и так это знаешь.
Вообще мы по-моему напряглись с этими объектами.

Итальянец


созерцатель:
>А сказал это Бог Свету. Больше выло некому. Так вот и сказал: "Свет! Будь!" И стал свет.

Африканец
>процедурный язык: Процедура Sort! Выполнись над массивом A!
>объектный язык: Объект A! Посылаю тебе сообщение "Sort" и чтоб ты отсортировался!

Выходит, Бог создавал мир объектно-ориентированым способом.

Guinevera


Выходит, Бог создавал мир объектно-ориентированым способом.
Guinevera

Ну да! "Что было, то и будет, и что делалось, то и будет делаться, и нет ничего нового под солнцем"

созерцатель и Екклизиаст


Об объектно-ориентированности в сотворении.
Бог сказал:"Да будет свет". С одной стороны нигде не говорится, что он это сказал свету. Иначе было бы:"И сказал Бог свету - будь!". Но все одно - с человеческой точки зрения нельзя сказать несуществующему - будь. Поэтому для классов "Директивы_Бога" и "Директивы_человека" выполняется конструктором перегрузка оператора "будь". Как в C++. И тогда можно Богу использовать "будь" к свету, которого еще нет.

МоржМиша


C Рождеством BCEX православных, то есть славящих право!
Чисто у моего папы сегодня день варенья был, так что я так кумекаю - у Вована день рожденья сегодня, у Христоса - завтра!
Первый день творения, воилас.

А про примат слова ни фига нет в Библии, может, у нас адаптированное издание для чудакофф?

Была Жаба и package java.all
И выполнился метод java.all.createGod();
И стал Бог.
И Бог взял Жабу и написал:
// class theFirstDay
import java.all.*;
public class theFirstDayOfCreation {
public static void main (String[] everything) {
final int luminescence = 10;
createSky();
createEarth();
System.out.println ("Let the light be!");
Light newLight = new Light (luminescence); // передача интенсивности света в качестве параметра
newLight.setName ("light"); // и назвал, собственно...
Night newNight = new Night (false); // наличие света = нет
newNight.setName ("night");
if (getCurrentTime() > 5) setEvening(); // если позже пяти - вечер
else setMorning(); // иначе - утро
this.evaluate(); // посмотрел и сказал, что...
if (this.evaluate() == "suxx")
throw new badWorldException();
else
System.out.println ("Рулез!");
} // end of main
} // end of class
second day follows...

Stan