Здравствуйте, Vamp, Вы писали:
V>Дело не в том, какая приставка, а в том, что они мешают в целом.
Если тебе мешают пары функций, то и не используй их. А ломать инкапсуляцию ради удобства — это дурдом.
К>>Проперти, будучи в языке, внесли бы строгость. Но их нет, и они не внесли. V>Я так и не вижу их преимуществ. Все это неизжитый дельфизм.
Вижуалбейсикизм и олекомизм.
В VC они введены в язык именно для поддержки оле.
К>>А как именно нахлебался? V>Да по-всякому. Я тут уже два раза писал, как половина полезного синтаксиса закрывается. См. выше. V>Кроме этого, усложняется косвенная адресация. Например, есть желание универсально обращаться к полю.
Указатели на члены (-функции и -данные) — это замыкания для голытьбы.
Завернул бы в интерфейс или в пару function<>, и было бы счастье.
Или, если уж хочется по-короткому и на шаблонах, то
template<class C, class Getter, class Setter>
void manipulate(C* obj, Gettter getter, Setter setter, what_t what)
{
typedef PLEASE_EXTRACT_VALUE_TYPE_FROM_MEMBER_FUNCTION(getter) T;
switch(what)
{
case read: (obj->*setter)(get_user_input<T>());
case write: output_to_user(obj->*getter());
}
}
К>>2) нетупое присваивание — валидация; V>И что ты делал, если валидация обламывалась?
А что делают, если валидация обламывается. Или подгонял значение, или исключение кидал. В чём здесь вопрос?
K>>почему ни в одном стандарте с++ до сих пор не предложили нормальные пропертя?
MZ>Отвечу коротко и надеюсь ясно: потому что нахрен они никому не нужны.
Хинт — пока что-то не сделают, оно нахрен никому не нужно. Например, если бы лет 10 назад спросить на этом форуме — почему нету лямбд, последовал бы ответ — они никому не нужны
Здравствуйте, enji, Вы писали:
MZ>>Отвечу коротко и надеюсь ясно: потому что нахрен они никому не нужны.
E>Хинт — пока что-то не сделают, оно нахрен никому не нужно. Например, если бы лет 10 назад спросить на этом форуме — почему нету лямбд, последовал бы ответ — они никому не нужны
А лямбды и сейчас не нужны. Но, суки, удобные.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Здравствуйте, netch80, Вы писали:
N>Здравствуйте, jazzer, Вы писали:
N>>>Тут есть два выхода. Можно разрешить любые неописанные операции через get-modify-set, а можно какие-то операции явно определить с реализующим их кодом, а не только get и set. Можно использовать оба. J>>Ага. Сколько у нас там операторов? С десяток наберется ведь?
N>Ну вообще-то больше, а что?
а то, что с нормальными членами работать удобно, в отличие от пропертей, который либо подерживают только get/set через присваивание, либо надо лепить полную обвязку со всеми операторами.
J>>И вся эта карусель лишь ради того, что "Вдруг Когда-то Где-то Кому-то" (tm) могут потребоваться сайд-эффекты.
N>Не "где-то кому-то могут потребоваться", а вообще принципиальная (и очень полезная) концепция представления действий с объектом через привычные действия через его именованные члены.
какие "привычные действия" имеются в виду? у пропертей только get/set есть по умолчанию.
В то время как для члена типа int "привычными действиями" является весь арсенал операторов, а в случае std::string — еще и функций-членов и свободных функций (std::for_each, например).
N>>> property foo { N>>> void resize(size_t newsize) { this->resize_foo(newsize); } N>>> }; J>>Те же проблемы, что и с операторами, только еще хуже. Это ж для всех функций-членов всех классов придется подобное писать, и для каждого свое, так что даже в макрос не упрячешь.
N>Почему *придётся*? Это пишется только там, где оно такое действительно запрошено. Никто не мешает совмещать этот механизм и с открытыми членами, и с геттерами, где надо.
А где это не запрошено? Кому-то удобнее все через присваивания делать, можно подумать?
Если хочется удобства, то придется. Если удобство не нужно, то конечно, можно ничего не делать.
J>>Так что овчинка выделки не стоит совершенно.
N>В варианте, доведённом до абсурда — да, не стоит. В нормальном — не доказано.
Где ты видишь абсурд?
Вот есть член типа std::string — у него 3 десятка функций-членов, десяток операторов и 3 десятков свободных функций.
Если это просто открытый член — мне весь этот арсенал средств доступен "из коробки".
Если же мы во что бы то ни стало хотим сделать проперть, сохранив при этом сей арсенал, нам придется весь этот интерфейс воспроизвести еще раз в терминах проперти.
Укажи, где именно тут ты увидел абсурд.
N><...> J>>std::string — туши свет
N>Конечно, это уже за пределами их понимания, потому что ты делаешь везде копии и не подсказал компилятору никакой оптимизации. N>(С другой стороны, вполне возможно, оптимизации тут есть в реализации, за счёт сохранения общего буфера строки и COW на модификации. Поэтому остаются только несколько вызовов функций, которые относительно дёшевы. Но это за пределами темы properties.)
Вот именно что за пределами. А делать копии — так другого способа с пропертями нету, простите, если ты хочешь ее менять.
А что именно я должен был подсказать компилятору? Перепиши код, чтоб было "как надо", чтоб компилятор все заоптимизировал.
Не говоря уже о том, что код с пропертями нечитабелен абсолютно по сравнению с кодом прямой работы с членами.
J>>// введем еще один (тривиальный) уровень сеттеров-геттеров
N>И тут, когда не добрались до std::string, проблем нет — всё аккуратно вычитывается напрямую по смещениям и не создаются никакие getB().
Зато когда добрались — туши свет, не?
J>>к слову, std::string используется из поставки компилятора, а не какой-нть из STLPort с оптимизацией коротких строк, который компилятор не сможет соптимизировать с вероятностью 99.94%.
N>Я не изучал разницу, но не вижу тут принципиальной проблемы. std::string сам по себе достаточно сложный зверь. Никто не обещал тотального упрощения всего и везде. Но вот сделать удобный для человека сахар для важного случая — почему бы и нет?
Ну так если это сложный зверь, зачем еще дополнительно усложнять себе жизнь, оборачивая его в проперти?
Здравствуйте, jazzer, Вы писали:
N>>Я не изучал разницу, но не вижу тут принципиальной проблемы. std::string сам по себе достаточно сложный зверь. Никто не обещал тотального упрощения всего и везде. Но вот сделать удобный для человека сахар для важного случая — почему бы и нет?
J>Ну так если это сложный зверь, зачем еще дополнительно усложнять себе жизнь, оборачивая его в проперти?
А кто предлагал такое (всё через get и set) именно для string? Я как раз не предлагал. Обсуждай с тем, кто это предложил и за это агитирует.
Моё предложение было существенно иным — если оно и string, то явно необходимые для сущности конкретного свойства операции должны быть определены явно и само это определение уже даст необходимые оптимизации. А остальные операции спокойно могут быть при необходимости реализованы через дефолтные get и set.
N>>>>Тут есть два выхода. Можно разрешить любые неописанные операции через get-modify-set, а можно какие-то операции явно определить с реализующим их кодом, а не только get и set. Можно использовать оба. J>>>Ага. Сколько у нас там операторов? С десяток наберется ведь? N>>Ну вообще-то больше, а что? J>а то, что с нормальными членами работать удобно, в отличие от пропертей, который либо подерживают только get/set через присваивание, либо надо лепить полную обвязку со всеми операторами.
Ты не то и не с тем сравниваешь.
Сравнивай не прямую работу с членами, а работу через свойства с их неявно определёнными действиями — с явно вызываемыми геттерами, сеттерами и прочими модификаторами. Это когда надо каждый раз писать getTitle(), setTitle(), expandTitle() и так далее, потому что прямого присвоения недостаточно — например, setTitle() может требовать немедленной перерисовки на экране или переиндексации в базе. В случае отсутствия свойств как элемента языка тебе требуется пачка функций по управлению содержимым — то есть тот кошмар, на который, например, ругается Vamp; но его не избежать, если в принципе возможно, что какой-то член класса является не просто куском данных, который в нём лежит для общности, но и имеет какое-то семантическое отражение внутри (как заголовок окна для класса окна).
J>Не говоря уже о том, что код с пропертями нечитабелен абсолютно по сравнению с кодом прямой работы с членами.
Это с чего вдруг? Для доступа извне реализации класса разницы никакой вообще, синтаксис идентичен.
Для внутри — наоборот, он в разы читабельнее, если мы имеем, аналогично предыдущему примеру, property{} с определением действий — вместо адских шаблонных наворотов, которые потребуются, если мы будем обеспечивать те же эффекты за счёт того, что членом класса будет другой специальный класс, который возьмёт на себя необходимые переопределения операций.
Если ты определишь, например, для строки операцию взятия значения, дописки в конец и установки нового значения через
это сильно просто по сравнению с тем, что потребуется, если определять класс, который будет реагировать на установку значения, например, вызовом assert_correct_title() у объекта-владельца. И писать это кошмарно, и скорее всего дороже в рантайме — потому что потребуется хранить ссылку на владельца. Может, кто-то сможет шаблонами упростить это — чтобы компилировалось уже со знанием конкретного владельца; я достаточно паршиво знаю систему плюсовых шаблонов и не в курсе, могут ли они вытянуть такое, чтобы избавиться от лишних ссылок. Но если может, то это всё равно кошмарный кусок кода в худших традициях шаблонизации. А в виде свойства всё получается красиво и просто.
J>>>И вся эта карусель лишь ради того, что "Вдруг Когда-то Где-то Кому-то" (tm) могут потребоваться сайд-эффекты. N>>Не "где-то кому-то могут потребоваться", а вообще принципиальная (и очень полезная) концепция представления действий с объектом через привычные действия через его именованные члены. J>какие "привычные действия" имеются в виду? у пропертей только get/set есть по умолчанию.
Это потому, что ты смотришь на то, как они определены в тех языках, где есть.
А я не хочу ограничиваться именно таким представлением (хотя и оно достаточно неплохо, если не вызывает огромных накладных расходов). Что мешает определить и другие операции?
Более того, почему ты вообще говоришь про get и set? Представь себе, что это не свойство, а обычная переменная. Ты будешь о ней говорить в терминах get и set? Нет, в случае C++ ты будешь думать о, например, operator int() для присвоения целому, operator double() для присвоения плавающему, и перегруженному operator =(...) для присвоения уже ему значения какого-то типа.
Так при чём тут get и set?
J>В то время как для члена типа int "привычными действиями" является весь арсенал операторов, а в случае std::string — еще и функций-членов и свободных функций (std::for_each, например).
И тут будет то же самое, если реализовывать в стиле C++, а не копировать логику, которая адекватна, может быть, для языка стиля Python. Другая семантика — другая логика. J>>>Так что овчинка выделки не стоит совершенно. N>>В варианте, доведённом до абсурда — да, не стоит. В нормальном — не доказано. J>Где ты видишь абсурд?
Абсурд именно в ограничении набором из get и set, даже не параметризованных.
J>Вот есть член типа std::string — у него 3 десятка функций-членов, десяток операторов и 3 десятков свободных функций. J>Если это просто открытый член — мне весь этот арсенал средств доступен "из коробки". J>Если же мы во что бы то ни стало хотим сделать проперть, сохранив при этом сей арсенал, нам придется весь этот интерфейс воспроизвести еще раз в терминах проперти.
Не весь. А только тот, что нужен для данного случая. Да, он будет ограничен. Но само по себе property — это метод ограничения и управления доступом к классу, так что тут такое естественно.
J>Вот именно что за пределами. А делать копии — так другого способа с пропертями нету, простите, если ты хочешь ее менять.
И до седмижды семидесяти: не думай о свойствах в стиле других языков. Мы в теме C++, так что думай о том, как они должны были бы быть реализованы для C++.
J>А что именно я должен был подсказать компилятору? Перепиши код, чтоб было "как надо", чтоб компилятор все заоптимизировал.
Не буду, ибо незачем. Правильно — выставить именно нужные операции оптимальным способом, а не придумывать методы обхода через дальнее болото.
Здравствуйте, Kingofastellarwar, Вы писали:
K>почему ни в одном стандарте с++ до сих пор не предложили нормальные пропертя?
K>разве не лучше писать Core->SystemA->Manager->Call(); K>чем GetCore()->GetSystemA()->GetManager()->Call(); K>? K>или еще хуже с разными с порнонотациями типа : K>getCore()->getSystemA()->getManager()->Call(); K>или полные дрова: K>get_Core()->get_SystemA()->get_Manager()->Call();
K>я из за этого уродства забил на изоляцию мемберов от внешнего мира и использую паблик мемберы по полной.
K>почему в 11-м стандарте предложена куча всякой ультраспецифичной лабуды, а такого ништяка до сих пор там нет?
K>(костыли и мс-специфичные прагмы не предлагать, пробовал уже)
Я вот так извращался что бы поиметь пропертя, они были нужны для реализации MVC и таких полей было тьма:
объявление и использование полей в принципе оказалось вполне приемлемым. Короткий синтаксис объявления +начальное значение.
Не очень сложно использовать. Подсказки по коду тоже работают.
Проблемы были только с методом Assign его постоянно надо поддерживать в актуальном состоянии. Ну нету в C++ reflection.
Здравствуйте, о_О, Вы писали:
о_О>Здравствуйте, jazzer, Вы писали:
J>>В том виде, в котором они в С++, они ни разу не удобные
о_О>обоснуй, пожалуйста, и приведи пример
они мономорфные, типы надо явно указывать, что тут еще обосновывать...
Здравствуйте, netch80, Вы писали:
N>Сравнивай не прямую работу с членами, а работу через свойства с их неявно определёнными действиями — с явно вызываемыми геттерами, сеттерами и прочими модификаторами. Это когда надо каждый раз писать getTitle(), setTitle(), expandTitle() и так далее, потому что прямого присвоения недостаточно — например, setTitle() может требовать немедленной перерисовки на экране или переиндексации в базе.
Ну и зачем нужны эти грабли? Когда ты типа с переменной работаешь, а её какие-то добрые люди потом пропертёй обернули и каждый ++ перестройку индексов к терробайтной базе рожает?
N>В случае отсутствия свойств как элемента языка тебе требуется пачка функций по управлению содержимым — то есть тот кошмар, на который, например, ругается Vamp;
Дык интерфейс надо по-человечески проектировать.
Например, зачем заголовкам окон что-то кроеме сета и гета? Ну там, какой-нибудь find зачем?
На крайняк можно константный доступ дать...
N>Это с чего вдруг? Для доступа извне реализации класса разницы никакой вообще, синтаксис идентичен.
Да в том-то и беда, что написанно может быть одно и то же, а делать при этом совсем разное...
N>А я не хочу ограничиваться именно таким представлением (хотя и оно достаточно неплохо, если не вызывает огромных накладных расходов). Что мешает определить и другие операции?
Ну заводишь пачку интерфейсов и вперёд
N>И до седмижды семидесяти: не думай о свойствах в стиле других языков. Мы в теме C++, так что думай о том, как они должны были бы быть реализованы для C++.
Я думаю, что в С++ они противоестественны.
Хороший С++ объект не должен ничего знать о своём владельце.
В логику С++ хорошо ложился бы механизм, позволяющий заводить как-то ограниченные наборы методов класса-параметра + подписка на вызов методов.
Ну типа пишешь что-то типа SeperVar<std::string>{ тут перечисляешь как-то нужные методы } myString.
И потом на эту myString можно подписаться
Но такую конструкцию можно и сейчас соорудить, вообще-то.
Будет немного не так, конечно, но тоже ничего
struct MyTitleString : SuperVar<std::string> {
// тут дописываешь методы, кроме get и set
} myTitle;
Только не понятно на кой оно всё надо...
Реально вся тема с пропертями упирается в две проблемы.
1) В С++ очень убогие шаблоны. Они конечно мощны для извратов, но без извратов не работают почти никак.
2) Имея указатель на один и тот же объект, как на член и как на данные, нельзя получить указатель на аггрегирующий объект. Ясно, что в некоторых случаях это невозможно чисто технически. Но в некоторых-то возможно. Но нельзя никогда.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Abyx, Вы писали:
A>например, имеем код
A>
A>struct Foo
A>{
A> int state;
A>};
A>
A>и пару сотен использований токена "state" в исходниках. A>надо понять где, как и зачем state меняется, и например добавить туда новый код (в setter)
Просто пишем, что это const int state и по списку ошибок компиляции узнаём места...
А твой подход сильно сломается, если на поле берут указатель и куда-то отдают бродить...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
N>>Сравнивай не прямую работу с членами, а работу через свойства с их неявно определёнными действиями — с явно вызываемыми геттерами, сеттерами и прочими модификаторами. Это когда надо каждый раз писать getTitle(), setTitle(), expandTitle() и так далее, потому что прямого присвоения недостаточно — например, setTitle() может требовать немедленной перерисовки на экране или переиндексации в базе. E>Ну и зачем нужны эти грабли? Когда ты типа с переменной работаешь, а её какие-то добрые люди потом пропертёй обернули и каждый ++ перестройку индексов к терробайтной базе рожает?
Почти верно. Когда ты типа с переменной работаешь, а её какие-то добрые люди пропертей обернули и каждый ++ побочные эффекты рожает... а что, ты всерьёз думаешь, что перестройка индекса будет такая сложная? А какая тогда разница по сравнению с setFoo(getFoo()+1)? Только то, что не знаешь, просто это переменная или что-то иное? Так для этого документация есть.
N>>В случае отсутствия свойств как элемента языка тебе требуется пачка функций по управлению содержимым — то есть тот кошмар, на который, например, ругается Vamp; E>Дык интерфейс надо по-человечески проектировать. E>Например, зачем заголовкам окон что-то кроеме сета и гета? Ну там, какой-нибудь find зачем?
Не знаю, это тебя надо спросить. Я никакого find тут не предлагал.
E>Да в том-то и беда, что написанно может быть одно и то же, а делать при этом совсем разное...
"Это Спарта!!!" В смысле, это C++. Или вообще любой "взрослый" язык программирования, в котором операция, выглядящая как простое сложение, может переворачивать атомоходы, отстреливать айсберги и двигать материки.
N>>А я не хочу ограничиваться именно таким представлением (хотя и оно достаточно неплохо, если не вызывает огромных накладных расходов). Что мешает определить и другие операции? E>Ну заводишь пачку интерфейсов и вперёд
И что? Не понимаю глубокой мысли.
N>>И до седмижды семидесяти: не думай о свойствах в стиле других языков. Мы в теме C++, так что думай о том, как они должны были бы быть реализованы для C++. E>Я думаю, что в С++ они противоестественны. E>Хороший С++ объект не должен ничего знать о своём владельце.
А это и не объект. Это свойство. Это совершенно другое понятие, и привлекать к нему хоть какую-то логику объекта бессмысленно.
E>Только не понятно на кой оно всё надо...
Удобно для программиста. В язык вводят кучу фишек и значительно менее удобных и важных.
E>Реально вся тема с пропертями упирается в две проблемы. E>1) В С++ очень убогие шаблоны. Они конечно мощны для извратов, но без извратов не работают почти никак. E>2) Имея указатель на один и тот же объект, как на член и как на данные, нельзя получить указатель на аггрегирующий объект. Ясно, что в некоторых случаях это невозможно чисто технически. Но в некоторых-то возможно. Но нельзя никогда.
Это всё потому, что вместо поддержки компилятора ты думаешь об извратах, как это всё сделать с теми средствами, что сейчас. Конечно, ничего хорошего не получится.
Здравствуйте, Ops, Вы писали:
Ops>Кроме доступа там могут быть какие-то сайд-эффекты прикручены, уведомить кого-то об изменении переменной, например. Так что ничего плохого в set/get нет.
Забавно, все стали упоминать про побочные эффекты в геттерах/сеттерах — редкий и сомнительный case.
А защиту состояния объекта от ломающих изменений почему-то никто не вспомнил
Здравствуйте, 0x7be, Вы писали:
0>Здравствуйте, Ops, Вы писали:
Ops>>Кроме доступа там могут быть какие-то сайд-эффекты прикручены, уведомить кого-то об изменении переменной, например. Так что ничего плохого в set/get нет. 0>Забавно, все стали упоминать про побочные эффекты в геттерах/сеттерах — редкий и сомнительный case. 0>А защиту состояния объекта от ломающих изменений почему-то никто не вспомнил
Потому что для прямой защиты достаточно явных методов get, set.
Здравствуйте, о_О, Вы писали:
о_О>Здравствуйте, jazzer, Вы писали:
J>>они мономорфные, типы надо явно указывать, что тут еще обосновывать...
о_О>Это С++, а не Йуморле. Большего ожидать не стоит.
Никаких принципиальных проьблем сделать это в С++ я лично не вижу.
Boost.Lambda как-то с этим справляется в рамках С++: _1 < _2.
Вот это — хороший, годный синтаксис для лямбд.
Вот таким он примерно и должен быть, только должен быть встроенным в язык, чтоб были плюшки в виде нормальной диагностики и т.д.
На самом деле, нынешние лямбды — это просто сахар для объявления/определения локального класса-функтора.
И чтоб его можно было использовать со всякими std::for_each, пришлось поменять стандарт и явно разрешить параметризовать шаблоны локальными классами.
Полиморфные лябмды а ля Boost.Lambda элементарно реализуются аналогичным образом, только оператор у функтора должен быть шаблонным, что сейчас запрещено для локальных классов. Если это разрешить — получим нормальные полиморфные лябмды, т.е. такая запись
> Хинт — пока что-то не сделают, оно нахрен никому не нужно. Например, если бы лет > 10 назад спросить на этом форуме — почему нету лямбд, последовал бы ответ — они > никому не нужны
Здравствуйте, jazzer, Вы писали:
J>Вот таким он примерно и должен быть, только должен быть встроенным в язык, чтоб были плюшки в виде нормальной диагностики и т.д.
вот она главная проблема: старые маразматики из комитета назвали направление развития "путем расширения стандартной библиотеки" (отсюда убогие std::function, std::bind вместо нормальных делегатов, примитивные лямбды, всякие noexcept, std::begin без std::rbegin — это вообще facepalm)).