OSDev

для всех
Текущее время: 28 мар 2024, 14:20

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 285 ]  На страницу Пред.  1 ... 25, 26, 27, 28, 29
Автор Сообщение
СообщениеДобавлено: 07 окт 2015, 11:45 

Зарегистрирован: 04 ноя 2007, 14:48
Сообщения: 113
Есть мнение, что в C# это возможно.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 08 окт 2015, 14:56 
Аватара пользователя

Зарегистрирован: 14 мар 2011, 12:31
Сообщения: 970
Откуда: Дагоба
SII писал(а):
- дать доступ к определённым полям экземпляров классов из программ внешнего редактирования (настройка значений свойств объектов не в коде на Це++, а внешними средствами, что, понятное дело, много удобней и быстрей -- создание той же гуйни, расположение неписей на уровне игры и т.д. и т.п.);

Не совсем понятно, в какой степени редактирование является внешним? Редактирование скомпилированных двоичных объектов? Если речь идёт о доступе к полям объектов, то почему не сделать это на уровне класса? Лучше бы рассмотреть на каком-либо конкретном примере, чтобы было понятно, чего именно не хватает.

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

Т.е. что-то типа автоматической сериализации объектов? Если да, то есть два нюанса.
1. Как автоматически сериализировать, если объект содержит аллокируемые области памяти (особенно со ссылками на них и полями, зависящими от размера и размещения аллокированной области)?
2. Если таких полей нет, то почему нельзя трактовать его просто как аморфный двоичный объект в памяти с двумя атрибутами - размещением (получаемым как (void *)&x) и размером (sizeof(x))? Соответственно, копировать, записывать в файл, считывать и т.д.

SII писал(а):
В Дельфях эта задача частично решена благодаря двум вещам:
- наличию у тамошних классов не только "низкоуровневых" полей (обычных переменных, по сути), но и свойств (ключевое слово property;...

Само по себе, как мне кажется, property не решает эту задачу, оно только делает удобней определённые средства защиты доступа к полям объекта. Правда, с использованием property могут возникнуть определённые семантические сложности, например, допустимость использования модифицирующих операторов типа ++x, а также неожиданное поведение при реализации доступа по чтению. Например, функция доступа по чтению может скрыто модифицировать значение поля, в результате мы можем получить два разных значения при двух считываниях подряд. Но если во втором случае могут быть даже определённые плюсы (например, мы можем реализовать программный ГСЧ и каждый раз считывать новое случайное число), то организация применимости модифицирующих операторов может существенно усложнить синтаксис языка и затруднить его понимание. Вызов функций-членов в этом смысле лишён каких-либо скрытых эффектов и не позволяет явным образом использовать модифицирующие операторы.
Я хочу сказать, что использование property не так однозначно хорошо, как может показаться сначала, и требует более детального исследования. Вот что действительно однозначно полезно - это разрешение доступа к некоторым приватным полям по чтению. Сеттеры также видятся полезными, т.к. позволяют осуществлять единообразный упрощённый контроль присваемого значения, а также вводить разные степени проверки при разных режимах компиляции (например, проверка допустимости в отладочном режиме). Но и сеттеры тоже требуют отдельного разграничения доступа, к примеру, переменная может быть приватной с публичным сеттером, либо также с приватным сеттером. В общем, не всё так просто.

SII писал(а):
- наличию области видимости published (тот же public, но известный не только внутри самой программы, но и за её пределами; все свойства, которые можно редактировать в дельфозной ИДЕ, являются именно опубликованными).

Собственно, все члены, объявленные как public, также доступны в любом месте за пределами программы, достаточно лишь корректно узнать тип объекта. В этом смысле я не вижу принципиальных отличий published. Более того (поправьте меня, если я ошибаюсь), published в Delphi как раз и отличается от public тем, что генерирует соответствующую информацию о типах времени выполнения RTTI (RunTime Type Information). То есть, базовым важным свойством в данном случае является наличие этой самой информации RTTI, а не конкретный способ доступа published.

SII писал(а):
в Дельфях невозможно сделать автоматическую сериализацию определённых свойств объектов (нет, в принципе, это возможно -- но только написанием внешнего дополнительного компилятора, управляемого особыми комментариями подобно макросам в Це++, а это не шибко элегантно и т.д. и т.п.). Ну а отсюда, собственно, вопрос: не задумывались ли, можно ли подобную задачу реализовать чисто средствами самого языка?

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

_________________
Yet Other Developer of Architecture.
The mistery of Yoda’s speech uncovered is:
Just an old Forth programmer Yoda was.

<<< OS Boot Tools. >>>


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 11 окт 2015, 09:54 

Зарегистрирован: 28 окт 2007, 18:33
Сообщения: 1418
Прошу прощения за тормоза с ответом :)

