Re[3]: О множественном наследовании
От: vdimas Россия  
Дата: 07.09.12 07:23
Оценка:
Здравствуйте, maxkar, Вы писали:

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

Т.ё, всё что ты писал, к наследованию никаким боком, оно может быть просто поддержано языком.
Насчет перегрузки сигнатур конструкторов — аналогично. А что ты делаешь когда речь о пререгрузке сигнатур обычных ф-ий? Наверно, приводишь к нужной сигнатуре и компилятор находит подходящую сигнатуру, так?

=================
Есть, правда, небольшое рациональное зерно в том, чтобы иметь разные конструкторы с одинаковыми типами параметров. ))
Такая потребность возникает если эти одинаковые типы несут разную семантику. В этом случае как раз либо вместо публичных конструкторов делают статические методы, либо создают типы-алиасы-обертки, чтобы отделить внести разницу семантики в разницу типов. Классика — замена int на enum.
Re[4]: О множественном наследовании
От: maxkar  
Дата: 08.09.12 15:04
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Здравствуйте, maxkar, Вы писали:


V>Если ты имел ввиду "двухтактность" происходящего, когда сначала выделяется память, а потом эта память инициализируется, то оно ничуть тебе не мешает и не может. Ты же в аргументе new указываешь конкретный тип, т.е. пофиг, сколько у него баз, вся механика скрыта от тебя.


Как раз таки может смущать и смущает. Мне не нравится, что на уровне пользователя класса различаются "конструктор" и "статический метод". Причем не только на уровне кода, а даже на уровне рантайма. Можно посмотреть на Newobj в msil, аналоги в java (там вообще два вызова — на выделение памяти и на вызов конструктора). Вроде бы и в C++ генерация кода различается для двух случаев. Еще можно посмотреть на reflection API, которые различают конструктор и остальные методы. Это все безобразие именно из-за той двухфазности с выделением памяти. Все "конструкторы" (в классическом смысле) — это на самом деле инициализаторы (устанавливают переменные и т.п.). А вот "создателя" из них делает конструкция "new ...".
Вполне естественно напрашивается вопрос: а зачем клиенту класса видеть такое разделение? Чем (с точки зрения клиента класса) отличается "конструктор" от "метода, который возвращает экземпляр класса"? Разница там небольшая: конструктор гарантирует новое identity объекта, обычный метод — нет. Учитывая, что для identity все равно нет нормальной поддержки (в контрактах методов/верификаторах/системе типов), особой роли это не играет.
Следующий вопрос. Если особой разницы для клиента нет, почему же эта разница все равно есть в языке? Правильно, в силу все той же двухфазности. Если мы хотим поддержать "method-like constructors", нужно вводить (на уровне генерации кода) еще и инициализаторы (которые память не выделяют). Фактически, вся компиляция будет генерировать "пару" методов. Один — с выделением памяти (и вызовом единственного инициализатора данного класса). Второй — чистый инициализатор (с вызовом родительских или других своих инициализаторов). При убирании наследования упрощается вторая часть. Там возможен только вызов своих инициализаторов. При этом даже ограничения по доступу (public/private) и т.п. проверять не нужно.

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

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

Без наследования оно проще в реализации внутренностей класса получается. А так — да, можно синтетику нагенериовать.
V>Насчет перегрузки сигнатур конструкторов — аналогично. А что ты делаешь когда речь о пререгрузке сигнатур обычных ф-ий? Наверно, приводишь к нужной сигнатуре и компилятор находит подходящую сигнатуру, так?
А в "основном" языке у меня перегрузки методов вообще нет, зато есть аргументы по умолчанию и varargs. Поэтому нужно делать методы c разными именами. Зато очень легко работать с методами как с first class function — не нужно сигнатуры типов указывать, да и reflection заметно проще становится.

V>=================

