Пол Грем, «Хакери і художники», глава 10: «Programming Languages Explained»

imageКнига «Хакери і Художники», глава 10.

Ця глава є тільки в книзі, на сайті Пола Грема вона відсутня.
До речі, залишилося зовсім трохи і буде готова остання глава книги, тим самим буде повний російський хабраперевод «Хакерів і художників». (Попередній переклад — Пол Грем: «The Other Road Ahead».)

За допомогу з перекладом спасибі Щекотовой Яні.

Мови програмування «в розрізі»

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

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

Машинний мова

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

Проблема з машинним мовою/мовою асемблера полягає в тому, що більшість комп'ютерів можуть виконувати лише дуже прості речі. Наприклад, припустимо, що вам потрібно, щоб комп'ютер відтворив короткий звуковий сигнал 10 разів. Сумніваюся, що у комп'ютера є інструкція для здійснення якої-небудь дії n разів. Тому, якщо б вам знадобилося, щоб комп'ютер щось зробив 10 разів, використовуючи справжні машинні інструкції, вам би довелося написати щось схоже на:

put the number 10 location in memory 0
a location if 0 is negative, go to line b
beep
subtract 1 from the number in location 0
go to line a
b ...rest of program…

Якщо вам доводиться виконувати стільки роботи тільки для того, щоб змусити машину пропикать 10 разів, то тільки уявіть, скільки праці витрачається на написання чогось на зразок текстового процесора або програми для роботи з електронними таблицями.

І, до речі, погляньте ще раз на програму. Вона і справді відтворить короткий звуковий сигнал 10 разів? Неа, 11. У першій рядку мені треба було вказати 9 а не 10. Я навмисно помістив в наш приклад помилку, щоб продемонструвати важливий аспект з приводу мов. Чим більше вам доводиться писати для виконання тих чи інших дій, тим складніше розгледіти помилки.

Високорівневі мови

Уявіть, що вам потрібно створювати програми на мові асемблера, але у вас є якийсь помічник для виконання всякої «брудної» роботи. Тому ви можете просто написати щось типу

do times 10 beep,

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

Цей більш зручний мову, який ви згодовуєте» компілятору, і називається високорівневим. Він дозволяє складати програми на основі потужних команд, таких як «do щось n разів» замість горезвісного «add два числа.»

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

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

Open Source

