"Парадокс" і "+" +


37

Я читав статтю тут: http://www.paulgraham.com/avg.html і частина про "парадокс" була особливо цікава. Як хтось, котрий головним чином кодує c ++, але має інший мову (в основному Haskell), я знаю кілька корисних речей на цих мовах, які важко повторити на c ++. Питання в основному стосується людей, які володіють як мовою c ++, так і якоюсь іншою мовою, чи є якась потужна мовна особливість чи ідіома, якою ви користуєтесь мовою, яку було б важко концептуалізувати чи реалізувати, якби ви писали лише на c ++?

Зокрема, ця цитата привернула мою увагу:

За індукцією, єдиними програмістами, які в змозі побачити всі відмінності у силі між різними мовами, є ті, хто розуміє найпотужнішу. (Це, мабуть, мав на увазі Ерік Реймонд про те, що Лісп зробить вас кращим програмістом.) Ви не можете довіряти думкам інших, через парадокс Блуба: вони задоволені якою мовою вони користуються, бо це диктує як вони думають про програми.

Якщо виявиться, що я еквівалент програміста "Blub" завдяки використанню c ++, то виникає таке питання: Чи є корисні поняття чи методи, з якими ви стикалися на інших мовах, які вам було б важко осмислити, якби у вас писав чи «думав» у c ++?

Наприклад, парадигма логічного програмування, що спостерігається на таких мовах, як Prolog і Mercury, може бути реалізована в c ++ за допомогою бібліотеки castor, але в кінцевому підсумку я вважаю, що концептуально я замислююсь з точки зору коду Prolog і перекладаю на еквівалент c ++ при використанні цього. Як спосіб розширити свої знання з програмування, я намагаюся з’ясувати, чи є інші подібні приклади корисних / потужних ідіом, які ефективніше виражаються іншими мовами, про які я, можливо, не знаю як розробник c ++. Інший приклад, який спадає на думку, - це макросистема в lisp, генерування програмного коду всередині програми, здається, має багато переваг для деяких проблем. Здається, це важко здійснити і продумати зсередини c ++.

Це питання не може бути дискусією "c ++ vs lisp" або будь-якою дискусією типу мовних воєн. Задаючи таке питання, це єдиний спосіб, коли я бачу можливість дізнатися про речі, про які я не знаю, я не знаю.



2
Я згоден. Поки це не перетвориться на дискусію C ++ проти Ліспа, я думаю, що тут є чому навчитися.
jeffythedragonslayer

@MasonWheeler: there are things that other languages can do that Lisp can't- Навряд чи, оскільки Лісп є Тьюрінгом. Можливо, ви хотіли сказати, що в Ліспі є деякі речі, які не практично робити? Я можу сказати те саме про будь-яку мову програмування.
Роберт Харві

2
@RobertHarvey: "Всі мови однаково потужні в сенсі того, що Тюрінг є рівнозначним, але це не сенс слова, про яке програмісти дбають. (Ніхто не хоче програмувати машину Тюрінга.) Такого типу силових програмістів, про які піклуються, може не бути. формально визначений, але одним із способів пояснення цього було б сказати, що він стосується особливостей, які ви могли отримати лише в менш потужній мові, написавши перекладача для більш потужної мови в ній ". - Пол Грехем, виноска до питання про тролліст. (Дивіться, що я маю на увазі?)
Мейсон Уілер

@Mason Wheeler: (Не дуже.)
Роберт Харві

Відповіді:


16