V>Есть, правда, небольшое рациональное зерно в том, чтобы иметь разные конструкторы с одинаковыми типами параметров. ))
V>Такая потребность возникает если эти одинаковые типы несут разную семантику. В этом случае как раз либо вместо публичных конструкторов делают статические методы, либо создают типы-алиасы-обертки, чтобы отделить внести разницу семантики в разницу типов. Классика — замена int на enum.
И то, и другое — костыли. Ну вот почему какой-то из вариантов сделан конструктором, а какой-то — статическим методом? Который сделан методом чем-то хуже что-ли? И на уровне языка я один создаю через "new" а второй через вызов методов.

Что касается вторых костылей (алиасы). Мне такой подход категорически не нравится. Он, конечно, работает в mainstream, но там просто нет альтернатив. Это все — попытка натянуть все возможные ограничения на одну систему типов. В простейшем случае нужно отличать "типы" (те самые "int" и т.п.) и "роли". Роли — те самые обертки, чтобы значение ушло не туда. Соответственно, на роли накладываются свои ограничения вроде "сумма двух длин — длина". Более правильный пример для ролей — различные "кэши" приложения. "Кэш" — общий интерфейс. Система ролей же отличает "кэш товаров" от "кэша продавцов", например (это важно при dependency injection). При этом API двух кэшей полностью одинаковое. Аналогично можно разделять "роли" функций (я о first-class function, при этом функции могут быть с одной сигнатурой и разными ролями). В более сложном случае нужно в одной и той же программе иметь несколько различных систем типов. Одна — ограничения "языка", среды выполнения. Вторая — ограничения бизнес-логики. Третья — более продвинутая система ограничений, которая не имеет поддержки в runtime (например, какое-то подмножество зависимых типов). Все эти "языки" отличаются только понятием типа (т.е. в грамматике для type разные правила и правила комбинации типов разные), все остальное AST — одинаковое. У меня, кстати, есть сценарий для "первой и третьей" системы типов, когда я хотел бы в большей части проекта использовать более строгую типизацию и только в некоторых местах использовать более слабую типизацию — не все выражается в "более строгой" (+ хуки для более сильной типизации, чтобы переход между двумя системами работал нормально). Если интересно — расскажу, но это лучше в отдельную ветку, так как к наследованию и консрукторам это уже отношения не имеет.
Re[5]: О множественном наследовании
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 08.09.12 18:21
Оценка:
Здравствуйте, maxkar, Вы писали:

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


Ок, ответь тогда на несколько вопросов. Для примера возьмем CLR — там есть возможность создания объекта без вызова конструктора и нет никаких заморочек с выделением памяти. Итак:
1) Как обеспечить отсутствие возможности легко получить ссылку на неинициализированный объект?
2) Как гарантировать вызов конструкторов базовых классов, причем в нужном порядке?
3) Как обеспечить нормальную работу модификатора readonly?
... << RSDN@Home 1.2.0 alpha 5 rev. 65 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[6]: О множественном наследовании
От: maxkar  
Дата: 09.09.12 17:38
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, maxkar, Вы писали:


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


AVK>Ок, ответь тогда на несколько вопросов. Для примера возьмем CLR — там есть возможность создания объекта без вызова конструктора и нет никаких заморочек с выделением памяти. Итак:

Хорошо. Только я не понял, в каком контексте вопросы. Так что если ответ получится совсем не в тему, значит нужно уточнить вопросы. Мне пока не ясно, что мы вообще делаем. Мы пишем компилятор нашего языка в CLR? Или мы пишем верификатор CLR-кода для нашего языка? Или мы делаем еще что-то? На всякий случай, я не утверждал, что будет хоть какая-нибудь совместимость с уже существующими библиотеками (в том числе и системной) и что вообще язык будет хорошо ложиться на какую-нибудь существующую систему (не утверждал и обратного).

