Comments 35
Интересно когда свойства интегрируются в язык, так чтобы они синтаксически были не отличимы от переменных.
Ага, когда читал, подумал, что можно было бы сделать хитрое пубичное поле с переопределёнными операторами присваивания для установки/чтения значения, но статья как-то внезапно закончилась.
Я так не пробовал, просто пришедшая в голову идея:
struct Person{
Property<std::string> name("");
Property<int, private_setter=true> id(0, setter=[](int value){ assert(value >= 0); return value;});
}
Нужна именно языковая поддержка. Не понимаю почему в С++ до сих пор не ввели. Помнится, в древнем С++Builder'е чуть ли не 98 года свойства уже были.
Макросы, генерирующие исполняемый код — зло в квадрате.
Хуже только макросы, генерирующие несколько функций сразу.
Код с использованием макросов, генерирующих исполняемый код, сложен в понимании, практически не поддаётся отладке, сложен для модификации и поддержки. И этот букет приятных свойств распространяется соседствующие участки здорового кода.
koowaah, в аду для вас уже готовят персональный котёл.
Также интересно как Вы реализуете без макросов debug-assert'ы, кроссплатформенные интерфейсы для взаимодействия с системным API и тому подобные вещи.
1)Условная компиляция (#ifdef и т.п.)
2)Включение файлов (без алтернативно).
3)Дополнительные параметры для компилятора (#pragma)
Подстановка констант — ЗЛО. Для этого есть const и constexpr.
Подстановка частей кода — АБСОЛЮТНОЕ ЗЛО. Функции вам в руки. Инлайнинг рулит.
Исключение только использование макросов из системного (WinAPI) и библиотечного кода (Qt).
Стандартно если копипаста больше пары строк то делаю функцию. Часто статическую.
Но у них есть например и статические функции для этого.
И вообще в области библиотек для меня идеал это STL где макросы для пользователя отсутствуют.
Почему не сделать так
// A.h
class AImpl;
class B {
public:
void a();
private:
AImpl *impl;
}
// A.cpp
#include "AImpl.h"
void A::a() {
impl->a();
}
Конечно, лексические макросы С/С++ не подарок, это очень древнее, кривое и уже давно устаревшее решение; лучше бы были синтаксические с глубокой интеграцией в компилятор и среду разработки с возможностью REPL и просмотра сгенерированного кода, но что есть — то есть.
А макросы, которые генерируют несколько функций — вполне нормально, если это какие-то неразрывно связанные функции (ну как геттер и сеттер), и изменение кода одной неизбежно влечет изменение кода другой.
Что лучше умозрительность или очевидность — в прямом смысле слов.
Ответ неоднозначен — кому как.
Если стоит задача иметь класс с полями — то или эти поля независимо изменяемы и инвариант обеспечивается внешними функциями, либо обеспечение инварианта лежит на самом классе, но тогда кодогенерация геттеров и сеттеров не имеет смысла, ибо каждый геттер обеспечивает специфичные проверки инварианта, а сеттеры — необходимые преобразования полей.
Иметь генерированные однообразные геттеры и сеттеры, который не обеспечивают инвариант — значит утроить количество поддерживаемого кода( и утроить кол-во юниттестов для этого кода)
Использую макросы для генерирования геттеров и сеттеров, уменьшает код класса. А используя type traits можно обезопасить себя от неверного указания типа и переменной.
Получается выстрелить себе в ногу не получиться.
Либо нужны логика и поведение — тогда нужны полноценные функции-члены. В идеале так.
И геттеры-сеттеры, и проперти — это артефакт, появившийся из-за интерфейсов, как vtable. У интерфейса есть только указатели на методы, вот и приходится оборачивать доступ к «виртуальным полям» в геттеры, проперти и сеттеры.
Как-то так.
PS. В дизайн-тайме GUI они нужны — чтобы заполнить данные из записанных значений в дизайнере экранной формы: в поле напрямую записать нельзя, а метод интерфейса вызвать можно.
На уровне использования наличие свойств лишь предоставляет синтаксический сахар доступа к полю объекта.
pCPP->Feature() = new Feature(); // Для простых случаев без инварианта
pCPP->Feature(new Feature()); // Для претензией на сохранение инварианта
pCSharp.Feature = new Feature();
На уровне реализации свойства в С# страдают тем же врожденным недостатком — если логика eсть, то уникальная в каждом свойстве — и её надо писать и, руководствуясь "Явное лучше неявного" и проблемами при многоступенчатой инициализации сложносоставных объектов, имеет смысл выделять такие функторы в явные независимые сущности или отдельных методы с явными именами, а если логики нет — get; set; составляют визуальный мусор.
Концептуально, понятие "свойство" неотделимо от "поле объекта". Наличие или отсутствие синтаксиса — на усмотрении авторов языка и я не могу делать вывод хорошо\плохо без понимания проблемы, которую решали авторы C# и Delphi вводя синтаксис свойств в дополнение к методам и полям объекта.
Возможно поэтому они выглядят так похоже.
Реализация свойств в С++