Які проблеми введення C ++ - як const у мову?


17

Мене цікавить ідея C ++ - як constне таке конкретне виконання (як відкидання const).

Візьмемо для прикладу C # - йому не вистачає C ++ - як const, а причиною цього є звичайне - люди та час. Крім того, здається, що команда C # вивчила виконання C ++ const, маркетингу CLR і цього було достатньо (дивіться, чому в параметрі c # і const немає методу члена const ; спасибі Svick). Якщо ми рухатимемось далі, чи це ще щось?

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

Чи є що - то в ПРИРОДІ з constцієї пози проблеми , що краще для мови , щоб уникнути цього? Щось на зразок вирішення питання, чи constповинен він бути глибоким або неглибоким (маючи constконтейнер, це означає, що я також не можу додати новий елемент або змінити наявні елементи; що робити, якщо елементи мають опорний тип)?

ОНОВЛЕННЯ : хоча я згадую C #, і, таким чином, роблячи історичну перспективу, я цікавлюсь сутністю потенційних проблем constмови.

Це не є викликом мов. Будь ласка, ігноруйте такі фактори, як поточні тенденції чи популярність - мене цікавлять лише технічні питання - дякую.


3
як осторонь: багаторазове успадкування може бути не важко зрозуміти, але дозвіл методу може стати досить потворним. Наївна роздільна здатність першої глибини швидко стає неінтуїтивною (" алмазна проблема "). Порядок дозволу метод C3 (опубл '96) вирішує цю проблему, але, звичайно , НЕ легко зрозуміти. Тому поза законом багаторазове успадкування часто може здатися досить розумним - але справжня проблема полягає в тому, що Java передує алгоритму C3, а C # орієнтується після Java.
амон

3
@amon Багато людей насправді не вважають, що множинне спадкування - це особливість, яку ви хочете мати в першу чергу, наприклад, творці мови програмування D: Це складна особливість дискусійного значення. Це дуже складно реалізувати ефективно, і компілятори схильні до багатьох помилок при його реалізації. Майже всі значення ІМ можна обробляти за допомогою єдиного успадкування, поєднаного з інтерфейсами та агрегацією. Залишене не виправдовує ваги впровадження ІМ. (джерело)
jcora


2
Навіть не маючи множинного спадкування, ви вже можете кодувати будь-яку проблему 3-SAT як роздільну здатність методу (або точніше роздільну здатність перевантаження) у C #, тим самим зробивши її NP-завершеною.
Йорг W Міттаг

1
@svick, дуже дякую Оскільки я не мав жодних відповідей на це запитання, я взяв на себе сміливість редагувати його, щоб зосередитись на природі проблеми, а не на історичних причинах, тому що, здається, 99% з них були "час + люди + анти C ++ упередженість + CLR ".
greenoldman

Відповіді:


10

Зверніть увагу, якщо це підходить вам, але у функціональних мовах, таких як Standard ML, все заміна за замовчуванням. Мутація підтримується через загальний refтип еренції. Отже intзмінна є незмінною, а ref intзмінна є контейнером, що змінюється, для ints. В основному, змінні - це реальні змінні в математичному сенсі (невідоме, але фіксоване значення), а refs - "змінні" в сенсі імперативного програмування - комірка пам'яті, в яку можна записувати та читати. (Я люблю їх називати присвоюваними .)

Я думаю, що проблема з constдвома проблемами . По-перше, у C ++ бракує збору сміття, що необхідно для створення нетривіальних стійких структур даних .const має бути глибоким, щоб мати сенс, але мати цілком незмінні значення в C ++ не доцільно.

По-друге, в C ++ вам потрібно ввімкнути, constа не відмовитися від нього. Але коли ви constщось забудете і пізніше це виправите, ви опинитесь у ситуації "отруєння Const", згаданої у відповіді @ RobY, де constзміна відбуватиметься протягом усього коду. Якби constза замовчуванням ви не застосували б constзаднім числом. Крім того, необхідність додавати constвсюди додає багато шуму коду.

Я підозрюю, що основні мови, які слідують за ними (наприклад, Java), сильно формували успіхи та спосіб мислення C та C ++. Справа в тому, що навіть при збиранні сміття більшість API колекціонування мов передбачають змінні структури даних. Той факт, що все є незмінним і незмінним, сприймається як кутовий випадок, багато в чому говорить про імперативний спосіб мислення, що стоїть за популярними мовами.

EDIT : Після роздуму над коментарем Greenoldman я зрозумів, що constсправа не стосується незмінності даних; constкодує у тип методу, чи має він побічні ефекти на екземпляр.

Мутацію можна використовувати для досягнення референтно прозорої поведінки. Припустимо, у вас є функція, яка при виклику послідовно повертає різні значення - наприклад, функцію, з якої читається один символ stdin. Ми могли б використовувати кеш / запам'ятати результати цієї функції для створення референтно прозорого потоку значень. Потік буде зв'язаним списком, вузли якого викличуть функцію при першому спробі отримати їх значення, але потім кешують результат. Отже, якщо stdinмістить Hello, world!, перший раз, коли ви намагаєтеся отримати значення першого вузла, він прочитає його charта повернеться H. Після цього він буде продовжувати повертатися, коли ви намагаєтеся отримати його значення, цього разу повертаючи та кешуючи цей результат.H без додаткових дзвінків для читання char. Аналогічно, другий вузол буде читати a charзstdine

Цікавим є те, що ви перетворили процес, який за своєю суттю є державним, в об'єкт, який, здавалося б, є без громадянства. Однак, щоб досягти цього, потрібно було мутувати внутрішній стан об'єкта (кешуючи результати) - мутація мала доброякісний ефект . Неможливо зробити наше, CharStream constнавіть якщо потік поводиться як незмінна цінність. Тепер уявіть, що тут є Streamінтерфейс з constметодами, і всі ваші функції очікують const Streams. Ви CharStreamне можете реалізувати інтерфейс!

( EDIT 2: Мабуть, є ключове слово C ++, mutableяке б дозволило нам обманювати і створюватиCharStream const . Однак ця лазівка ​​руйнує constгарантії - тепер ви справді не можете бути впевнені, що щось не вимкне його constметодами. Я припускаю, що це не так погано, оскільки потрібно явно вимагати лазівку, але ви все ще повністю покладаєтесь на систему честі.)

По-друге, припустимо, у вас є функції високого порядку - тобто ви можете передавати функції як аргументи іншим функціям. constness є частиною підпису функції, тому ви не зможете передавати нефункції constяк аргументи функціям, які очікують constфункцій. Сліпо примусове виконання constтут призведе до втрати загальності.

Нарешті, маніпулювання constоб'єктом не гарантує, що воно не мутує якесь зовнішнє (статичне або глобальне) стан за вашою спиною, тому constгарантії не такі сильні, як вони з'являються спочатку.

Мені не зрозуміло, що кодування наявності чи відсутності побічних ефектів у типовій системі є загальноприйнятною справою.


1
+1 дякую. Змінювані об’єкти - це щось інше, ніж C ++ const (це скоріше перегляд). Але скажімо, C ++ мав би const за замовчуванням, і varна вимогу залишив би лише одну проблему - глибину?
greenoldman

1
@greenoldman Добре. Минув час, коли я використовував C ++, тому я забув, що ви можете мати constпосилання на не- constоб'єкт. Тим не менш, я не вірю, що це має сенс мати неглибокий const. Вся суть constполягає в гарантії того, що ви не зможете модифікувати об'єкт за допомогою цього посилання. Вам не дозволяється обходити const, створюючи не constпосилання, то чому б це було нормально обходити const, мутуючи членів об'єкта?
Довал

+1 :-) Дуже цікаві проблеми у вашому оновленні (життя з лямбдами, які не мають констатів, і, можливо, слабша проблема із зовнішнім станом), я мушу перетравлювати це довше. У всякому разі, що стосується Вашого коментаря, я не маю нічого зла на увазі - навпаки, я шукаю функції для підвищення чіткості коду (ще один: ненульові вказівники). Тут же категорія (принаймні, це моя мета) - я визначаю, func foo(const String &s)і це сигнал sне буде змінено foo.
greenoldman