Примерно как это будет выглядеть в языке я показывал здесь, второй пример. В зависимости от желания контролировать байткод и типа наследования придется добавить от нуля до двух атрибутов. Атрибуты "ctor" и "initializer". Первый через reflection не виден. Второй, наверное, тоже не виден.

AVK>1) Как обеспечить отсутствие возможности легко получить ссылку на неинициализированный объект?

На каком уровне? На уровне языка в constructor так и будут все те ограничения, что есть в существующих классах. Клиент класса в языке объект "сам по себе" вообще никак создать не может (С# вроде бы тоже не позволит руками указать только ту инструкцию). На уровне байткода инструкцию создания объекта разрешить только внутри статических методов класса и ограничить аргументы только этим классом (и вообще, убрать у нее аргументы). В зависимости от уровня паранои можно позакручивать гайки — разрешить метод только у методов с атрибутом "ctor" или вообще автоматически на стек класть для методов с атрибутом "ctor" вновь созданный объект и инструкцию убрать (да, тогда точно понадобится атрибут). В байткоде верифицировать все то же самое, что и сейчас в конструкторах. Тоже зависит от уровня паранойи. Можно использование this запретить везде, кроме левых частей присваивания, запретить вызово методов и т.п. В общему, внутри "constructor'а" остаются все проверки существующего конструктора. А вот для вызывающего кода это обычный вызов метода (ему разницы нет, что там внутри себя метод делает).

Полностью я пока отказаться от понятия конструктора я не предлагал — не совсем понятно, как правильно выделять память (да и все остальные гарантии тоже, которые привязаны к процессу "создания" объекта).

AVK>2) Как гарантировать вызов конструкторов базовых классов, причем в нужном порядке?

А вот здесь как раз играет роль возможность/невозможность наследования реализации. Без наследования реализации проблемы просто нет. С наследованием придется на каждый "конструктор" плодить пару методов. Один — конструктор. Второй — инициализатор. Соответственно, конструктор создает объект и вызывает инициализатор. Инициализатор в свою очередь вызывает родительские инициализаторы. Соответственно, в язык придется добавлять конструкцию вызова родительского инициализатора. Вроде parent.initialize "someMethodName". Не очень хорошо получается, все таки приходится "светить" наследникам различие между "конструкторами" и "обычными методами" (у одного есть соответствующий инициализатор, у другого — нет).

За вопрос спасибо, все таки не зря я подозревал, что с наследованием не все так просто. Но меня вполне устроит отсутствие наследования реализации, я им не пользуюсь.

AVK>3) Как обеспечить нормальную работу модификатора readonly?

Точно так же, как и раньше это все обеспечивает сейчас обычный конструктор. Внутри метода "constructor" ведет себя так же, как и "обычный" конструктор — со всеми гараниями по полям и т.п. А вот с точки зрения клиента это обычный метод. Не важно, создал ли метод объект внутри себя (и инициализировал переменные) или вызывал другой метод для создания объекта. "Какой-то" constructor уже завершился и все гарантии работают.

Итого. На уровне "среды исполнения" модификатор "constructor" пока остается. Он нужен для выделения памяти и доп. гарантий. Но никто из клиентов этого класса не может осмысленно воспользоваться подобным знанием. Более того, "constructor" может стать затем обычным статическим методом с соответствующим типом возвращаемого значения, на работе клиентов это вообще не скажется. Возможно и обратное преобразование — из статического метода сделать "constructor".

P.S. Я .NET не знаю, знаю только Java. Так что если где-то пишу чушь, меня нужно поправить и описать что именно нужно чуть подробнее.
Re[7]: О множественном наследовании
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 09.09.12 18:03
Оценка:
Здравствуйте, maxkar, Вы писали:

M>Хорошо. Только я не понял, в каком контексте вопросы.


Ты утверждаешь, что семантическая разница между конструктором заключается только в выделении памяти. Попробуй с этой позиции ответить на заданные вопросы. Они вроде как вполне понятные.