Ну, оскільки ви згадали про Haskell:

  1. Узгодження шаблону Я вважаю, що відповідність шаблонів набагато простіше читати та писати. Розгляньте визначення карти та подумайте, як вона буде реалізована мовою без відповідності шаблону.

    map :: (a -> b) -> [a] -> [b]
    map f [] = []
    map f (x:xs) = f x : map f xs
  2. Тип типу. Іноді це може бути болем, але це надзвичайно корисно. Ви повинні запрограмувати з нею, щоб дійсно зрозуміти це і скільки помилок він застає. Також референтна прозорість чудова. Це стає очевидним лише після програмування в Haskell на деякий час, скільки помилок викликано керуванням державою в імперативній мові.

  3. Функціональне програмування загалом. Використання карт і складок замість ітерації. Рекурсія. Йдеться про мислення на вищому рівні.

  4. Ледача оцінка. Знову мова йде про роздуми на більш високому рівні та дозволити системі обробляти оцінку.

  5. Кабал, пакети та модулі. Мати пакети для завантаження Cabal для мене набагато зручніше, ніж знаходити вихідний код, писати файл файлу тощо. Бути в змозі імпортувати лише певні імена набагато краще, ніж по суті, щоб усі вихідні файли були скинуті разом, а потім скомпільовані.


2
Примітка про відповідність шаблонів: я б не сказав, що простіше писати взагалі, але після того, як ви трохи прочитаєте проблему з виразом, стає зрозуміло, що такі речі, як, якщо і перемикають оператори, перерахунки та шаблон спостерігача, - все це неповноцінні реалізації алгебраїчних типів даних + Узгодження шаблонів. (І давайте навіть не розпочати роботу над тим, як, можливо, заставляє нульові винятки покажчика застарілими)
hugomg

Те, що ви говорите, є правдою, але проблема вираження стосується обмеження типів алгебраїчних даних (і подвійних обмежень стандартних OOP).
Blaisorblade

@hugomg Ви мали на увазі шаблон відвідувачів замість Observer?
Себастьян Редл

так. Я завжди переключаю ці два імені :)
hugomg

@hugomg Йдеться не про те, щоб Maybe(див. C ++ див. std::optional), а про те, щоб чітко позначити речі як необов'язкові / зведені назовні / можливо.
Дедуплікатор

7

Пам'ятайте!

Спробуйте написати це на C ++. Не з C ++ 0x.

Занадто громіздкий? Гаразд, спробуйте це з C ++ 0x.

Подивіться, чи можете ви перемогти цю 4-лінійну (або 5-рядкову, будь-яку: P) компіляційну версію в D:

auto memoize(alias Fn, T...)(T args) {
    auto key = tuple(args);                               //Key is all the args
    static typeof(Fn(args))[typeof(key)] cache;           //Hashtable!
    return key in cache ? cache[key] : (cache[key] = Fn(args));
}

Все, що вам потрібно зробити, щоб зателефонувати йому, це щось на кшталт:

int fib(int n) { return n > 1 ? memoize!(fib)(n - 1) + memoize!(fib)(n - 2) : 1;}
fib(60);

Ви також можете спробувати щось подібне в Scheme, хоча це трохи повільніше, тому що це відбувається під час запуску і тому, що пошук тут лінійний, а не хешований (і добре, тому що це схема):

(define (memoize f)
    (let ((table (list)))
        (lambda args
            (cdr
                (or (assoc args table)
                    (let ((entry (cons args (apply f args))))
                        (set! table (cons entry table))
                        entry))))))
(define (fib n)
        (if (<= n 1)
            1
            (+ (fib (1- n))
                (fib (- n 2)))))))
(set! fib (memoize fib))

1
Отже, ви любите APL, де ви можете написати що-небудь в одному рядку? Розмір не має значення!
Бо Персон

@Bo: я не використовував APL. Я не впевнений, що ви маєте на увазі під "розміром не має значення", але чи є щось не так у моєму коді, що змушує вас це сказати? І чи є якась перевага того, як ви зробили це іншою мовою (на зразок C ++), про яку я не знаю? (Я трохи відредагував назви змінних, на випадок, про що ви мали на увазі.)
Мехрдад

1
@Mehrdad - Мій коментар про найбільш компактну програму не є ознакою найкращої мови програмування. У такому випадку APL виграє руки вниз, тому що ви робите більшість справ з одним оператором чарівності. Проблема лише в тому, що вона не читається.
Бо Персон