Yoda писал(а):
SII писал(а):
- дать доступ к определённым полям экземпляров классов из программ внешнего редактирования (настройка значений свойств объектов не в коде на Це++, а внешними средствами, что, понятное дело, много удобней и быстрей -- создание той же гуйни, расположение неписей на уровне игры и т.д. и т.п.);

Не совсем понятно, в какой степени редактирование является внешним? Редактирование скомпилированных двоичных объектов? Если речь идёт о доступе к полям объектов, то почему не сделать это на уровне класса? Лучше бы рассмотреть на каком-либо конкретном примере, чтобы было понятно, чего именно не хватает.


Ну, в Дельфях сделано, грубо говоря, следующим образом. В состав библиотеки языка, помимо обычной RTL (управление памятью, синусы-косинусы и прочие обычные вещи), входит библиотека визуальных компонентов (VCL). Каждый компонент в ней является классом, содержащим, как и положено, различные поля, свойства и методы. VCL существует сразу в двух видах: как модули, которые подключаются к пользовательской программе (грубо можно считать, что это аналог h-файлов в Си, только в Дельфях всё уже предварительно скомпилировано, хотя в теории можно всю библиотеку собрать с нуля из поставляющихся исходников), и как готовые DLL. Когда идёт разработка гуйни, IDE подгружает DLL, содержащие код используемых компонентов. Когда программист, скажем, добавляет кнопочку, IDE создаёт соответствующий объект, вызывая конструктор нужного класса из DLL. Естественно, этот объект сам себя отрисовывает и т.д. и т.п., поэтому внешне разрабатываемое окно выглядит почти так же, как при выполнении (но кое в чём могут быть отличия, поскольку код объектов учитывает, выполняется ли он в редакторе или в готовом приложении -- в редакторе могут быть доступны некоторые возможности по настройке компонентов и т.д., которые отключены при нормальной работе). Чтобы посмотреть и при необходимости изменить свойства объектов, в IDE существует так называемый инспектор объектов -- это окно, в котором перечислены все опубликованные свойства компонента, с которым мы работаем. Если программист меняет то или иное свойство, IDE сохраняет это изменение в файле формы (файл времени разработки, содержащий информацию обо всех компонентах, используемых в том или ином окне разрабатываемого приложения), а также дёргает сам объект, либо прямо присваивая значение соответствующему полю, либо вызывая нужный метод -- это зависит от того, как определено соответствующее property.

Таким образом, работа с объектом в редакторе по своей сути не отличается от работы с ним в скомпилированной готовой программе -- точно так же происходят обращения к полям или дёрганье методов, разница лишь в некоторых атрибутах объекта (в IDE он создаётся со специальным флагом, указывающим, что идёт работа в редакторе). В Qt и других подобных сишных библиотеках, по всей вероятности, работа идёт принципиально точно так же, но, поскольку Си++ не имеет области видимости published и не имеет свойств, информацию о том, какие свойства у класса доступны для редактирования в IDE, как к ним обращаться и т.п., приходится создавать внешними по отношению к языку инструментами (метаобъектным компилятором для Qt, например), а синтаксически в исходном коде это представляется всякими специальными макросами. Такое решение не шибко элегантно, поскольку "загаживает" исходники всякими костылями и прилично увеличивает и без того немаленькое время сборки проекта. В Дельфях же, поскольку и published, и property являются элементами самого языка, вся необходимая информация в откомпилированные модули помещается самим компилятором в ходе обычной компиляции программы, что куда быстрей и эффективней.

