как грамотно спроектировать вызов статичных методов наследуемого класса

cursedj

Новичок
Повторяю для тех кто Crazy :) . Полиморфность -- это разное содержание одной и той же формы. Если у нас есть совмещенные функции (не виртуальные) -- это полиморфность, если у нас есть виртуальные функции перекрытые в производных классах -- это то же полиморфность. Разница в только в диспетчеризации вызовов, в первом случае получаем диспетчеризацию во время компиляции, во втором - во время выполнения. RTFM, батенька, RTFM.

Полиморфизм в твоем понимании -- это определение нужного метода во время выполнения.

P.S. Не бойся словами я тебя не пугаю, но если мы говорим об устройстве автомобиля, то не будем же называть двигатель "большой хреновиной там под крышкой" :)

P.P.S. Не понял меня народ, закрыли тему про недостатки PHP. Недостатки нужны для того что бы их исправлять, а не повод разводить флейм:( . Я всего лишь хотел, что бы каждый высказал свое мнение об ограничениях PHP, о том чего ему не достает в языке. Есть идея добавить эти возможности своими силами. Ведь от разработчиков PHP дождешся улучшений!! А как же! Проще с нуля самому создать:mad:. На меня тут же накинулись, мол "какой хороший язык критикуеш", "пшел вон, недовольный", "а-а-а, неверный!!":). Наверное не там постил, или неправильно тему начал.
 

Crazy

Developer
Автор оригинала: cursedj
Повторяю для тех кто Crazy :)
Да ты, наверное, в старшей группе детского сада был чемпионом по юмору. Круто.

Полиморфность -- это разное содержание одной и той же формы.
...какой нет в случае, если сигнатуры методов разные. Add(int,Strring) и Add(String) -- два разные формы. Поэтому настоящего полиморфизма в смысле, который придает ему ООП, здесь нет. Еще раз:

1. Есть три типа полиморфизма: динамический, статический и параметрический.
2. Для всех трех типов характерно повторное использование для разных целей одного и того же идентификатора
3. Статический и парнаметрический полиморфизм не имеют никакого отношения к ООП. В частности, потому, что они вознкли в не-ООП-языках.
4. Полиморфизм, о котором говорится в трех постулатах ООП, это динамический полиморфизм. Без вариантов.

-~{}~ 14.06.07 15:55:

Автор оригинала: cursedj
Поэтому упомяну только наиболее значительные:
Во первых -- перегрузка методов.
Это, как я уже сказал, в топку. По опыту последних 10 лет, перегрука методов вызывает больше труднообнаружимых логических ошибок, чем любой другой прием программирования.

Во вторых -- динамическая типизация.
Что в данном случае имеется в виду под динамической типизацией?

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

В-четвёртых -- Unicode.
Определенно. Язык для веб-разработки, использующий однобайтовую кодировку для строк, трудно назвать полноценным.

В-пятых -- НОРМАЛЬНАЯ поддержка ООП. (финальные методы есть, финальные классы есть, а финальных переменных объекта - нет;
Финальные переменные -- в отличие от констант a la C++ -- есть благоглупость. Вызывает больше проблем, чем решает. Опыть же -- по реальному опыту.

список можно продолжать...)
Ждем-с. Мне интересно, появится ли в нем единственный пункт, который действительно делает программирование на PHP, Java, C++ и т.п. неполноценным в плане использования ООП.
 

cursedj

Новичок
Форма одна и та же -- имя метода, а сигнатура используеться для диспетчеризации (во время компиляции в C++, но это НЕ ОБЯЗАТЕЛЬНО выполнять во время компиляции), при динамическом полиморфизме используеться иная характеристика -- фактический тип объекта. При этом две формы полиморфизма можно совмещать,
когда метод совмещаеться по сигнатуре и по фактическому типу объекта.

Но, если использовать строгую терминологию, и считать, что ролимофизм в ООП -- это только динамическая его форма (что справедливо для динамических скриптовых языков таких как PHP, Ruby и Python, на последнем, кстати приведенны все примеры в артикле о трех постулатах ООП), я полностью согласен, но такой взгяд на полиморфизм считаю несколько ограниченным.