@Bo: Як я вже сказав, я не рекомендував APL; Я ніколи навіть цього не бачив. Розмір був одним із критеріїв (хоча й значущим, як це видно, якщо ви спробуєте це з C ++) ... але чи є щось не так у цьому коді?
Мехрдад

1
@ Matt: Ваш код memoized на функцію, але цей код може memoize будь функції. Вони насправді не є рівнозначними. Якщо ви насправді намагаєтеся записати подібну функцію вищого порядку в C ++ 0x, це набагато більш втомливо, ніж у D (хоча це все-таки цілком можливо ... хоча це не можливо в C ++ 03).
Мехрдад

5

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

Однак, я не можу придумати верхню частину головної мови рідної мови C ++, яка робить те, що робиться yieldв Python або JavaScript.

Інший приклад - паралельне програмування . C ++ 0x буде говорити про це, але нинішній стандарт не робить, і паралельність - це зовсім новий спосіб мислення.

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


Я навіть не можу почати думати, як важко було б створити генератори в C ++, що даються C ++ 2003. C ++ 2011 р. Полегшить, але все-таки нетривіально. Рутинна робота з C ++, C # і Python, генератори - це легко та легко функція, яку я найбільше сумую в C ++ (тепер, коли C ++ 2011 додала лямбда).

Я знаю, що за це мене знімуть , але якби мені абсолютно довелося впроваджувати генератори в C ++, я повинен був би використовувати ... setjmpі longjmp. Я поняття не маю, наскільки це зламається, але, мабуть, винятки будуть першими. Тепер, якщо ви пробачте, мені потрібно перечитати Modern C ++ Design, щоб це вийти з голови.
Майк Десімоне

@Mike DeSimone, чи можете ви детально пояснити, як би ви спробували рішення за допомогою setjmp та longjmp?

1
Короутини ізоморфні для функторів.
GManNickG

1
@Xeo, @Mike: xkcd.com/292
Мехрдад

5

Супроводи - це надзвичайно корисна мовна функція, яка лежить в основі більшої кількості відчутних переваг інших мов у порівнянні з C ++. Вони в основному забезпечують додаткові стеки, тому функції можна переривати і продовжувати, надаючи схожі на конвеєр мови засоби, які легко подають результати операцій через фільтри до інших операцій. Це чудово, і в Ruby я знайшов це дуже інтуїтивно та елегантно. Лінива оцінка також пов'язана з цим.

Інтроспекція та компіляція / виконання коду під час виконання / оцінювання / що завгодно - це потужно потужні функції, яких не вистачає на C ++.


Програми доступні у FreeRTOS ( див. Тут ), який реалізований у C. Цікаво, що потрібно, щоб вони працювали в C ++?
Майк Десимоне

Копрограми - це неприємний злом для емуляції об'єктів у C. У C ++ об'єкти використовуються для з’єднання коду та даних. Але в С не можна. Таким чином, ви використовуєте стек спільної рутини для зберігання даних, а функцію спільної рутини - для зберігання коду.
MSalters

Коротинії на C ++: crystalclearsoftware.com/soc/coroutine
Ferruccio

1
@Ferruccio: Дякую за посилання ... в статті у Вікіпедії також є кілька. @MSalters: що змушує вас описувати спільні програми як "неприємний злом"? Здається для мене дуже довільною перспективою. Використання стека для зберігання стану також виконується за допомогою рекурсивних алгоритмів - вони теж хакітні? FWIW, coroutines та OOP вийшли на сцену приблизно в один і той же час (на початку 1960-х) ... сказати, що колишній хак для об'єктів на C здається химерним ... Я б уявив, що кілька програмістів на C тоді були зацікавлені в емуляції об'єктів, > 15 років до C ++.
Тоні

4