AVK>>1) Как обеспечить отсутствие возможности легко получить ссылку на неинициализированный объект?

M>На каком уровне? На уровне языка

На нем.

M> в constructor так и будут все те ограничения, что есть в существующих классах


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

M>Клиент класса в языке объект "сам по себе" вообще никак создать не может


Это пока эту роль выполняют конструкторы.

M> (С# вроде бы тоже не позволит руками указать только ту инструкцию)


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

M>. На уровне байткода инструкцию создания объекта разрешить только внутри статических методов класса


Ну то есть проблема в твоем варианте никак не решается. Ответ понятен.

M>В зависимости от уровня паранои можно позакручивать гайки — разрешить метод только у методов с атрибутом "ctor"

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

О да, я именно такого ответа и ждал. Выкидываем из языка конструктор и добавляем способ разметки, чтобы сделать из некоторых статических методов ... да, конструктор. Ну и нафига все это? Чтобы можно было method group из конструктора сделать, и не писать примитивнейшей утилитки, нивелирующей разницу в рефлекшене между GetMethods и GetConstructors? Сильный замах, да.

AVK>>3) Как обеспечить нормальную работу модификатора readonly?

M>Точно так же, как и раньше это все обеспечивает сейчас обычный конструктор.

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

M>Итого. На уровне "среды исполнения" модификатор "constructor" пока остается.


Он у тебя пока остается на любом уровне.

M>P.S. Я .NET не знаю, знаю только Java.


В джаве вроде бы можно сделать конструктор приватным, не так ли? В таком случае все твои заявленные потребности эта фича покрывает с лихвой и без отказа от наследования реализации.
... << RSDN@Home 1.2.0 alpha 5 rev. 65 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[8]: [[SomeType alloc] init];
От: Qbit86 Кипр
Дата: 09.09.12 18:06
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Ты утверждаешь, что семантическая разница между конструктором заключается только в выделении памяти. Попробуй с этой позиции ответить на заданные вопросы. Они вроде как вполне понятные.


Нужно посмотреть, как подобные вопросы решаются в Objective-C. «Обратите внимание, что метод(ы) init является обычным методом, ничем не выделяющимся среди остальных (в отличие от C++, где конструктор — это особый метод, у которого, например, нельзя взять адрес).» (Wikipedia)
Глаза у меня добрые, но рубашка — смирительная!
Re[9]: [[SomeType alloc] init];
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 09.09.12 18:13
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>Нужно посмотреть, как подобные вопросы решаются в Objective-C


Да никак они не решаются. К примеру, базовые инициализаторы нужно звать ручками — сомнительное, на мой вкус, достижение.
... << RSDN@Home 1.2.0 alpha 5 rev. 65 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[8]: О множественном наследовании
От: maxkar  
Дата: 09.09.12 20:34
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, maxkar, Вы писали:


M>> в constructor так и будут все те ограничения, что есть в существующих классах


AVK>При чем тут ограничения? Сейчас проблемы неинициализированных объектов почти нет, потому что конструктор это очень специальный метод, и доступ ему дается только к самому себе. Это все равно приводит к проблемам, но не таким сильным как если бы неявный доступ к неинициализированному объекту был возможен из любого статического метода.


В каком смысле "доступ дается только к самому себе"? В обычном конструкторе можно делать почти все то же, что и в других методах. И this из обычного конструктора элементарно можно можно куда угодно передать. В том числе и в статический метод. Тот "конструктор", который я предлагал, внутри инициализатора тоже работает как "обычный конструктор", а снаружи выглядит как "static method".

M>>Клиент класса в языке объект "сам по себе" вообще никак создать не может

AVK>Это пока эту роль выполняют конструкторы.
И что? И дальше эту роль будут выполнять "конструкторы". Только вот клиент больше не знает, какой из используемых методов является "конструктором", а какой — обычным методом.