P.S. В этих вопросах wikipedia для меня не авторитет.
 

Crazy

Developer
Автор оригинала: cursedj
Форма одна и та же -- имя методах., а сигнатура используеться для диспетчеризации (во время компиляции в C++, но это НЕ ОБЯЗАТЕЛЬНО выполнять во время компиляции),
Это нужно обязательно выполнять во время компиляции, поскольку нет абсолютно никакого смысла делать это во время исполнения (опровергай, если желаешь).

Имя метода -- это именно Add(int,String). :)

при динамическом полиморфизме используеться иная характеристика -- фактический тип объекта. При этом две формы полиморфизма можно совмещать, когда метод совмещаеться по сигнатуре и по фактическому типу объекта.
При этом важно понимать, что статический полиморфизм на этапе компиляции уничтожается полностью. В скомпиоированном файле Add(int,String) и Add(String) имеют не больше общего, чем имели бы AddAt(int,String) и AddAtEnd(String). Для компилятора, повторяю, полным именем является Add(int,String), а не просто Add -- какой бы богатой не была бы поддержка RTTI.

Динамический полиморфизм, в отличие от этого механизма, раскрывает перед нами те возможности, ради которых создано ООП.

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

Итак, по результатам у меня осталось к тебе два вопроса:

1. В каком случае есть смысл откладывать обработку статического полиморфизма на период исполнения?
2. Как на счет того, чтобы продолжить список пунктов, по которым реализация ООП в PHP не является полноценной?
 

cursedj

Новичок
1. Есть такая идея. Если рассматривать вызовы методов как посылку сообщений объекту, то может быть полезной динамически задавать сигнатуру метода (сообщение с динамическим количеством и типами параметров), при этом выбор метода во время выполнения будет происходить по его сигнатуре. Например, так:
Код:
class Frobnicator
{
    int getFoo(Object* c);
    int getFoo(String* c);
    int getFoo(Blob* c);
}

//...
Object *objs[] = new Object[] { new Object(), new String(), new Blob() };
foreach (Object *obj in objs)
     puts(frob->getFoo(obj));
Правда такое в C++, невозможно.

2. Можно и без финальных переменных, но вот константы класов в PHP могут быть только примитивных типов (int, float, string). Поясню про пространства имен, я имею в виду вложение классов и интерфейсов, а также логические пространства имен -- те что namespace в C++, а модули, в моем понимании, это аналог скомпилированных модулей, то есть средство физического разделения компонентов системы, в то время как пространства имен -- логическое, для того что б "разложить все по полочках".
И про динамическую типизацию. Имееться ввиду возможность явной привъязки типа к переменной, например
Код:
 var $str = "string";
var $int = 10 + $str; // Предупреждение! неявное привидение string к int.
var $double = 3.14;
$double = $str; // Предупреждение! Изменение типа переменной
var $double = $str; // А так возможно! var -- оператор привязки типа к переменной. Явное декларирований намерений.
Вот такая идея, может я где-то ошибся?

P.S. Вспомнил. Статический полиморфизм применяеться при совмещении операций:
Код:
class EverithingAdd
{
     EverithingAdd& operator+(String *s);
     EverithingAdd& operator+(int x);
     //EverithingAdd& operator+(double x); 
     // если добавить посл. метод, то измениться поведения кода:
     // EverithingAdd everithing;
     // everithing = everithing + 10.0;
     //...
}
Согласен может вызвать проблемы при определении того, какой метод должен быть вызван, но в основном
эти проблемы возникают при автоматическом неявном приведении типов.
 

Crazy

Developer
Автор оригинала: cursedj
1. Есть такая идея. Если рассматривать вызовы методов как посылку сообщений объекту, то может быть полезной динамически задавать сигнатуру метода
Это есть в некоторых языках (в Sather, если не ошибаюсь), но, если мне не изменяет мой склероз:

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

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