Високорівнева мова, який ви згодовуєте» компілятору, також відомий як вихідний код, а результат його трансляції на машинну мову називається об'єктним кодом. Коли ви купуєте комерційне, вам зазвичай надається тільки об'єктний код. (Об'єктний код так складно читати, тому що він добре зашифрований для захисту комерційної таємниці компанії). Але останнім часом з'явився альтернативний підхід: з відкритим вихідним кодом (open source), коли вам надається вихідний текст програми, який при бажанні можна модифікувати.

Різниця між цими двома моделями істотна. Open source надає вам куди більше контролю. Коли ви користуєтеся відкритим ПО і хочете зрозуміти, що воно робить, то ви можете прочитати вихідний код і з'ясувати це. А при бажанні, ви можете навіть внести зміни в програму і перекомпілювати її.

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

Але переваги open source не зводяться тільки до того, що у вас є можливість внести виправлення при необхідності. Це можуть все. З відкритим вихідним кодом – це документ, представлений для експертної оцінки. Багато розумні люди вивчили исходники відкритих операційних систем Linux і FreeBSD і вже знайшли більшість помилок. У той час як Windows надійна рівно настільки, наскільки це може забезпечити відділ QA у великих компаніях.

Прихильників open source іноді сприймають як диваків, які виступають проти самої ідеї права власності в цілому. Деякі такими і є. Але я точно не виступаю проти цього права, а адже я б дуже неохоче встановлював, вихідних кодів якого у мене б не було. Середньому користувачеві може і не знадобиться вихідний код його текстового процесора, але коли вам дійсно потрібна надійність, то це вже вагома причина для того, щоб використовувати open source.

Мовні війни

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

Fortran, Lisp, Cobol, Basic, C, Pascal, Smalltalk, C++, Java, Perl, Python – все це високорівневі мови. І це тільки ті, які найбільш відомі. Сущесвуют буквально сотні різних мов високого рівня. І на відміну від машинних, які всі пропонують подібний набір інструкцій, ці високорівневі мови надають вам досить різні принципи для побудови програм.

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

Деякі комп'ютерники, можливо, бажання здатися більш досвідченими, скажуть вам, що всі мови за своєю суттю однакові. «Я програмував на мовах всіх типів, – сказав суворий старий хакер за стійкою бару, – і неважливо, яким користуватися. Що дійсно важливо, так це правильно ти мислиш.» Або щось в цьому дусі.

Звичайно ж, це нісенітниця. Існує величезна різниця між, скажімо, Fortran I і останньою версією Perl. Або, якщо вже на те пішло, між ранньою і останньої версіями Perl. Але суворий старий хакер може і сам вірить у те, що говорить. Можна писати одні і ті ж примітивні паскалеподобные програмки практично на кожному мовою. Якщо ви харчуєтеся тільки в mcdonald's, то вам здасться, що їжа в кожній країні одна і та ж.

Деякі просунуті програмісти віддають перевагу ту мову, до якого звикли, і недолюблюють всі інші. Інші кажуть, що всі мови однакові. Але істина знаходиться десь посередині між цими двома крайнощами. Мови дійсно відрізняються один від одного, але складно сказати напевно, які з них краще. Ситуація все ще знаходиться в розвитку.

Рівень абстракцій

Як високорівневі мови є більш абстрактними по відношенню до мов асемблера, так і деякі з цих високорівневих мов більш абстрактні, ніж інші. Наприклад, C досить низькорівневий, практично portable мова асемблера, в той час як Lisp володіє дуже високим рівнем абстракцій.

Якщо програмувати на високорівневих мовах краще, ніж на мові асемблера, то можна очікувати, що чим вище рівень мови, тим він краще. Звичайно так, але не завжди. Мова може бути дуже абстрактний, але пропонує не ті абстракції. Думаю, що саме це і відбувається, наприклад, в Prolog. У ньому реалізовані неймовірно потужні абстракції для вирішення близько 2% завдань, а весь інший час ви дуже старанно намагаєтеся використовувати ці абстракції неналежним чином, і пишете програми на мові Pascal.

Ще одна причина, по якій вам би захотілося використовувати низькорівневий мова, це продуктивність. Якщо вам потрібен супер-швидкий код, то краще дотримуватися машинних інструкцій. Більшість операційних систем написані на C, і це не збіг. Оскільки апаратне забезпечення стає все швидше, то створювати програми на мовах такого ж низького рівня як З вже не так критично важливо, але всім все ще хочеться, щоб операційні системи працювали як можна швидше. (Або, ймовірно, всім хочеться завжди бути напоготові на випадок можливої атаки на переповнення буферу.[1])

Ремені безпеки або наручники?

Найбільший спір у сфері проектування мов, ймовірно, той, який ведеться між тими, хто думає, що мова повинна захищати програмістів від вчинення дурниць, і тих, хто вважає, що програмістам повинно бути дозволено робити те, що вони захочуть. Java відноситься до першого табору, а Perl – до другого. (І не дивно, адже міністерство оборони США помешано на Java.)

Прихильники ліберальних мов висміюють табір опонентів, називаючи такі мови «B&D» (bondage and discipline – рабство та дисципліна), з досить зухвалим натяком на те, що ті, кому подобається програмувати на таких мовах, просто невдахи. Я не знаю, як протиборча сторона називає мови подібні Perl. Можливо, вони не з тих людей, які вигадують образливі прізвиська для опонентів.

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

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

OO

Ще однією великою темою на даний момент є об'єктно-орієнтоване програмування. Воно являє собою інший спосіб організації програм. Припустимо, ви хочете написати програму для знаходження площі двовимірних фігур. Спочатку програма буде мати уявлення тільки про колі, квадраті. Одним із способів реалізації написання одного шматка коду, в межах якого ви перевіряєте, що у вас запитують: коло або квадрат. А потім використовуєте соответвствующую формулу для пошуку площі. Об'єктно-орієнтований спосіб написання програм передбачає створення двох класів, коло і квадрат, а потім прив'язати до кожного класу фрагмент коду (який називається метод) для знаходження площі даного типу фігури. Коли вам потрібно обчислити площу чого-небудь, ви питаєте, до якого класу це щось належить, витягаєте відповідний метод, і запускаєте його, щоб отримати результат.
Ці два випадки можуть здатися дуже схожими. І справді, те, що в дійсності відбувається при запуску коду, досить схоже. (Не дивно, т. к. ви вирішуєте одну і ту ж задачу) Але код в підсумку може виглядати по-різному. В об'єктно-орієнтованою версією, код розрахунку площі квадрата і круга може навіть бути представлений в різних файлах, один файл містить всі, що пов'язано з колом, а інший – все, що пов'язано з квадратом.

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

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

В останньому варіанті мало переваг. Безсумнівно, мову, який дозволяє зробити x принаймні так само добре, як і той, що змушує вас робити таким чином. Тому, стосовно мов, ми, принаймні, можемо обійти це питання. Звичайно, користуйтеся мовою, який дозволяє писати ОО програми. А чи хочете ви цього насправді – це вже інше питання.

Відродження

Я думаю, всі, хто пов'язаний з мовами, погодяться з тим, що останнім часом з'явилася величезна кількість нових мов програмування. До 1980 року, тільки університети могли дозволити собі обладнання, необхідне для розробки таких мов, і тому багато мови були спроектовані професорами або дослідниками в великих компаніях. Зараз навіть школяр може дозволити собі потрібне «залізо».
Натхненні в основному прикладом Ларрі Уолла, творця Perl, багато комп'ютерники думають, чому я не можу спроектувати свій власний мову? Ті, кому вдається приборкати міць open source співтовариства, мають доступ до величезної кількості коду, написаного в стислі терміни.

В результаті з'являється такий тип мови, який можна назвати нестійким: мова, чиє ядро не дуже добре спроектовано, але який володіє надзвичайно потужними бібліотеками для вирішення специфічних завдань. (Уявіть автомобіль марки «Zastava» (також відомий як «Yugo») з реактивним двигуном, прикрученим до даху). Для незначних, щоденних завдань, на вирішення яких програмісти витрачають багато часу, бібліотеки, можливо, важливіше ядра мови. Тому такі дивні гібридні рішення досить корисні, і, відповідно, стають популярними. Автомобіль «Zastava» з прикрученим до даху реактивним двигуном може бути і працював би, поки ви не спробували б виконати на ньому поворот [2].

Також в результаті ми отримаємо величезну різноманітність, яке завжди спостерігалося в програмних мовами. Fortran, Lisp, and APL відрізняються один від одного так само сильно, як морська зірка, ведмідь і бабка, адже всі були створені до 1970. А нові відкриті мови природно продовжили цю традицію.

Здається, що я дізнаюся про новий мовою кожні два дні. Джонатан Еріксон назвав це «епохою відродження мов програмування». А ще люди іноді вживають фразу «мовні війни». Проте протиріччя тут немає. В епоху Відродження сталася купа воєн.

І дійсно, багато істориків вважають, що ці війни були побічним продуктом тих сил, що створили епоху Відродження [3]. Причиною цих сил в Європі, можливо, був той факт, що вона була розділена на деяке число дрібних конкуруючих держав. Вони розташовувалися досить близько один до одного, щоб ідеї могли кочувати з однієї в іншу, але в той же час були досить незалежні, щоб ні одному правителю не вдалося накласти заборону на нововведення, як одного разу це зробив суд Китаю, який заборонив розробку великих океанських кораблів.

Тому, можливо, все це й на краще, що програмісти живуть в постбіблійському світі. Якщо б ми всі використовували один і той же мова, він би, напевно, був не найкращим.

Примітки до глави 10

1 найпоширеніший спосіб злому комп'ютерів використовує деякі особливості мови C. C, коли ви відводите шматок пам'яті (буфер) для вхідних даних, ви припускаєте, що він буде розміщений поруч з пам'яттю, що містить адресу повернення поточного виконується коду. Адреса повернення – це область пам'яті коду, який буде виконуватися, коли поточний код завершить свою роботу. Це, по суті, наступний пункт у списку справ комп'ютера.

Тому якщо хтось захоче зламати ваш комп'ютер, і дізнається, що ви використовуєте 256-байтний буфер для зберігання деяких вхідних даних, тоді, просто посилаючи більше 256 байт, він може переписати адреса повернення. Коли поточний код завершиться, управління перейде до будь-якої області пам'яті, яка була заздалегідь визначена зловмисником. А область, яку він визначить, чи буде початком буфера, що містить програму на машинній мові на його вибір. Бінго: тепер на вашому комп'ютері виконується його програма.

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

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

2 Замітка для хакерів: це всього лише метафора. Не намагайтеся сісти за кермо машини «Zastava» з прикрученим до даху реактивним двигуном. Можливо, феномен реактивної машини далеко не новий. Fortran також зобов'язаний своєю популярністю, в основному, своїм бібліотек.

3 Cipolla, Carlo, Guns, Sails, and Empires: Technological Innovation and the Early Phases of European Expansion 1400-1700, Pantheon, 1965.




Хакери і художники
image
Глави і переказиwww.paulgraham.com/hptoc.html
  1. Why Nerds Are Unpopular
    Their minds are not on the game.
    оригінал, переклад частина 1, частина 2
  2. Hackers and Painters
    Hackers are makers, like painters or architects or writers.
    оригінал, переклад частина 1, частина 2, альтернатива
  3. What You can't Say
    How to think heretical thoughts and what to do with them.
    оригінал, переклад
  4. Good Bad Attitude
    Like Americans, hackers win by breaking rules.
    оригінал, переклад
  5. The Other Road Ahead
    Web-based software offers the biggest opportunity since the arrival of the microcomputer.
    оригінал, переклад частина 1
  6. How to Make Wealth
    The best way to get rich is to create wealth. And startups are the best way to do that.
    оригінал, перевод
  7. Mind the Gap
    Could «unequal income distribution» be less of a problem than we think?
    оригінал, переклад
  8. A Plan for Spam
    Till most recently experts thought spam filtering wouldn't work. This proposal changed their minds.
    оригінал, переклад
  9. Taste for Makers
    How do you make great things?
    оригінал, переклад
  10. Programming Languages Explained
    What a programming language is and why they are a hot topic now.
  11. The Hundred-Year Language
    How will we program in a hundred years? Why not start now?
    оригінал, перевод
  12. б'ється серцем the Averages
    For web-based applications you can use whatever language you want. So can your competitors.
    оригінал, переклад
  13. Revenge of the Nerds
    In technology, «industry best practice» is a recipe for losing.
    оригінал, переклад 1, 2, 3
  14. The Dream Language
    A good programming language is one that lets hackers have their way with it.
    оригінал, переклад частина 1, частина 2
  15. Design and Research
    Research has to be original. Design has to be good.
    оригінал, переклад


Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.