LL1 тарату тізіміндегі Revenge of the Nerds мақаласында көтерілген мәселелерді талқылау кезінде Paul Prescod есімде қалып қойған бір ой айтты.
Python-ның мақсаты — ықшамдылық емес, жүйелілік пен оқылымдылық.
Сырт көзге бұл бағдарламалау тілі туралы айтылған өте ауыр айыптау сияқты көрінеді. Менің пайымдауымша, ықшамдылық = құдірет. Егер солай болса, онда орындарын алмастырсақ, мынадай шығады:
Python-ның мақсаты — құдірет емес, жүйелілік пен оқылымдылық.
ал бұл адам жасағысы келетін ымыраға (егер бұл шынымен ымыра болса) ұқсамайды. Бұл Python-ның мақсаты бағдарламалау тілі ретінде тиімді болу емес деп айтумен бірдей дерлік.
Ықшамдылық = құдірет пе? Бұл маған маңызды сұрақ, бәлкім, тіл дизайнына қызығатын кез келген адам үшін ең маңызды сұрақ болып көрінеді және оған тікелей бетпе-бет келген пайдалы болар еді. Бұған бірден «иә» деп жауап беруге әлі толық сенімді емеспін, бірақ бастау үшін жақсы гипотеза сияқты.
Гипотеза
Менің гипотезам: ықшамдылық — бұл құдірет, немесе оған соншалықты жақын болғандықтан, патологиялық мысалдарды есепке алмағанда, оларды бірдей деп санауға болады.
Меніңше, ықшамдылық — бағдарламалау тілдерінің негізгі мақсаты. Компьютерлер үшін машиналық тілде тікелей не істеу керегін айтса да бәрібір болар еді. Жоғары деңгейлі тілдерді жасауға бейнеттенетініміздің басты себебі — машиналық тілдің 1000 жолын қажет ететін нәрсені жоғары деңгейлі тілдің 10 жолында айта алатындай (және ең бастысы, ойлана алатындай) артықшылыққа ие болу. Басқаша айтқанда, жоғары деңгейлі тілдердің басты мәні — бастапқы кодты кішірейту.
Егер бастапқы кодтың шағын болуы жоғары деңгейлі тілдердің мақсаты болса, ал қандай да бір нәрсенің құдіреті оның өз мақсатына қаншалықты жақсы жететіндігімен өлшенсе, онда бағдарламалау тілінің құдіретінің өлшемі — оның бағдарламаларыңызды қаншалықты шағын ететіндігі.
Керісінше, бағдарламаларыңызды шағын етпейтін тіл бағдарламалау тілдері атқаруға тиіс міндетті нашар орындайды, бұл жақсы кеспейтін пышақ немесе оқылмайтын баспа сияқты.
Метрикалар
Бірақ қандай мағынада шағын? Код көлемінің ең кең таралған өлшемі — код жолдарының саны. Бірақ бұл метрика ең көп таралған, себебі оны өлшеу ең оңай деп ойлаймын. Ешкім оны бағдарлама ұзындығының шынайы сынағы деп санамайтын шығар. Әртүрлі тілдерде бір жолға қанша нәрсе жазу керектігі туралы әртүрлі ережелер бар; C тілінде көптеген жолдарда бір немесе екі бөлгіштен басқа ештеңе болмайды.
Тағы бір оңай сынақ — бағдарламадағы таңбалар саны, бірақ бұл да онша жақсы емес; кейбір тілдер (мысалы, Perl) басқаларға қарағанда қысқа идентификаторларды ғана пайдаланады.
Менің ойымша, бағдарлама көлемінің жақсырақ өлшемі элементтер саны болар еді, мұндағы элемент — егер сіз бастапқы кодты көрсететін ағаш салсаңыз, жеке түйін болатын кез келген нәрсе. Айнымалының немесе функцияның аты — элемент; бүтін сан немесе жылжымалы үтірлі сан — элемент; мәтіндік литералдың сегменті — элемент; шаблон элементі немесе пішімдеу директивасы — элемент; жаңа блок — элемент. Шекаралық жағдайлар бар (-5 бұл екі элемент пе, әлде бір ме?), бірақ олардың көпшілігі әр тілде бірдей, сондықтан салыстыруға аса әсер етпейді деп ойлаймын.
Бұл метриканы әлі де нақтылау қажет және нақты тілдер жағдайында интерпретацияны қажет етуі мүмкін, бірақ ол дұрыс нәрсені, яғни бағдарламаның бөліктерінің санын өлшеуге тырысады деп ойлаймын. Меніңше, бұл жаттығуда сіз салатын ағаш — бағдарламаны ойша елестету үшін санаңызда құрастыруыңыз керек нәрсе, сондықтан оның көлемі оны жазу немесе оқу үшін жұмсайтын еңбегіңіздің мөлшеріне пропорционал.
Дизайн
Мұндай метрика бізге әртүрлі тілдерді салыстыруға мүмкіндік берер еді, бірақ, кем дегенде мен үшін, оның басты құндылығы бұл емес. Ықшамдылық сынағының басты құндылығы — тілдерді жобалаудағы бағдар ретінде қызмет етуі. Тілдер арасындағы ең пайдалы салыстыру — бір тілдің екі ықтимал нұсқасын салыстыру. Бағдарламаларды қысқарақ ету үшін тілде не істей аламын?
Егер бағдарламаның тұжырымдамалық жүктемесі оның күрделілігіне пропорционал болса, ал белгілі бір бағдарламашы белгіленген тұжырымдамалық жүктемені ғана көтере алса, онда бұл: «бағдарламашыларға барынша көп жұмыс тындыруға мүмкіндік беру үшін не істей аламын?» деген сұрақпен бірдей. Ал бұл мен үшін: «жақсы тілді қалай жобалай аламын?» деген сұрақпен пара-пар көрінеді.
(Айтпақшы, тілдерді жобалау сияқты ешнәрсе «барлық тілдер баламалы» деген ескі сөздің жалған екенін соншалықты анық көрсетпейді. Жаңа тілді жобалаған кезде, қайсысы жақсырақ екенін шешу үшін сіз үнемі екі тілді — егер мен x-ті жасасам қалай болады және жасамасам қалай болады деп — салыстырып отырасыз. Егер бұл шынымен мағынасыз сұрақ болса, онда монета лақтырып шеше салуға болар еді.)
Ықшамдылыққа ұмтылу жаңа идеяларды табудың жақсы жолы сияқты. Егер сіз көптеген түрлі бағдарламаларды қысқартатын бірдеңе жасай алсаңыз, бұл кездейсоқтық болмауы мүмкін: сіз пайдалы жаңа абстракцияны тапқан боларсыз. Тіпті қайталанатын үлгілерді іздеу арқылы көмектесетін бағдарлама жазуыңыз да мүмкін. Басқа тілдердің ішінде ықшамдылығымен танымал тілдер жаңа идеяларды іздейтін тілдер болар еді: Forth, Joy, Icon.
Салыстыру
Менің білуімше, бұл мәселелер туралы алғаш жазған адам — The Mythical Man-Month кітабында Fred Brooks болды. Ол бағдарламашылар қай тілде жазса да, күніне шамамен бірдей көлемде код өндіретін сияқты деп жазды. Жиырмадан асқан шағымда мұны алғаш оқығанда, бұл мен үшін үлкен тосынсый болды және үлкен салдары бардай көрінді. Бұл (a) бағдарламалық жасақтаманы тезірек жазудың жалғыз жолы — неғұрлым ықшам тілді пайдалану екенін, және (b) бұған күш салған адам мұны істемеген бәсекелестерін шаң қаптырып кете алатынын білдірді.
Brooks гипотезасы, егер ол рас болса, хакерліктің дәл ортасында тұрған сияқты. Содан бергі жылдар ішінде мен ресми зерттеулерден бастап жеке жобалар туралы әңгімелерге дейін осы мәселе бойынша қол жеткізе алған кез келген дәлелге мұқият назар аудардым. Оны жоққа шығаратын ештеңе көрген жоқпын.
Мен әлі күнге дейін түпкілікті болып көрінетін дәлелдерді көрген жоқпын және көремін деп те күтпеймін. Lutz Prechelt-тің бағдарламалау тілдерін салыстыруы сияқты зерттеулер мен күткен нәтижелерді бергенімен, мәнді сынақ болу үшін тым қысқа есептерді пайдалануға бейім. Тілдің жақсырақ сынағы — жазуға бір ай кететін бағдарламаларда не болатыны. Ал жалғыз нақты сынақ, егер сіз тілдің басты мақсаты (компьютерге ойлап тапқан соң не істеу керегін айту ғана емес) ойлануға ыңғайлы болу деп мен сияқты сенсеңіз — онда қандай жаңа нәрселер жаза алатыныңыз. Сондықтан алдын ала анықталған спецификацияға сай келуіңіз керек кез келген тілді салыстыру сәл дұрыс емес нәрсені сынайды.
Тілдің шынайы сынағы — басқа біреу тұжырымдап қойған мәселені шешу үшін оны қаншалықты жақсы пайдалана алатыныңыз емес, жаңа мәселелерді қаншалықты жақсы тауып, шеше алатыныңыз. Бұл екеуі мүлдем бөлек өлшемдер. Өнерде кесте тігу және мозаика сияқты тәсілдер не жасағыңыз келетінін алдын ала білсеңіз жақсы жұмыс істейді, бірақ білмесеңіз өте нашар. Бейнені жасау барысында тапқыңыз келсе — мысалы, адам бейнесі сияқты күрделі нәрсе жасағанда солай істеуге тура келеді — қарындаш, тушь немесе майлы бояу сияқты икемдірек құралдарды пайдалануыңыз керек. Шынында да, гобелендер мен мозаикалар іс жүзінде алдымен сурет салып, содан кейін оны көшіру арқылы жасалады. («Мультфильм» [cartoon] сөзі бастапқыда осы мақсатқа арналған суретті сипаттау үшін қолданылған).
Бұл нені білдіреді: бізде ешқашан бағдарламалау тілдерінің салыстырмалы құдіреті туралы дәл салыстырулар болуы екіталай. Бізде нақты салыстырулар болады, бірақ олар шынайы дәл болмайды. Атап айтқанда, тілдерді салыстыру мақсатындағы арнайы зерттеулер, шағын есептерді пайдаланатындықтан және міндетті түрде алдын ала анықталған есептерді қолданатындықтан, неғұрлым құдіретті тілдердің күшін төмендетіп бағалауға бейім болады.
Практикадан алынған есептер «ғылыми» зерттеулерге қарағанда онша нақты болмаса да, мәндірек болуы мүмкін. Мысалы, Ericsson-нан Ulf Wiger жүргізген зерттеу Erlang тілінің C++ тіліне қарағанда 4-10 есе ықшам және бағдарламалық жасақтаманы әзірлеуге сәйкесінше тезірек екендігін анықтады:
Ericsson ішкі әзірлеу жобалары арасындағы салыстырулар бағдарламалық жасақтаманы әзірлеудің барлық кезеңдерін қоса алғанда, қай тіл (Erlang, PLEX, C, C++ немесе Java) пайдаланылғанына қарамастан, жол/сағат бойынша ұқсас өнімділікті көрсетеді. Бұл ретте әртүрлі тілдерді ерекшелендіретін нәрсе бастапқы код көлемі болып шығады.
Зерттеу сонымен қатар Brooks кітабында тек астарлы түрде айтылған мәселені нақты қарастырады (өйткені ол жөнделген код жолдарын өлшеген): құдіреттірек тілдерде жазылған бағдарламаларда қателер аз болады. Желілік коммутаторлар сияқты қолданбаларда бұл бағдарламашының өнімділігінен де маңыздырақ болуы мүмкін өз алдына бөлек мақсатқа айналады.
Талғам сынағы
Ақыр соңында, сіз өз түйсігіңізге сенуіңіз керек деп ойлаймын. Бұл тілде бағдарламалау қандай сезім тудырады? Ең жақсы тілді табудың (немесе жобалаудың) жолы — тілдің ойлануға қаншалықты мүмкіндік беретініне аса сезімтал болу, содан кейін өзіңізге ең жақсы сезілетін тілді таңдау/жобалау. Егер тілдің қандай да бір мүмкіндігі ыңғайсыз немесе шектеулі болса, алаңдамаңыз, сіз мұны бірден сезесіз.
Мұндай аса сезімталдықтың өз бағасы болады. Сіз ебедейсіз тілдерде бағдарламалауға мүлдем шыдай алмайтын боласыз. Маған макростары жоқ тілдерде бағдарламалау төзгісіз шектеулі болып көрінеді, бұл динамикалық типтеуге үйренген адамға әр айнымалының типін жариялау керек болатын және әртүрлі типтегі нысандардың тізімін жасай алмайтын тілде бағдарламалауға қайта оралу қаншалықты төзгісіз болса, дәл сондай.
Мұндай мен ғана емеспін. Мен мұны басынан өткерген көптеген Lisp хакерлерін білемін. Шын мәнінде, бағдарламалау тілдерінің салыстырмалы құдіретінің ең дәл өлшемі — қолданба саласына қарамастан, сол тілді қолдануға болатын кез келген жұмысқа келісетін осы тілді білетін адамдардың пайызы болуы мүмкін.
Шектеулілік
Менің ойымша, көптеген хакерлер тілдің шектеулі сезілуінің не екенін біледі. Сіз мұны сезінгенде не болады? Меніңше, бұл сіз барғыңыз келетін көше жабылып қалып, діттеген жеріңізге жету үшін ұзақ айналма жолмен жүруге тура келгендегі сезіммен бірдей. Сіз бірдеңе айтқыңыз келеді, бірақ тіл оған мүмкіндік бермейді.
Мұнда шынында не болып жатыр десек, менің ойымша, шектеулі тіл — жеткілікті дәрежеде ықшам емес тіл. Мәселе тек сіз ойлаған нәрсені айта алмайтындығыңызда ғана емес. Мәселе — тіл сізді мәжбүрлейтін айналма жолдың ұзағырақ болуында. Мына ойша экспериментті жасап көріңізші. Сіз жазғыңыз келетін қандай да бір бағдарлама бар делік, бірақ тіл оны жоспарлағандай білдіруге мүмкіндік бермейді, оның орнына бағдарламаны қысқарақ басқа жолмен жазуға мәжбүр етеді. Кем дегенде мен үшін бұл аса шектеулі болып сезілмес еді. Бұл сіз жүргіңіз келген көше жабылып қалып, қиылыстағы полиция қызметкері сізді айналма жолдың орнына төте жолға бағыттағаны сияқты болар еді. Керемет қой!
Менің ойымша, шектеулілік сезімінің көп бөлігі (тоқсан пайызы?) тілде жазатын бағдарламаңызды басыңыздағыдан ұзағырақ етуге мәжбүр болудан туындайды. Шектеулілік — көбінесе ықшамдылықтың жоқтығы. Сондықтан тіл шектеулі болып көрінсе, бұл (көбінесе) оның жеткілікті түрде ықшам еместігін білдіреді, ал тіл ықшам болмаса, ол шектеулі болып сезіледі.
Оқылымдылық
Мен бастаған дәйексөз басқа екі сапаны атайды: жүйелілік пен оқылымдылық. Жүйеліліктің не екенін немесе жүйелі әрі оқылатын кодтың жай ғана оқылатын кодтан қандай артықшылығы бар екенін (егер бар болса) білмеймін. Бірақ мен оқылымдылық дегеннің не екенін білемін деп ойлаймын және бұл да ықшамдылықпен байланысты деп есептеймін.
Бұл жерде кодтың жеке жолының оқылымдылығы мен бүкіл бағдарламаның оқылымдылығын мұқият ажыратып алуымыз керек. Екіншісі маңыздырақ. Basic-тің бір жолы Lisp-тің бір жолына қарағанда оқылымдырақ болуы мүмкін екенімен келісемін. Бірақ Basic тілінде жазылған бағдарлама Lisp тілінде жазылған дәл сол бағдарламаға қарағанда көп жолдан тұратын болады (әсіресе Гринспун аймағына өткенде). Basic бағдарламасын оқудың жалпы күш-жігері сөзсіз көбірек болады.
жалпы күш-жігер = бір жолға кететін күш-жігер x жолдар саны
Мен оқылымдылықтың ықшамдылыққа тікелей пропорционал екеніне құдірет сияқты сенімді емеспін, бірақ ықшамдылық оқылымдылықтың бір көбейткіші (математикалық мағынада; жоғарыдағы теңдеуді қараңыз) екені сөзсіз. Сондықтан тілдің мақсаты ықшамдылық емес, оқылымдылық деп айтудың тіпті мәні болмауы мүмкін; бұл мақсат оқылымдылық емес, оқылымдылық дегенмен бірдей болуы мүмкін.
Бір жолдың оқылымдылығы тілмен алғаш рет танысқан қолданушы үшін бастапқы кодтың қорқынышсыз көрінуін білдіреді. Сондықтан бір жолдың оқылымдылығы жаман дизайн шешімі болса да, жақсы маркетингтік шешім болуы мүмкін. Бұл адамдарға бөліп төлеуге мүмкіндік беретін өте сәтті тәсілге ұқсайды: оларды жоғары бастапқы бағамен қорқытудың орнына, сіз оларға төмен ай сайынғы төлемді айтасыз. Дегенмен, бөліп төлеу жоспарлары сатып алушы үшін таза шығын, ал бір жолдың ғана оқылымдылығы бағдарламашы үшін де дәл сондай шығар. Сатып алушы сол шағын, шағын төлемдердің көп санын жасайды; ал бағдарламашы сол жеке оқылатын жолдардың көп санын оқиды.
Бұл ымыра бағдарламалау тілдерінен бұрын пайда болған. Егер сіз романдар мен газет мақалаларын оқуға үйренген болсаңыз, математикалық мақаланы алғаш оқу тәжірибеңіз көңілсіз болуы мүмкін. Бір бетті оқуға жарты сағат кетуі мүмкін. Соған қарамастан, белгілеу жүйесі мәселе емес екеніне мен толық сенімдімін, бірақ солай көрінуі мүмкін. Математикалық мақаланы оқу қиын, өйткені идеялар күрделі. Егер сіз дәл осы идеяларды қарапайым сөзбен жеткізсеңіз (математиктер ықшам белгілеулерді дамытқанға дейін солай істеуге мәжбүр болғандай), оларды оқу оңайырақ болмас еді, өйткені мақала кітаптың көлеміне дейін ұлғайып кетер еді.
Қай дәрежеге дейін?
Көптеген адамдар ықшамдылық = құдірет деген идеяны қабылдамады. Менің ойымша, олар бірдей ме, жоқ па деп жай ғана дауласудың орнына: ықшамдылық қай дәрежеге дейін = құдірет деп сұраған пайдалырақ болар еді? Себебі ықшамдылық жоғары деңгейлі тілдердің қызметінің үлкен бөлігі екені анық. Егер бұл олардың жалғыз мақсаты болмаса, онда олар тағы не үшін қажет және бұл басқа функциялар салыстырмалы түрде қаншалықты маңызды?
Мен мұны пікірталасты тек өркениетті ету үшін ғана ұсынып отырған жоқпын. Мен шынымен жауабын білгім келеді. Тіл қашан, егер мүмкін болса, өзіне зиян тигізетіндей тым ықшам болады?
Мен бастаған гипотеза бойынша, патологиялық мысалдарды қоспағанда, ықшамдылықты құдіретпен бірдей деп санауға болады деп ойладым. Менің айтқым келгені, кез келген адам жобалайтын кез келген тілде олар бірдей болар еді, бірақ егер біреу осы гипотезаны теріске шығару үшін арнайы тіл жасағысы келсе, олар мұны істей алар еді. Шынымды айтсам, мен тіпті бұған да сенімді емеспін.
Бағдарламалар емес, тілдер
Біз жекелеген бағдарламалардың емес, тілдердің ықшамдылығы туралы айтып отырғанымызды нақты түсінуіміз керек. Әрине, жеке бағдарламалар тым тығыз жазылуы мүмкін.
Мен бұл туралы On Lisp кітабында жазғанмын. Күрделі макрос өзін ақтау үшін өз ұзындығынан бірнеше есе үнемдеуі керек болуы мүмкін. Егер қандай да бір күрделі макросты жазу оны әр қолданған сайын сізге он жол код үнемдесе, ал макростың өзі он жол кодтан тұрса, онда оны бірнеше рет пайдалансаңыз, жолдар бойынша таза үнемдеу аласыз. Бірақ бұл бәрібір жаман шешім болуы мүмкін, өйткені макрос анықтамаларын оқу қарапайым кодқа қарағанда қиынырақ. Макрос оқылымдылықтың таза жақсаруын қамтамасыз ету үшін оны он немесе жиырма рет пайдалануыңыз қажет болуы мүмкін.
Әрбір тілде осындай ымыралар бар екеніне сенімдімін (бірақ тіл құдіретті болған сайын бәс те көтеріледі деп күдіктенемін). Әрбір бағдарламашы қайсыбір зерек адам күмәнді бағдарламалау айлаларын қолданып, шамалы ғана қысқартқан кодты көрген болуы керек.
Сондықтан бұл туралы ешқандай дау жоқ — кем дегенде, мен тараптан. Жекелеген бағдарламалар өздеріне зиян тигізетіндей тым ықшам болуы әбден мүмкін. Сұрақ мынада: тіл сондай бола ала ма? Тіл бағдарламашыларды жалпы оқылымдылыққа нұқсан келтіре отырып, (элементтері бойынша) қысқа код жазуға мәжбүрлей ала ма?
Тілдің тым ықшам болуын елестетудің қиын болуының бір себебі — егер бірдеңені білдірудің тым ықшам тәсілі болса, онда оның ұзағырақ тәсілі де болуы мүмкін. Мысалы, егер көптеген макростарды немесе жоғары ретті функцияларды қолданатын Lisp бағдарламалары тым тығыз деп тапсаңыз, қаласаңыз, Pascal-ға изоморфты код жаза аласыз. Егер Arc тілінде факториалды жоғары ретті функцияны шақыру ретінде білдіргіңіз келмесе (rec zero 1 * 1-), рекурсивті анықтаманы да жаза аласыз: (rfn fact (x) (if (zero x) 1 (* x (fact (1- x))))) Қазір ойыма бірден ешқандай мысал келмесе де, тілдің тым ықшам болуы мүмкін бе деген сұрақ мені қызықтырады. Кодты түсініксіз және қисынсыз етіп жазуға мәжбүрлейтін тілдер бар ма? Егер біреуде мысалдар болса, мен оларды көруге өте қызығар едім.
(Ескерту: Менің іздеп отырғаным — бөлгіштерді алып тастауға болатындықтан және барлық нәрсе бір таңбалы атауға ие болғандықтан қысқа болатын бағдарламалар емес, жоғарыда сипатталған «элементтер» метрикасы бойынша өте тығыз бағдарламалар).