2. Можно и без финальных переменных, но вот константы класов в PHP могут быть только примитивных типов (int, float, string).
По уму, константой должна быть возможность сделать все, что угодно -- от числа до функции или объекта. Но напрямую к ООП это не имеет отношения.

И про динамическую типизацию. Имееться ввиду возможность явной привъязки типа к переменной, например
Код:
 var $str = "string";
var $int = 10 + $str; // Предупреждение! неявное привидение string к int.
var $double = 3.14;
$double = $str; // Предупреждение! Изменение типа переменной
var $double = $str; // А так возможно! var -- оператор привязки типа к переменной. Явное декларирований намерений.
Не понимаю, почему мы говорим про динамическую типизацию. Это все статика, выполняемая на этапе компиляции. Это есть во всех языках семейства ML. Вообще, сама концепция type inference (этим умным словом называется эта методика) мне очень импонирует, хотя применительно к ООП с ней не все до конца ясно. Собственно, поэтому это нашло применение в основном в не-ООП языках.

Что касается лично моего взгляда на недостатки ООП в PHP, то здесь недостает полноценной (в том числе -- в плане синтаксиса) реализации замыканий. А без них ООП неизбежно принимает невоворотливый вид, либо приходится забивать на некоторые основные принципы.
 

cursedj

Новичок
А это тоже статика?
Код:
class Bar extends Frobnicator {
   function __tostring() {
      return (string)($this->counter++);
   }
}
if ($isItTrue) {
  var $foo = new Bar();
} else {
  var $foo = "hello";
}

print $foo;

P.S. Кстати о замыканиях они же closure, они же методы обратного вызова (в смысле удобны для этого), они же отличное средство реализации итераторов и функционального программирования. Каюсь, забыл о них, так как причислял их к средствам функционального программирования (ошибся). Без них действительно приходиться "идти длинным путем". (Хотя .NET решает эту проблему на уровне синтаксиса, там итераторы просто преобразуються компилятором в соответсутвующий набор классов и методов, а в .NET 2.0 уже есть такое -- анонимные методы).
 

Crazy

Developer
Автор оригинала: cursedj
А это тоже статика?
Код:
class Bar extends Frobnicator {
   function __tostring() {
      return (string)($this->counter++);
   }
}
if ($isItTrue) {
  var $foo = new Bar();
} else {
  var $foo = "hello";
}

print $foo;
Именно статика. И на "print $foo" ты получишь ошибку, поскольку невозможно определить тип $foo.

Type inference, если он работает только иногда, лишен практического смысла.


Что касается замыканий, то это единственный способ элегантно следовать правилу "не интересуйся внутренним состоянием других объектов". Согласно принципам ООП, объект A не должен интересоваться состоянием объекта B. Он должен давать ему указания. В качестве примера возьмем класс Account, который, среди прочего, умеет снимать со счета деньги.

Совсем плохая реализация (здесь и далее -- PHP-образный псевдокод):

Код:
if ($account.amount >= $value) {
  $account.withdraw($value);
  $form->show_success();  
} else {
  $form->show_error();  
}
Получше, но тоже плохо:

Код:
try {
  $account.withdraw($value);
  $form->show_success();  
} catch {
  $form->show_error();  
}
Решение в стиле ООП, с замыканиями:

Код:
$account.withdraw: $value success: [ $form->show_success(); ] error: [ $form->show_error(); ]
Мы даем объекту $account четкое укаказание: снять деньги. И говорим, что делать в каждом из двух исходов. При этом нас не интересует, сколько денег на счету и мы не хотим, чтобы нас об этом даже косвенно (исключением) информировали.
 

cursedj