M>> (С# вроде бы тоже не позволит руками указать только ту инструкцию)


AVK>Все шарп позволяет. Только это не инструкция, а специальный метод специального объекта. Но сейчас такое сделать можно только специально. При отказе же от конструкторов нужно будет выставлять эту фичу в частое использование — кто то ведь, в итоге, экземпляр класса должен создать.

И в чем проблема? Как раз статический (чистый статический!) метод и создает экземпляр. И условия на то, откуда можно использовать такую инструкци, очень жесткие, вплоть до позиции инструкции в байткоде метода можно задать. У меня даже специально не получится создать объект, не вызвав предусмотренные классом инициализаторы. Совсем никак, любые попытки верификатор не пропустит. Вот если инициализаторы куда-то не туда уводят объект, то можно получить неинициализированный объект. Но и на обычных конструкторах я изображу все те же проблеимы. Во что именно дальше будет разворачиваться инициализатор — в вызов "instance method" инициализатора или будет продолжать внутри себя поля ставить — это уже проблемы кодогенерации и модели выполнения (те же гарантии на final поля и т.п.).
AVK>Но если тебе непременно приспичило — бери да пользуйся. Только что то я пока такого радикального неприятия конструкторов не встречал.

M>>. На уровне байткода инструкцию создания объекта разрешить только внутри статических методов класса

AVK>Ну то есть проблема в твоем варианте никак не решается. Ответ понятен.
Здесь все точно так же, как и с обычными "конструкторами". Обычный конструктор может передать неинициализированную ссылку. Мой тоже может передать (специально!). А вот "случайно" ссылки на неинициализированный объект у меня вообще не могут возникнуть. Они появляются при входе в "конструктор" в качестве объекта this (да, да, у моего "конструктора" внутри instance есть). Ну а дальше уже сам программист виноват...

M>>В зависимости от уровня паранои можно позакручивать гайки — разрешить метод только у методов с атрибутом "ctor"

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

AVK>О да, я именно такого ответа и ждал. Выкидываем из языка конструктор и добавляем способ разметки, чтобы сделать из некоторых статических методов ... да, конструктор. Ну и нафига все это? Чтобы можно было method group из конструктора сделать, и не писать примитивнейшей утилитки, нивелирующей разницу в рефлекшене между GetMethods и GetConstructors? Сильный замах, да.

Ну примерно для этого и делалось. Но только акцент в другую сторону. Чтобы из конструкторов сделать обычные (с точки зрения той же системы типов, например) методы. Method group меня не волнует. Меня волнуют лишние сущности. Вот зачем "вне" класса понятие его конструктора (при отсутствии наследования реализации)? Да не зачем, значит можно и выпилить его. Внутри класса нужен? Нужен. Значит там его и оставить. Инкапсуляция деталей реализации обычная.

AVK>>>3) Как обеспечить нормальную работу модификатора readonly?

M>>Точно так же, как и раньше это все обеспечивает сейчас обычный конструктор.

AVK>Ну то есть мы все таки конструктор оставляем в неизменном практически виде, только теперь static надо будет дополнительно указать и имя придумать.

"Внутри" класса — да, оставляю. Вне класса (для всех его пользователей) конструкторов больше нет. Больше нельзя гарантированно получить новую identity (раньше это делал new ...). static писать не обязательно, он у всех "constructor" включен автоматически (так же, как public у методов интерфейсов). Даже имя можно оставить new в большинстве случаев для начала.

M>>Итого. На уровне "среды исполнения" модификатор "constructor" пока остается.

AVK>Он у тебя пока остается на любом уровне.
Не на любом. При остуствтии наследовании реализации и компиляции во что-то низкоуровневное понятия "конструктор" на уровне среды нет. Есть метод, который выделяет память, инициализирует ее чем-то и возвращает результат. Все зависит от набора целевых команд и требуемой валидации. Если в тот же CLI генерировать целевой код, вместо всех моих "конструкторов" будут методы, которые зовут "обычные" приватные конструкторы для этого CLI. Все, все остальные не видят ни одного "конструктора".