Yoda писал(а):
SII писал(а):
- как бы расширить возможности языка, не заставляя программиста писать каждый раз примерно один и тот же код (например, загрузка и сохранение значений свойств объектов из внешнего файла).

Т.е. что-то типа автоматической сериализации объектов? Если да, то есть два нюанса.
1. Как автоматически сериализировать, если объект содержит аллокируемые области памяти (особенно со ссылками на них и полями, зависящими от размера и размещения аллокированной области)?
2. Если таких полей нет, то почему нельзя трактовать его просто как аморфный двоичный объект в памяти с двумя атрибутами - размещением (получаемым как (void *)&x) и размером (sizeof(x))? Соответственно, копировать, записывать в файл, считывать и т.д.


1. Единственный способ решить эту проблему, на мой взгляд, -- обязать класс иметь специальные методы для сохранения и загрузки, если экземпляры этого класса подлежат сериализации (это может быть атрибутом класса).

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

Цитата:
Само по себе, как мне кажется, property не решает эту задачу, оно только делает удобней определённые средства защиты доступа к полям объекта. Правда, с использованием property могут возникнуть определённые семантические сложности, например, допустимость использования модифицирующих операторов типа ++x, а также неожиданное поведение при реализации доступа по чтению. Например, функция доступа по чтению может скрыто модифицировать значение поля, в результате мы можем получить два разных значения при двух считываниях подряд. Но если во втором случае могут быть даже определённые плюсы (например, мы можем реализовать программный ГСЧ и каждый раз считывать новое случайное число), то организация применимости модифицирующих операторов может существенно усложнить синтаксис языка и затруднить его понимание. Вызов функций-членов в этом смысле лишён каких-либо скрытых эффектов и не позволяет явным образом использовать модифицирующие операторы.


Ну, в Паскале проблем с ++ нет за их отсутствием :) Но на самом деле, это вполне прописывается в правила языка: ++ выполняется всегда путём чтения-модификации-записи, причём для чтения и записи либо происходит прямое обращение к полю, либо вызов метода в зависимости от того, как определено свойство. Например, если есть такое определение:

Код:
  Internal_Value : Integer;

  procedure Set_Internal_Value(New_Value : Integer);

  property Value : Integer read Internal_Value write Set_Internal_Value;


то оператор

Код:
Value++;


будет выполнен как:

Код:
Set_Internal_Value(Internal_Value + 1);


Yoda писал(а):
Я хочу сказать, что использование property не так однозначно хорошо, как может показаться сначала, и требует более детального исследования. Вот что действительно однозначно полезно - это разрешение доступа к некоторым приватным полям по чтению. Сеттеры также видятся полезными, т.к. позволяют осуществлять единообразный упрощённый контроль присваемого значения, а также вводить разные степени проверки при разных режимах компиляции (например, проверка допустимости в отладочном режиме). Но и сеттеры тоже требуют отдельного разграничения доступа, к примеру, переменная может быть приватной с публичным сеттером, либо также с приватным сеттером. В общем, не всё так просто.


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

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

Yoda писал(а):
SII писал(а):
- наличию области видимости published (тот же public, но известный не только внутри самой программы, но и за её пределами; все свойства, которые можно редактировать в дельфозной ИДЕ, являются именно опубликованными).

Собственно, все члены, объявленные как public, также доступны в любом месте за пределами программы, достаточно лишь корректно узнать тип объекта. В этом смысле я не вижу принципиальных отличий published. Более того (поправьте меня, если я ошибаюсь), published в Delphi как раз и отличается от public тем, что генерирует соответствующую информацию о типах времени выполнения RTTI (RunTime Type Information). То есть, базовым важным свойством в данном случае является наличие этой самой информации RTTI, а не конкретный способ доступа published.


published -- это не только наличие RTTI, но и ещё прямое указание средствам разработки (визуальному редактору форм в составе IDE) о том, что данное свойство должно появляться в инспекторе объектов, чтобы разработчик мог на него любоваться, а также менять, когда нужно (если это свойство допускает изменение в принципе, конечно). public-свойства в инспекторе объектов не появляются, поскольку они не нужны человеку при создании приложения.