Впровадивши систему комп’ютерної алгебри і в Lisp, і на C ++, я можу вам сказати, що це завдання було набагато простіше в Lisp, хоча я і був початківцем мовою. Цей спрощений характер у списках спрощує безліч алгоритмів. Звичайно, версія C ++ була в мільйони разів швидшою. Так, я міг би зробити ліпшу версію швидше, але код не був би таким лісивим. Сценарій - це ще одна річ, яка завжди буде простішою, наприклад. Вся справа у використанні правильного інструменту для роботи.


Яка різниця у швидкості?
Quant_dev

1
@quant_dev: звичайно, кратне на мільйон!
Метт Еллен

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

2

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

Чим "потужніша" та "виразніша" мова, тим обмеженіше її використання. Тож, можливо, "потужний" та "виразний" - це неправильні слова, які слід використовувати для інструменту вузької корисності. Можливо, "відповідні" або "абстрактні" - кращі слова для таких речей.

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

І все моє пізніше розуміння мови вищого рівня завдячує моєму досвіду роботи з асемблером. Все, що я дізнався пізніше, було легко, бо, бачте, все - як би не було абстрактним - зрештою повинно вміститись до обладнання.

Можливо, ви захочете забути про більш високі та більш високі рівні абстракції - тобто про більш вузькі та вузькі поля зору. Ви завжди можете забрати це пізніше. Навчитися досить просто - за кілька днів. На мій погляд, вам краще буде вивчити мову обладнання 1 , щоб максимально наблизитися до кісток.


1 Можливо , не зовсім доречний, але carі cdrвзяти їх імена з апаратних засобів: перший Лисп побіг на машині , яка мала фактичний декремент регістр і фактична адреса Регістр. Як це?


Ви бачите, що вибір - це подвійний меч. Ми всі до цього прагнемо, але є темна сторона і це робить нас нещасними. Краще мати дуже чіткий погляд на світ і визначені межі, якими можна керувати. Люди - це дуже творчі істоти, які можуть робити чудові речі з обмеженими інструментами. Отже, підводячи підсумок, я кажу, що це не мова програмування, але є талановиті люди, які можуть змусити співати будь-яку мову!
Чад

"Пропонувати - це створити; визначити - знищити." Думаючи, що ти можеш полегшити життя іншою мовою, почуваєш себе добре, але як тільки ти зробиш стрибок, то доведеться мати справу з бородавками нової мови.
Майк Десимоне

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

@Mike, тоді вам доведеться мати спілкування з попередньою мовою в межах нової;)
Чад

2

Асоціативні масиви

Типовим способом обробки даних є:

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

Правильний інструмент для цього є асоціативний масив .

  • Найкраща мовна підтримка асоціативних масивів, які я бачив, - це MUMPS , де асоціативні масиви: 1. завжди сортуються 2. їх можна створити на диску (так звана база даних) з таким самим синтаксисом. (Побічний ефект: він надзвичайно потужний як база даних, програміст має доступ до нативного btree. Найкраща система NoSQL коли-небудь.)
  • Мій другий приз припадає на PHP , мені подобається синтаксис foreach та easy, як $ a [] = x або $ a [x] [y] [z] ++ .

Мені не дуже подобається синтаксис асоціативного масиву JavaScript, тому що я не можу створити, скажімо, [x] [y] [z] = 8 , спочатку я повинен створити [x] і a [x] [y] .

Гаразд, в C ++ (і на Java) є хороший портфоліо класів контейнерів Map , Multimap , що б там не було, але якщо я хочу сканувати, я повинен зробити ітератор, і коли я хочу вставити новий елемент глибокого рівня, я повинні створити всі верхні рівні тощо. Некомфортно.

Я не кажу, що в C ++ (і Java) немає корисних асоціативних масивів, але безмовні (або не строгі набрані) мови скриптів перемагають складені, оскільки вони є безтиповими мовами скриптів.

Відмова: Я не знайомий з C # та іншими .NET мовами, AFAIK вони мають гарну асоціативну обробку масиву.