1
@greenoldman Я точно можу побачити апеляцію та обґрунтування. Однак я не думаю, що існує справжнє рішення проблеми, окрім якнайбільше уникнення змінних станів (разом з іншими неприємними речами, такими як nullспадщина.)
Doval

8

Основна проблема полягає в тому, що програмісти, як правило, не використовують її достатньо, тому, коли вони потрапляють у місце, де це потрібно, або пізніше обслуговуючий персонал хоче зафіксувати правильність const, виникає величезний ефект пульсації. Ви все ще можете написати ідеально непоганий код без цього const, ваш компілятор просто не буде його виконувати, і буде складніше оптимізувати його. Деякі люди вважають за краще, щоб їх компілятор не допомагав. Я не розумію цих людей, але їх дуже багато.

У функціональних мовах майже все є const, а зміна є рідкісним винятком, якщо це взагалі дозволено. Це має ряд переваг, таких як простіша паралельність і простіші міркування про спільний стан, але потрібно трохи звикнути, якщо ви походите з мови із зміною культури. Іншими словами, не бажаючи const- це питання людей, а не технічний.


+1 дякую. Хоча незмінний об’єкт - це щось інше, ніж я шукаю (ви можете зробити об'єкт непорушним у C # або Java), навіть при незмінному підході вам належить вирішити, чи він глибокий або неглибокий, візьмемо для прикладу контейнер покажчиків / посилань (чи можете ви змінити значення об’єктів, на які вказують). Через день здається, що основною проблемою є те, що встановлено за замовчуванням, і це легко вирішується при розробці нової мови.
greenoldman

1
+1 для lolz @ "Деякі люди вважають за краще, щоб їх компілятор не допомагав. Я не розумію цих людей, але їх дуже багато."
Томас Едінг

6

Недоліки я бачу як:

  • "отруєння const" - це проблема, коли одна декларація const може змусити попередню або наступну декларацію використовувати const, і це може призвести до використання const в попередніх наступних деклараціях і т. д. І якщо отруєння const перетікає в клас у бібліотеці що у вас немає контролю над цим, ви можете застрягти в поганому місці.

  • це не абсолютна гарантія. Зазвичай бувають випадки, коли const захищає лише посилання, але не може захистити базові значення з тих чи інших причин. Навіть у С є випадки краю, до яких const не може дістатися, що послаблює обіцянку, яку надає const.

  • загалом, настрої галузі, здається, віддаляються від сильних гарантій часу, але як більший комфорт вони можуть принести тобі та мені. Отже, вдень я витрачаю на торкання 66% своєї кодової бази через отруєння const, якийсь Python хлопець вибухнув 10 ідеально справних, добре розроблених, добре перевірених, повністю функціональних модулів Python. І він навіть не зламав, коли це робив.

Тож, можливо, питання полягає в тому, навіщо переносити потенційно суперечливу особливість, щодо якої навіть деякі фахівці неоднозначні, коли ви намагаєтесь прийняти свою новелу мову?

EDIT: коротка відповідь, нова мова має крутий пагорб, який потрібно підняти на прийняття. Це дизайнерам справді потрібно добре подумати над тим, які функції йому потрібні, щоб досягти прийняття. Візьмемо, наприклад, Go. Google начебто жорстоко врізав деякі найглибші релігійні битви, зробивши певний вибір дизайну стилю Конан-варварського, і я фактично думаю, що мова для нього краща, з того, що я бачив.


2
Ваша друга куля неправильна. У C ++ є три / чотири способи оголошення посилання / покажчика, wrt. constness: int *змінний вказівник на змінне значення, int const *змінний вказівник на значення int * constconst , const вказівник на змінне значення, int const * constconst вказівник на значення const.
phresnel

Дякую. Я запитав про природу, а не про маркетинг ("галузь, що відходить", не є природою C ++ const), тому такі "причини" я вважаю неактуальними (принаймні для цього питання). Про constотруєння - ви можете навести приклад? Тому що AFAIK - це перевага, ти щось передаєш, constі це має залишитися const.
greenoldman

1
Це не constпроблема, а зміна типу дійсно - що б ви не робили, це завжди буде проблемою. Подумайте про проходження RichString, а потім зрозуміти, що вам краще пройти String.
greenoldman

4
@RobY: Я не впевнений, що / з ким ви звертаєтесь до останнього та колишнього . Однак після того, як після обіду, переходячи до коду, ви мали б дізнатись, що вам слід відновлювати коефіцієнт правильності const-правильності знизу вгору, а не згори вниз, тобто починати в самих внутрішніх одиницях, і просуватися вгору. Можливо, ваші підрозділи також не були достатньо ізольованими, натомість були міцно з'єднані, або ви стали здобиччю внутрішніх систем.
phresnel

7
"Отруєння Const" насправді не є проблемою - справжньою проблемою є те, що C ++ за замовчуванням не const. Це занадто просто, щоб не constробити речі, які повинні бути, constтому що ви повинні ввімкнути це замість цього.
Довал

0

Є деякі філософські проблеми при додаванні constдо мови. Якщо ви декларуєте constклас, це означає, що клас не може змінитися. Але клас - це набір змінних у поєднанні з методами (або мутаторами). Ми досягаємо абстракції, ховаючи стан класу за набором методів. Якщо клас призначений для приховування стану, то вам потрібні мутатори, щоб змінити цей стан ззовні, і тоді його вже constнемає. Тож можна оголосити constлише класи, непорушні. Тому constздається можливим лише в сценаріях, де класи (або типи, які ви хочете оголосити const) є тривіальними ...

То нам constвсе-таки потрібно ? Я не думаю, що так. Я думаю, що ти можеш легко обійтися, constякщо у тебе хороший дизайн. Які потрібні вам дані та де, які методи - це методи передачі даних і які абстракції потрібні для вводу-виводу, мережі, перегляду тощо. Тоді ви, природно, розбиваєте модулі та класи, які стосуються стану, і у вас є методи та незмінні класи, які не потребують стану.

Я думаю, що більшість проблем виникає з великими жировими об’єктами даних, які можуть зберегти, перетворити і намалювати себе, і тоді ви хочете, наприклад, передати його рендерінгу. Тому ви не можете скопіювати вміст даних, оскільки це занадто дорого для великого об'єкта даних. Але ви не хочете, щоб це змінилося, тому вам потрібно щось таке, як constви думаєте. Нехай компілятор з'ясує ваші недоліки дизайну. Однак якщо ви розділите ці об'єкти лише на незмінний об'єкт даних та реалізуєте методи у відповідальному модулі, ви можете пройти навколо (лише) вказівник і робити все, що ви хочете зробити з даними, гарантуючи також незмінність.

Я знаю, що в C ++ можна оголосити деякі методи, constа не заявляти про інші методи, оскільки вони є мутаторами. А потім через деякий час вам потрібен кеш, а потім геттер мутує об'єкт (бо він лінивий навантажує), і він constбільше не є . Але в цьому і полягає вся суть цієї абстракції? Ви не знаєте, який стан змінюється під час кожного дзвінка.


1
"Отже, const здається можливим лише у сценаріях, коли класи (або типи, які ви хочете оголосити const) тривіальними ..." Стійкі структури даних незмінні та нетривіальні. Ви просто не побачите їх у C ++, оскільки майже всі вони діляться своїми внутрішніми даними між декількома екземплярами, а для C ++ бракує сміття для того, щоб це працювало. "Я думаю, що ви можете легко обійтися без const, якщо у вас хороший дизайн". Незмінні значення роблять код набагато простішим.
Довал

+1 дякую. Не могли б ви уточнити "оголосити const для класу"? Ви мали на увазі встановлення класу як const? Якщо так, я не запитую про це - C ++ const працює як перегляд, ви можете оголосити const поруч із об'єктом, а не класом (або щось змінено в C ++ 11). Також є проблема з наступним абзацом і словом "легко" - є гарне питання щодо C ++ - const в C #, і кількість роботи, яку він передбачає, є першорядною - для кожного типу, який ви маєте намір поставити const(у сенсі C ++ ) Ви також повинні визначити інтерфейс також для всіх властивостей.
greenoldman

1
Коли ви говорите про "клас", ви насправді маєте на увазі "екземпляр класу", правда? Я думаю, що це важлива відмінність.
svick
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.