Yoda писал(а):
SII писал(а):
в Дельфях невозможно сделать автоматическую сериализацию определённых свойств объектов (нет, в принципе, это возможно -- но только написанием внешнего дополнительного компилятора, управляемого особыми комментариями подобно макросам в Це++, а это не шибко элегантно и т.д. и т.п.). Ну а отсюда, собственно, вопрос: не задумывались ли, можно ли подобную задачу реализовать чисто средствами самого языка?

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


Полностью автоматическая -- да. Но вот поддержка "полуавтоматической" на уровне языка была б полезна, думается -- в виде атрибутов полей для автоматической сериализации и возможности указать методы для ручной. Есть же методы-конструкторы и деструкторы, которые синтаксически отличаются от обычных методов внутри класса (в Си++ их имена совпадают с именем класса, только у деструктора ещё ~ впереди добавлен; в Дельфях имена могут быть произвольными, но перед ними вместо обычной procedure или function стоит constructor или destructor). Думается, можно ввести ещё сериализаторы/десериализаторы; без наличия таковых в некоем классе выполняется лишь автоматическая (де)сериализация полей, имеющих соответствующий атрибут, а при наличии -- после автоматической вызывается соответствующий метод.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 11 окт 2015, 11:50 

Зарегистрирован: 04 ноя 2007, 14:48
Сообщения: 113
Цитата:
Во-первых, наличие свойств прилично расчищает исходный код программы: обращение к свойству как к полю элегантней, чем вызов метода (меньше лишних элементов вроде скобок и т.д.), а читабельность -- вещь очень важная, если создаётся не программа-однодневка.


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


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 13 окт 2015, 13:58 
Аватара пользователя

Зарегистрирован: 14 мар 2011, 12:31
Сообщения: 970
Откуда: Дагоба
SII писал(а):
Ну, в Дельфях сделано, грубо говоря, следующим образом.
...
Если программист меняет то или иное свойство, IDE сохраняет это изменение в файле формы (файл времени разработки, содержащий информацию обо всех компонентах, используемых в том или ином окне разрабатываемого приложения), а также дёргает сам объект, либо прямо присваивая значение соответствующему полю, либо вызывая нужный метод -- это зависит от того, как определено соответствующее property.
Таким образом, работа с объектом в редакторе по своей сути не отличается от работы с ним в скомпилированной готовой программе...

Занятная концепция. Однако, всё это вполне реализуемо на классах даже без автоматической сериализации и без поддержки published/property со стороны языка. Мне навскидку видится такой каркас. Есть базовый класс, скажем, GUIObject. В нём объявлены функции:
virtual const char **GetPropertiesList (void) = 0;
virtual Property *GetProperty (const char *name) = 0;
virtual void SetProperty (const Property *p) = 0;
virtual void Save (Form *f);
virtual void Restore (const Form &f);
Также, как видно из прототипов, есть два сервисных класса - Property (для удобного поиска и редактирования свойств) и Form (для сериализации и сохранения в файл или ресурс приложения). В принципе, первые четыре функции класса нужны в основном для визуального редактирования объекта. Редактор загружает dll, создаёт пустой объект, получает список свойств (первая функция) и редактирует их при помощи геттера/сеттера (вторая/третья функции). Объект отрисовывает себя сам в соответствии с заданными пользователем свойствами. Далее по завершению редактирования визуальный редактор сериализует свойства объекта четвёртой функцией – вуаля, объект готов. При запуске программы создаётся объект и его свойства восстанавливаются из сохранённого файла/ресурса. Замечу, что в данной схеме разработчик объекта практически не выполняет никакой лишней работы (по сравнению с подходом Дельфи). Список свойств, их индивидуальную установку и получение нужно реализовывать при любом раскладе. Заметим, что в принципе не нужно реализовывать даже Save/Restore т.к. достаточно сериализовать сами свойства (кои, скорей всего, ограничиваются весьма небольшим количеством типов), всю остальную работу может самостоятельно проделать базовый класс, получая список свойств и последовательно устанавливая/сохраняя их.

SII писал(а):
поскольку Си++ не имеет области видимости published и не имеет свойств, информацию о том, какие свойства у класса доступны для редактирования в IDE, как к ним обращаться и т.п., приходится создавать внешними по отношению к языку инструментами (метаобъектным компилятором для Qt, например), а синтаксически в исходном коде это представляется всякими специальными макросами. Такое решение не шибко элегантно, поскольку "загаживает" исходники всякими костылями и прилично увеличивает и без того немаленькое время сборки проекта.

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