1
Повне розкриття інформації: MUMPS не для всіх. Цитата: Щоб навести трохи більше "реального світу" прикладу жаху, що є MUMPS, почніть з участі однієї частини Міжнародного конкурсу збитого коду C, тире Perl, двох обвальних заходів FORTRAN і SNOBOL, а також незалежних і неузгоджених внесків десятки медичних дослідників, і там ви їдете.
Майк Десімоне

1
У Python ви можете використовувати або вбудований dictтип (наприклад x = {0: 5, 1: "foo", None: 500e3}, зауважте, що для клавіш або значень немає жодної вимоги). Намагатися зробити щось на кшталт a[x][y][z] = 8важко, тому що мова повинна заглянути в майбутнє, щоб побачити, чи збираєтесь ви встановити значення чи створити інший рівень; вираз a[x][y]сам по собі не говорить вам.
Майк Десимоне

MUMPS спочатку є базовою мовою з асоціативними масивами (може безпосередньо зберігатися на диску!). Пізніші версії містять процедурні розширення, що робить його дуже схожим на основний PHP. Один, хто боїться Basic та PHP, повинен вважати свинку лякаючою, а інші - ні. Програмісти ні. І пам’ятайте, що це дуже стара система, всі дивні речі, як-от однобуквені інструкції (хоча ви можете використовувати повні назви), порядок оцінки LR тощо - а також незвичайні рішення - мають лише одну мету: оптимізацію .
ern0

"Ми повинні забути про малу ефективність, скажімо, про 97% часу: передчасна оптимізація - корінь усього зла. Але ми не повинні пропускати свої можливості на цих критичних 3%". - Дональд Кнут. Те, що ви описуєте, звучить для мене як старовинна мова, наголос на відсталій сумісності, і це нормально. Особисто я вважаю, що технічне обслуговування важливіше, ніж оптимізація, а мова з неалгебраїчними виразами та командами з однієї літери звучить контрпродуктивно. Я обслуговую замовника, а не мову.
Майк Десімоне

@Mike: дуже цікаві посилання, які ви опублікували, я добре посміявся, читаючи їх.
човник87

2

Я не навчаюсь Java, C \ C ++, складанню та Java Script. Я використовую C ++, щоб заробляти на життя.

Хоча, я б сказав, що мені більше подобаються програмування монтажу та програмування на С. Це в основному з імперативним програмуванням.

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

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

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

Це стає складнішим, коли ви додаєте парадигми програмування до суміші, оскільки наш погляд на світ у всіх різний.


2

чи є якась потужна мовна особливість чи ідіома, якою ви користуєтесь мовою, яку було б важко концептуалізувати чи реалізувати, якби ви писали лише на c ++?

Чи є якісь корисні поняття чи прийоми, з якими ви стикалися в інших мовах, які вам було б складно осмислити, якби ви писали чи «думали» на c ++?

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

Реєструйте конвенції про розподіл та виклики

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

Щоб дізнатись про такі поняття, я рекомендую ознайомитись з програмуванням мови монтажу та ознайомтесь із цією статтею про якість генерації коду ARM .

Генерація коду часу виконання

Якщо ви знаєте лише C ++, то, напевно, ви думаєте, що шаблони - це всебічне і кінцеве метапрограмування. Вони ні. Насправді вони є об'єктивно поганим інструментом метапрограмування. Будь-яка програма, яка маніпулює іншою програмою, є метапрограмою, включаючи інтерпретатори, компілятори, системи комп’ютерної алгебри та докази теореми. Генерація коду під час виконання - корисна функція для цього.

Я рекомендую розпочати реалізацію схеми та пограти з нею, EVALщоб дізнатися про метациркулярну оцінку.

Маніпуляція деревами

Дерева є скрізь у програмуванні. При розборі у вас є абстрактні синтаксичні дерева. У компіляторах є ІР, які є деревами. У графіці та графічному програмуванні у вас є дерева сцен.

Цей "надзвичайно простий парсер JSON для C ++" важить всього 484 LOC, що дуже мало для C ++. Тепер порівняйте його з моїм простим аналізатором JSON, який важить лише 60 LOC F #. Різниця полягає насамперед у тому, що алгебраїчні типи даних ML та відповідність шаблонів (включаючи активні візерунки) значно полегшують маніпулювання деревами.