M>>P.S. Я .NET не знаю, знаю только Java.

AVK>В джаве вроде бы можно сделать конструктор приватным, не так ли? В таком случае все твои заявленные потребности эта фича покрывает с лихвой и без отказа от наследования реализации.
Да, можно. Но потребности фичи она не покрывает. Задалбывает ручками писать "прокси" для конструкторов, да и first-class methods в Java нет. Генерировать байт-код (аннотациями/постпроцессорами и т.п.) — костыли как раз. Мое выпиливание конструкторов ничего существенного (ага, кроме наследования реализации) не теряет, но костыли становятся не нужны. Да и вообще, если по всем языкам брать, все не так хорошо. У меня основной язык вообще ActionScript 3 (Java — второй). А там конструкторы всегда public, не first-class, да и через динамику их не вызывать. Метод я могу вызвать, передав аргументы массивом (func.apply(null, args)), а конструктор — нет (только через позиционные new Cls(...,..., ...)). Ну и обертки для конструкторов сильно надоедает писать (они единичные, но работа то лишняя).
Re[9]: О множественном наследовании
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 09.09.12 20:53
Оценка:
Здравствуйте, maxkar, Вы писали:

M>В каком смысле "доступ дается только к самому себе"? В обычном конструкторе можно делать почти все то же, что и в других методах.


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

M> И this из обычного конструктора элементарно можно можно куда угодно передать.


Но это очень плохой тон, приводящий к куче проблем.

M> В том числе и в статический метод. Тот "конструктор", который я предлагал, внутри инициализатора тоже работает как "обычный конструктор", а снаружи выглядит как "static method".


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

AVK>>Ну то есть проблема в твоем варианте никак не решается. Ответ понятен.

M>Здесь все точно так же, как и с обычными "конструкторами".

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

M>Ну примерно для этого и делалось. Но только акцент в другую сторону. Чтобы из конструкторов сделать обычные (с точки зрения той же системы типов, например) методы.


Они и так более менее обычные методы, по крайней мере в CLR и JVM. Хуже того, приватный конструктор позволяет тебе сделать именно то, что ты хочешь. Может ценой чуть чуть большего количества кода.

M> Method group меня не волнует.


Ты в первом сообщении переживал как раз по этому поводу.

M>Вот зачем "вне" класса понятие его конструктора (при отсутствии наследования реализации)?


Если не нужно — сделай конструктор приватным.

M>Да, можно. Но потребности фичи она не покрывает. Задалбывает ручками писать "прокси" для конструкторов


А не надо писать прокси, если внутри этой прокси логики нет. Конструктор ничем не хуже.

M>, да и first-class methods в Java нет


Там может в этом проблема, а не в конструкторах?
... << RSDN@Home 1.2.0 alpha 5 rev. 65 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[6]: О множественном наследовании
От: koodeer  
Дата: 10.09.12 20:12
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>А вообще можно, к примеру, было передать единственному классу в конструктор 1-2 функции. Если абсолютно одинаковые функции применялись не в одном месте (хотя при сотне вариантов такое, видимо, было редко) — конструктор вынести в статический метод-фабрику.


Очень интересно. Однако, таким образом мы можем расширить этот единственный класс функциями (методами). А как быть, если нужно добавить в базовый класс поля/свойства/эвенты ?
Re[7]: О множественном наследовании
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 10.09.12 20:37
Оценка: +1
Здравствуйте, koodeer, Вы писали:

K>А как быть, если нужно добавить в базовый класс поля/свойства/эвенты ?


С какой целью? Абстрактно рассуждать о дизайне бессмысленно, а в каждом конкретном случае всегда есть варианты.
... << RSDN@Home 1.2.0 alpha 5 rev. 65 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[10]: О множественном наследовании
От: maxkar  
Дата: 11.09.12 14:40
Оценка:
Здравствуйте, AndrewVK, Вы писали:

M>> В том числе и в статический метод. Тот "конструктор", который я предлагал, внутри инициализатора тоже работает как "обычный конструктор", а снаружи выглядит как "static method".

AVK>А в чем принципиальная разница между конструктором и статическим методом снаружи? В синтаксисе вызова? Это все?

Ну в моем варианте разницы не будет. Сейчас:
1. Да, есть синтаксическая разница между вызовом конструктора и метода
2. Конкретно у меня в AS3 first-class Constructor и first-class function — разные и несовместимые друг с другом типы. Это неудобно. Нельзя скормить конструктор во все high-order function вроде map и пр. Причем в силу особенностей рантайма, я даже простым способом из конструктора сделать фунцкию не могу, нужно писать различные оберкти на различное число аргументов.
3. При изменении кода у конструкторов чуть меньше гибкости (только с точки зрения автоматизации действий). Интересует ситуация, когда внутренняя структура класса сильно меняется и конструктор становится "deprectated" (рекомендуется использовать другие конструкторы, например, или статический метод вместо конструктора). В AS3 проблема актуальна — там нет перегрузки конструкторов (и методов тоже). Придется искать все вхождения конструктора и править их. С методами можно оставить старый метод. Можно сделать бывший "конструктор" обычным методом (пользователи их не различают), вызывать из него правильный "конструктор" и сделать "inline method", например.

AVK>Да у тебя везде все как с обычными конструкторами. Все принципиальные моменты, отличающие конструкторы от обычных методов, остаются в прежнем виде. В сухом остатке — мелкие синтаксические различия.


А это уже от задачи и стиля зависит. Мне как раз эти "мелкие синтаксические различия" позволят писать меньше кода. Причем не в одном месте. И даже если это будет ценой отказа от наследования реализации, я не расстроюсь. Как раз наследованием реализации я и не пользуюсь, а своей фичей пользуюсь.

M>> Method group меня не волнует.

AVK>Ты в первом сообщении переживал как раз по этому поводу.
Хм. Я их точно не имел в виду (у меня нет overload!). Мне нужны first-class constructors (которые при этом являются обычными first-class функциями) и возможность именованных конструкторов (в том числе из-за невозможности overload'а). Необходимость перегрузки конструктора "по имени" для меня нормальна.

M>>Вот зачем "вне" класса понятие его конструктора (при отсутствии наследования реализации)?

AVK>Если не нужно — сделай конструктор приватным.
M>>Да, можно. Но потребности фичи она не покрывает. Задалбывает ручками писать "прокси" для конструкторов
AVK>А не надо писать прокси, если внутри этой прокси логики нет. Конструктор ничем не хуже.

Так не хочу я давать "публичный" конструктор. Может, он через месяц поменяется. Что мне дальше делать? Рефакторинги с методами технически проще реализуются (см. выше). В некоторых из случаев у меня еще и подозрения бывают, что возвращается интерфейс, а не класс. В том смысле, что API определено, а вот "точный" тип — нет. В статическом методе через какое-то время вместо объекта может создаваться его "наследник" (появятся новые методы, будет декомпозиция/параметризация поведением и т.п., все внутри реализации). С публичным (общедоступным) конструктором это все проделывать более сложно.

M>>, да и first-class methods в Java нет

AVK>Там может в этом проблема, а не в конструкторах?
Это как посмотреть. В принципе, проблема очень похожа на лишнюю писанину с конструкторами, которой я хочу избежать. first-class методы прекрасно эмулируются интерфейсами и анонимными классами. Только это еще писана на каждый случай использования. Так что анонимные методы просто уменьшили бы объем кода. Моя фича тоже уменьшила бы у меня объем кода (в меньшей степени, чем first-class методы, но все же) в некоторых сценариях.