SII писал(а):
В Дельфях же, поскольку и published, и property являются элементами самого языка, вся необходимая информация в откомпилированные модули помещается самим компилятором в ходе обычной компиляции программы, что куда быстрей и эффективней.

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

SII писал(а):
1. Единственный способ решить эту проблему, на мой взгляд, -- обязать класс иметь специальные методы для сохранения и загрузки, если экземпляры этого класса подлежат сериализации (это может быть атрибутом класса).

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

В таком случае, это ничем не отличается от ручной сериализации.

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

Моё возражение состоит в том, что читабельность - функция как минимум двух параметров - обилия синтаксического мусора с одной стороны, и интуитивной ясности с другой стороны. Если мы говорим про реализацию свойств, то скобки появляются только в количестве двух символов, никаких параметров внутри них нет. Зато появляется понимание, что происходит внутри. Пример:
x = rand;
или
x = rand();
Первая запись короче на два символа. Однако, она полностью скрывает от программиста тот факт, что за сценой происходит нечто, что может привести к неожиданным результатам или вызвать кучу сомнений, требующих копания в исходниках/документации. Например два подряд идущих вызова дадут разный результат. Или программист может выкинуть лишнее с его точки зрения присваивание, не обратив внимание на важный побочный эффект лежащий внутри. Поэтому я возражаю против геттеров. Но не возражаю против сеттеров и ограниченного доступа по чтению.

SII писал(а):
Во-вторых, свойства тоже имеют области видимости. Объяви всё свойство в приватной части -- и его увидят только те, кто имеет на то право.

Я говорил о разграничении доступа для одного и того же поля (т.е., например, читать могут все, а писать только "свои"), чего свойства сами по себе не добавляют.

SII писал(а):
published -- это не только наличие RTTI, но и ещё прямое указание средствам разработки (визуальному редактору форм в составе IDE) о том, что данное свойство должно появляться в инспекторе объектов, чтобы разработчик мог на него любоваться, а также менять, когда нужно (если это свойство допускает изменение в принципе, конечно). public-свойства в инспекторе объектов не появляются, поскольку они не нужны человеку при создании приложения.

Тем более! Такая узкая специализация ещё больше настраивает против реализации класса доступа published.

SII писал(а):
в Дельфях имена могут быть произвольными, но перед ними вместо обычной procedure или function стоит constructor или destructor).

Непонятно, зачем конструктору/деструктору отдельное имя (точно так же, как и ключевые слова procedure и function), но да ладно, Бог – судья создателям Паскаль/Дельфи.

SII писал(а):
Думается, можно ввести ещё сериализаторы/десериализаторы; без наличия таковых в некоем классе выполняется лишь автоматическая (де)сериализация полей, имеющих соответствующий атрибут, а при наличии -- после автоматической вызывается соответствующий метод.

Вот сижу и размышляю, что лучше, ключевое слово "serializable", как неизменное свойство языка, указывающее, что данную переменную можно автоматически сериализировать, или имплементация сериализации на уровне функций-членов при помощи операторов "<<" и ">>". А так как большинство объектов достаточно сложные и функция сериализации будет присутствовать явно, то как уживутся вместе автоматическая сериализация одних полей с ручной сериализацией других. Не получится ли при этом фарш? А как объяснять этот механизм программистам? А не напрасно ли мы смешиваем свойство языка (ключевое слово) с конкретными высокоуровневыми объектами, куда мы собираемся сериализировать? Все возникающие в голове ответы подобны красному огню светофора перед полуавтоматической сериализацией по ключевым словам. Либо автомат, либо никак.

_________________
Yet Other Developer of Architecture.
The mistery of Yoda’s speech uncovered is:
Just an old Forth programmer Yoda was.

<<< OS Boot Tools. >>>


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 285 ]  На страницу Пред.  1 ... 25, 26, 27, 28, 29

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
cron
Создано на основе phpBB® Forum Software © phpBB Group
Русская поддержка phpBB