Ознайомтесь і з червоно-чорними деревами в OCaml .

Суто функціональні структури даних

Нестача GC в C ++ робить практично неможливим прийняття деяких корисних підходів. Суто функціональні структури даних є одним із таких інструментів.

Наприклад, ознайомтеся з цим збірником регулярних виразів 47 рядків в OCaml. Стислість зумовлена ​​значною мірою широким використанням суто функціональних структур даних. Зокрема, використання словників із наборами ключів. Це дійсно важко зробити в C ++, оскільки словники та набори stdlib всі змінні, але ви не можете мутувати ключі словника або ви порушуєте колекцію.

Логічне програмування та скасування буферів - це інші практичні приклади, коли суто функціональні структури даних роблять щось складне в C ++ дуже просто в інших мовах.

Хвост дзвінки

Мало того, що C ++ не гарантує хвостові дзвінки, але і RAII принципово не протиставляється тому, що деструктори перешкоджають виклику в положенні хвоста. Хвостові дзвінки дозволяють вам здійснювати необмежену кількість функціональних дзвінків, використовуючи лише обмежену кількість простору стеку. Це чудово підходить для впровадження державних машин, включаючи розширювані державні машини, і це чудова картка "вийти з в'язниці" за багатьох несприятливих обставин.

Наприклад, ознайомтеся з цією реалізацією проблеми 0-1 рюкзака, використовуючи стиль передачі продовження із запам'ятовуванням у F # з фінансової галузі. Якщо у вас є хвостові дзвінки, стиль проходження продовження може бути очевидним рішенням, але C ++ робить його непереборним.

Паралельність

Ще один очевидний приклад - одночасне програмування. Хоча це цілком можливо в C ++, він є надзвичайно схильним до помилок порівняно з іншими інструментами, особливо це стосується послідовних процесів, як це спостерігається на таких мовах, як Erlang, Scala та F #.


1

Це давнє запитання, але оскільки ніхто про це не згадував, я додам перелік (і тепер дік) розуміння. Написати однолінійку в Haskell або Python легко, що вирішує проблему Fizz-Buzz. Спробуйте це зробити на C ++.

У той час як C ++ робив величезні кроки до сучасності за допомогою C ++ 11, це трохи розтягує назву "сучасної" мови. C ++ 17 (який ще не був випущений) робить ще більше кроків, щоб досягти сучасних стандартів, якщо "сучасний" означає "не з попереднього тисячоліття".

Навіть найпростіші розуміння, які можна записати в один рядок на Python (і підкоряючись обмеженню довжини рядка 79 символів Гуйдо), стають безліччю і безліччю рядків кодів при перекладі на C ++, а деякі з цих рядків коду С ++ є досить складними.


Зверніть увагу: Більшість моїх програм програмується на C ++. Мені подобається мова.
Девід Хаммен

Я думав, що пропозиція про діапазони повинна була вирішити цю проблему? (Навіть не в С ++ 17, я думаю)
Мартін Ба

2
"масові переходи до сучасності": Які "сучасні" особливості надає C ++ 11, що були винайдені в поточному тисячолітті?
Джорджіо

@MartinBa - Моє розуміння пропозиції "діапазонів" полягає в тому, що це заміна ітераторів, з якими легше працювати і менш схильних до помилок. Я не бачив жодних припущень, які б дозволяли зробити щось таке цікаве, як розуміння списку.
Жуль

2
@ Giorgio - які особливості будь-якої популярної в даний час мови були винайдені в поточному тисячолітті?
Жуль

0

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