Новичок
Вся суть в операторе var, он задает тип переменной во время выполнения, и если, к примеру оператор print принимает только строки, то интерпертатор динамически определит какой тип у переменной $foo на момент обращения к оператору print, и выполнит соответствующие действия: просто возвратит значение переменной, если у нее строковой тип, или вызовет метод __tostring(), если это -- экземпляр Bar. А оператор var выполняет лишь декларативную функцию: указывает, что с этого момента переменная имеет такой то тип, и попытка использовать ее в неподходящем контексте вызовет предупреждение (или даже ошибку). При этом -- никаких безконтрольных автоматических преобразований типов, преобразование выполняеться автоматически только если соответствующий тип его поддерживает (например, для PHP это можно реализовать как "магические" методы -- __toint(), __todouble(), __to(Class $other_class))

P.S. var -- такого оператора в PHP, нет это только идея.
 

Crazy

Developer
Все сказанное выше вполне вписывается в статическую модель. И если ты начнешь писать настоящий реальный код, то увидишь, что статики достаточно. Остальное -- извращения, которые снижают надежность кода и сводят ценность контроля типов к нулю.
 

dark-demon

d(^-^)b
cursedj, как быть со случаем, когда функция может вернуть значения разных типов?

Crazy, не вижу преимуществ замыканий перед принятым для пхп:
Код:
if ($account.withdraw($value) $form->show_success();  
else $form->show_error();
да и вообще, не понятно, что ты вкладываешь в это понятие...
 

Crazy

Developer
Приведенный тобой код нарушает инкапсуляцию. Выполнив его, я фактически спрашиваю: а было ли достаточно средств для снятия?

Что я вкладываю в понятие замыкание? Стандартный смысл.
 

dark-demon

d(^-^)b
Приведенный тобой код нарушает инкапсуляцию. Выполнив его, я фактически спрашиваю: а было ли достаточно средств для снятия?
нет, ты спрашиваешь "был ли success" - то есть то же самое.

Что я вкладываю в понятие замыкание? Стандартный смысл.
просто никогда не рассматривал замыкания в контексте от создания функций, потому как
В программировании, Замыкание (англ. closure) — это процедура, которая ссылается на свободные переменные в своём лексическом контексте.
Свободные переменные упрощают начальный процесс написания программы но существенно осложняют её дальнейшее развитие и отладку.
 

bkonst

.. хочется странного?...
Автор оригинала: dark-demon
нет, ты спрашиваешь "был ли success" - то есть то же самое.
Не то же самое. Предположим, что бизнес-логика поменялась - добавилось новое условие для успешного снятия (скажем, лимит операций в день), и новый исход - подозрение на жульничество. В первом случае конструкцию придется переписывать полностью, во втором - только добавить обработку еще одного исхода. Если в первом случае забыть где-то что-то поменять, то программа продолжит работать с неверными данными: здравствуй, здоровый секс при отладке! Во втором случае мы получим ошибку (или при компиляции, или при выполнении) - но в нужном месте.
 

Crazy

Developer
Автор оригинала: dark-demon
нет, ты спрашиваешь "был ли success" - то есть то же самое
В этом и состоит принципиальная ошибка. Я ни о чем не спрашиваю. Я даю два блока кода -- один должен быть исполнен при успехе, второй -- при отказе. Вызывать их будет сам account или в свою очередь делегирует кому-то. Более того, возможна ситуация, когда к моменту вызова одного из этих блоков вызывающий объект уже удален сборщиком мусора.

просто никогда не рассматривал замыкания в контексте от создания функций
Правильнее будет сказать не "функций", а "подпрограмм". Так, процедурные блоки в ruby -- именно closures.

В программировании, Замыкание (англ. closure) — это процедура, которая ссылается на свободные переменные в своём лексическом контексте.
...
Свободные переменные упрощают начальный процесс написания программы но существенно осложняют её дальнейшее развитие и отладку.
Вторая часть утверждения -- чушь. Точно так же, можно с полным правоим утверждать, что "Foobar упрощают начальный процесс написания программы но существенно осложняют её дальнейшее развитие и отладку", где вместо Foobar подставить на выбор: "атрибуты объекта", "локальные переменные", "глобальные переменные" и т.п.

Языки типа Scheme вообще построены вокруг концепции closures и использования этих самых "свободных перенных из лексического контекста". В качестве примера могу порекомендовать MIT'овский учебник (если нужно -- найду точное название).
 

phprus

Moderator
Команда форума
Crazy
Получше, но тоже плохо:
code:
try {...} catch {...}
Решение в стиле ООП, с замыканиями:
code:
$account.withdraw: $value success: [ $form->show_success(); ] error: [ $form->show_error(); ]

Мы даем объекту $account четкое укаказание: снять деньги. И говорим, что делать в каждом из двух исходов.
Я все-же не понимаю чем в данном случае исключения хуже замыканий? В первом случае мы же тоже даем четкое указание снять деньги и также говорим что делать если произошла какаято ошибка.
Помоему решение с исключениями будет лучше, так как с большой вероятностью в $form->show_error() надо будет передать информацию о том, что же произошло. Помоему если использовать исключения то это можно будет сделать проще.
Или я в чем-то не прав?
 

dark-demon

d(^-^)b
phprus, а ничем :) это они и есть.

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

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