Це можливо в Objective-C, і це робить програмування інтерфейсу користувача легким вітерцем. Ви можете сказати кнопці: "Будь ласка, зателефонуйте цьому методу для цього об'єкта при натисканні", і кнопка зробить це. Ви можете безкоштовно використовувати будь-яке ім'я методу для зворотного дзвінка, який вам подобається, він не заморожений у коді бібліотеки, ви не повинні успадковувати адаптер для його роботи, а також компілятор не хоче вирішити виклик під час компіляції, і, що не менш важливо, ви можете сказати двом кнопкам викликати два різні методи одного і того ж об'єкта.

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

Саме ця особливість Objective-C навчила мене оцінювати здатність мови передавати будь-який тип об'єктів / функцій / що б не було важливо-поняття-мова - навколо них, а також сили їх збереження змінні. Будь-яка точка мови, яка визначає будь-який тип поняття, але не забезпечує засоби для його зберігання (або посилання на нього) у всіх доступних видах змінних, є важливим каменем спотикання і, ймовірно, джерелом дуже негарного, дубльований код. На жаль, барокові мови програмування мають тенденцію проявляти ряд таких моментів:

  • У C ++ ви не можете записувати тип VLA, а також зберігати вказівник на нього. Це фактично забороняє справжні багатовимірні масиви динамічного розміру (які доступні в C з C99).

  • У C ++ ви не можете записати тип лямбда. Ви навіть не можете ввести це. Таким чином, немає можливості обійти лямбда або зберегти посилання на неї в об'єкті. Функції лямбда можна передавати лише шаблонам.

  • У Fortran ви не можете записати тип назви. Просто не існує способу передати назовнику будь-яку рутину. Отже, якщо у вас є складний алгоритм, який повинен вміти обробляти два різних назви, вам не пощастить. Ви не можете просто написати алгоритм один раз і передати йому відповідні назви.

Це лише кілька прикладів, але ви бачите спільну думку: Щоразу, коли ви бачите таке обмеження вперше, зазвичай вам не буде байдуже, бо здається такою божевільною ідеєю робити заборонену справу. Однак, виконуючи певну програмування на цій мові, з часом ви стикаєтесь до того, що це точне обмеження стає справжньою неприємністю.


1
I have not seen a similarly flexible way to define a callback in any other language yet (though I'd be very interested to hear about them!) Те, що ви тільки що описуєте, звучить точно так, як працює керований подіями код інтерфейсу в Delphi. (І в .NET WinForms, на який сильно вплинув Delphi.)
Мейсон Уілер

2
"У C ++ ви не можете записати тип VLA" [...] - у C ++ VLA-стилі у стилі C99 непотрібні, оскільки у нас є std::vector . Хоча це трохи менш ефективно через те, що не використовується розподіл стеків, він функціонально ізоморфний для VLA, тому насправді не вважається проблемою типу "blub": програмісти на C ++ можуть подивитися, як це працює, і просто сказати: "так" , C робить це ефективніше, ніж C ++ ".
Жуль

2
"У C ++ ви не можете записати тип лямбда. Ви навіть не можете ввести його. Таким чином, немає можливості пройти навколо лямбда або зберегти посилання на нього в об'єкті" - ось для чого std::function.
Жуль

3
"Я ще не бачив подібного гнучкого способу визначення зворотного дзвінка будь-якою іншою мовою (хоча мені було б дуже цікаво почути про них!)" - на Java ви можете написати, object::methodі він буде перетворений на екземпляр будь-якого інтерфейсу, який очікує отримання коду. У C # є делегати. Кожна об'єктно-функціональна мова має цю особливість, оскільки це в основному точка перетину двох парадигм.
Жуль

@Jules Ваші аргументи якраз і полягають у тому, що стосується Blub-Paradox. Як досвідчений програміст на C ++, ви не вважаєте це обмеженням. Однак вони є обмеженнями, і інші мови на зразок C99 є більш потужними в цих конкретних точках. До останнього моменту: на багатьох мовах можливі обхідні шляхи, але я не знаю жодної, яка дійсно дозволяє передати ім'я будь-якого методу в інший клас і змусити його викликати його на якомусь об'єкті, який ви також надаєте.
cmaster
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.