Более того, возможна ситуация, когда к моменту вызова одного из этих блоков вызывающий объект уже удален сборщиком мусора.
это типа "зачать посмертно"? ^_^

Языки типа Scheme вообще построены вокруг концепции closures и использования этих самых "свободных перенных из лексического контекста".
это говорит не в его пользу. банальный пример: в большом куске кода у нас есть маленькая функция. и (о боже!) мы забыли проинициализировать переменную. в случае php - да ну и пофиг - переменная будет проинициализирован стандартным дефолтным значением и при попытке чтения будет выдан нотис. в случае замыкающихся языков - получите рандомный мусор в переменной без каких-либо предупреждений.

В качестве примера могу порекомендовать MIT'овский учебник (если нужно -- найду точное название).
если на буржуйском, то можешь не стараться - у меня с ним ой как туго.
 

Crazy

Developer
Автор оригинала: dark-demon
а я типа не даю два куска кода на два возможных варианта исхода события?
Так. Будем прказывать на пальцах. У нас есть магазин, в котором продают рассол и пиво. Маме до фени, что именно там есть -- папе плохо с похмелья и она посылает сына Васю в магазин, чтобы помочь папе.

Сценарий 1, плохое ООП: Вася, пойди в магазин, спроси у продавщицы, если ли рассол и перезвони мне. А я скажу, чего купить и куда нести.
Сценарий 2, хорошее ООП: Вася, пойди в магазин, если есть рассол -- купи рассол, иначе -- купи пиво; покупку отнеси папе.


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

-~{}~ 15.06.07 12:26:

Автор оригинала: phprus
Я все-же не понимаю чем в данном случае исключения хуже замыканий?
Вариант с исключением работает так: мы делаем предположение о состоянии объекта (денег хватает) и называем это основным ходом событий. И говорим, что если мы не угадали -- нужно кинуть нам исключение.

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

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

-~{}~ 15.06.07 12:28:

Автор оригинала: phprus
с большой вероятностью в $form->show_error() надо будет передать информацию о том, что же произошло.
Легко:

Код:
 $account.withdraw: $value 
  success: [ $form->show_success(); ] 
  error: [  $sysMessage, $userMessage| $form->show_error($userMesage); $log->error($sysMessage); ]
 

dark-demon

d(^-^)b
Так. Будем показывать на пальцах.
мы оба реализуем 2 сценарий

У тебя очень превратное представление о работе языков программирования.
ну да, фтопку аргументацию. даёшь безапеляционные заявления!

Вариант с исключением работает так: мы делаем предположение о состоянии объекта (денег хватает) и называем это основным ходом событий.
мы точно также можем предполагать всё, что угодно. например: по дефолту - произошла неизвестная ошибка; по success - нет ошибок; по erorr - есть ошибки.

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

Crazy

Developer
Автор оригинала: dark-demon
ну да, фтопку аргументацию. даёшь безапеляционные заявления!
Друг мой, ты сказал чушь. Доказывать тебе, что это чушь -- лично мне совершенно незачем.

Ты сделал безаппеляционное заявление:

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