Scenoje vėl Redmondo rastamanai. Šįkart jų čempionai, Windows Installer komanda.
Citata iš dokumentacijos (apie reliacinės bazės stulpelį):
===============================================================
Display (type Integer)
----------------------
The number in this field specifies the order in which the
feature is to be displayed in the user interface.
The value also determines whether or not the feature is
initially displayed expanded or collapsed. If the value is null
or 0 (zero), the record is not displayed.
* If the value is odd, the feature node is expanded initially.
* If the value is even, the feature node is collapsed initially.
===============================================================
(http://msdn.microsoft.com/en-us/library/aa368585(VS.85).aspx)
Gražu, ar ne? Ėmė ir sukišo nesusijusius parametrus į vieną skaičių. Matyt, taupo baitus. Windows Installeryje. Ha ha!
Bet čia nieko. Sunku patikėti, bet tai yra gėlytės, lyginant su tikru perlu. Toliau kalba eina apie kitą lentelę, Signature, su kurios pagalba galima sistemoje ieškoti, ar yra jums reikalingas failas. Pvz., ar yra .NET'as ir kokia jo versija. Viskas puiku, viskas faina. Bet štai padarai, ir neveikia. Tada žiūri kodėl ir randi šitokį siurprizą (skaitykit atidžiai):
===============================================================
Languages (type Text)
---------------------
The languages supported by the file.
MinVersion (type Text)
----------------------
The minimum version of the file, with a language comparison.
If this field is specified, then the file must have a version
that is at least equal to MinVersion. If the file has an equal
version to the MinVersion field value but the language specified
in the Languages column differs, the file does not satisfy the
signature filter criteria.
Note: The language specified in the Languages column is used
in the comparison and there is no way to ignore language. If you
want a file to meet the MinVersion field requirement regardless
of language, you must enter a value in the MinVersion field that
is one less than the actual value. For example, if the minimum
version for the filter is 2.0.2600.1183, use 2.0.2600.1182 to find
the file without matching the language information.
===============================================================
(http://msdn.microsoft.com/en-us/library/aa371853(VS.85).aspx)
Дорогая редакция, я фалломорфируюсь. Mėgstu sakyti, kad aš irgi noriu tokios žolės, bet šiuo atveju, tai nu ir nafig, tokio šūdo aš nerūkysiu.
Neapsiimsiu aiškinti kas čia negerai. Kad apsakyti tai žodžiais, reikia būti poetu. Ir dar, ko gero, rašyti klasikine kalba ir hegzametru. Na, jūs suprantat kur lenkiu.
Jeigu kažkam iš skaitytojų neprogramuotojų neaišku apie ką aš čia, patikėkite mano žodžiu, tai tas retas atvejis, kai palaimintas tas, kuris sėdi ir karpo ausimis nieko nesuprasdamas. Tikrai. Žmogų, be daugelio metų dvasinių treniruočių, staiga suvokusį šito kretinizmo mastą, gali ištikti nihilizmo priepuolis.
O programuotojams tema pamąstymui: jeigu komanda, kuri daro vieną iš core OS komponentų, sugeba paleisti į productioną šitokį kolosalaus masto mėšlą, ką galima manyti apie bendrą to komponento kokybę? Ar galima daryti prielaidą, kad kiti, į proto ribas telpantys, to komponento aspektai, yra geresni tyčia, ar taip gavosi nesąmoningai? Ir svarbiausia, kaip jaustis vartotojui, kuriam pateikiamas softas yra pošlykštis dėl to, kad pastatytas ant mėšlo krūvos, kuriai nepateikiama alternatyva?
Mieli kolegos, susimildami, būkit geri, nevartokite darbe svaigalų...
Vakar darbe pabaigiau vieną darbelį ir prieš dėdamas jį į revizijų kontrolę, nusprendžiau pabūti doras ir padaryti tai, ką mes vadinam TMR: Total Massive Rebuild. Tai veiksmas, kai perkompiliuoji visai visą produktą, kad įsitikinti, kad niekam nieko nesugadinai.
Nu cvs up, nu make clean, nu make all. Įprasti dalykai. Kompiliuojasi.
Tik kompiliuojasi neilgai, sustoja, nes sugriūna kažkuris unit testas. Galvoju, WTF? Bet aiškintis neturėjau laiko, tai užsiėmiau tuo šiandien.
Gana greitai išsiaiškinu kodėl griūna testas -- kolega neseniai padarė pakeitimą, visai gerą pakeitimą, dėl kurio šita problema ir turi išlįsti, o ne tyliai likti praignoruota. Viskas lyg ir tvarkoj. Bet vienas dalykas netvarkoj -- o kodėl *man* išlenda šita klaida, o kitiems ne?
Padebuginus paaiškėja, kad nesuveikia štai toks kodas:
mkdir ("%TEMP%/sub1/sub2/sub3/.../sub28/sub29");
(Tik vietoj %TEMP% ten buvo tikras kelias į temp direktoriją: C:\Users\Vytautas.Saltenis\AppData\Ir\Dar\Kažkas\Nepamenu\Kas\. Nu ir, aišku, vietoj daugtaškio visi trūkstami sub-sub-sub.)
Įtarimas aiškus -- kažkodėl viršija MAX_PATH. Betgi nusikopijuojam tą eilutę, pamatuojam jos ilgį ir matom, kad ne, neviršija. Jos ilgis 248. Va šitoj vietoj prasideda kondicija "O-ba...".
Pirma mintis: gal aš neteisingai atsimenu kiek yra MAX_PATH? Pasitikrinu, 260. Reiškia teisingai, ne tas...
Tada tikrinam klaidos kodą. errno po mkdir() būna 2, kas yra ENOENT, ką dokumentacija iškilmingai išaiškina: "Path was not found.". Blet. Koks dar not found? Aš gi sukurti bandau!
Gūglinam kaip ant Vindauso padarytas mkdir(). Randam, kad ten jis yra plonas wrapperis ant CreateDirectory() -- "gerai bent tiek, o ne atskira realizacija", spėju pagalvoti.
OK, tad kaipgi galima priversti CreateDirectory() nesuveikti? Ten yra kažkoks antras parametras, kažkas su security, gal ten kažkas ne taip? Nu, debuginam visaip kaip išsijuosę, ir žiūrim, kad mkdir() padarytas maždaug va taip:
int mkdir (char *path)
{
return CreateDirectory (path, NULL);
}
Blyn. Nu irgi nėra kam nesuveikti... Nebent tas NULL 20 metų veikė, o dabar neveikia. Vėjai.
Bet čia eiga pasisuka link atomazgos, prieinama prie CreateDirectory() dokumentacijos. Paskaitom prierašą prie pirmo parametro, ir liekam "в охуе":
"There is a default string size limit for paths of 248 characters. This limit is related to how the CreateDirectory function parses paths."
Bingo! Pasirodo, visgi susidūriau su limitu, pasiaiškinam kodėl kiti nesusidūrė, pataisom ir ilgai ir laimingai gyvenam. Boring.
The *fun* part! Kuo galvojo tas senovinis Microsoft darbuotojas, kuris parašė CreateDirectory()? Ar jis išvis galvojo? Ne, nu rimtai. Gaunasi taip: mūsų sistemoje apribojimas kelio ilgiui yra 260, bet aš chujovas programuotojas, dėl to nemoku suprogramuoti taip, kad būčiau suderinamas su likusia sistema ir padarysiu 248 ir dokumentacijoje parašysiu, kad aš chujovas programuotojas. Rimtai, taip išeina. Paskaitykit dar kartą citatą iš dokumentacijos:
"There is a default string size limit for paths of 248 characters. This limit is related to how impaired was the original author of CreateDirectory."
Pakalbam apie tai su kolegomis, pažvengiam, aptariam, paspėliojam kodėl 248, o ne 246, kodėl išvis yra toks MAX_PATH ir kodėl jis 260, o ne 256 ir pan... Linksmiausia išsakyta versija tokia: o nefig tau kurti direktorijos, į kurią paskui netilps 8.3 failas! Dėl to ir MAX_PATH - 12 = 248. Skamba įtikinamai ;-)
Akylesni skaitytojai gal pastebėjo ir iki šiol nesupranta kodėl gi man neveikė? Juk mano kelio ilgis buvo 248, ir funkcija priima 248. Turi veikti. Cha cha! Nieko jūs nesuprantat! Chujovą funkciją reikia ne tik chujovai suprogramuoti, ją paskui dar reikia ir chujovai dokumentuoti! Kitaip gausis tik pusiau chujova funkcija. Iš tikro jinai veikia su keliais iki 247 simbolių ilgio imtinai, o dokumentatorius parašė kokio dydžio buferis ten viduje naudojamas keliui kartu su terminuojančiu nuliu laikyti.
Atrodytų, tokia vat nuotaikinga istorija. Ir maniau, kad toliau jau nėra kur, kad čia viršūnė. Nope, naivu. Betvarkydamas mūsų kodą, užklydau į kitos įdomios funkcijos GetTempFileName() dokumentaciją. Skaitom pirmo parametro aprašymą:
"The directory path for the file name. [...] The string cannot be longer than MAX_PATH–14 characters or GetTempFileName will fail. If this parameter is NULL, the function fails."
Uch ty! Štai jums ir 246! Man dabar baisu į gūglą įvesti "MAX_PATH - 17", bijau, kad ką nors suras :-)
Beje, plika akim tai sunkiai įžiūrima, bet ten dokumentacijoj parašyta ne "MAX_PATH-14". Rimtai, nejuokauju. Ten ne minusas, ten tipografinis brūkšnys, "En dash" vadinasi. Ir jeigu nukopijuosi tą daiktą į kodą, gausi keistų pranešimų nuo kompiliatoriaus, versijų kontrolės sistemos ir kitų "suinteresuotų šalių".
Va taip vat. Pyzdėc, gerbiamieji Redmondo programuotojai. Pyz-dėc.
(Dear googler, if you come here from a search engine and are disappointed seeing this weird language and are looking for information on Vim and Doxygen, don't run away. There's an English version of this article.)
Kartą darbe įvyko didis džiaugsmas: numigravom mūsų SDK dokumentaciją į Doxygen. Ne, neklauskit iš ko mes migravom, tuo labiau neklauskit iš ko aš ją numigravau prieš 4 metus -- nenoriu gėdinti savo darbovietės :-)
Taigi, dokumentacija jau įgavusi labiausiai jai tinkamą pavidalą ir visi puola tvarkyti neišvengiamas kliurkas, kurios atsiranda po migravimo. Pamaniau, puiki proga prasukti tekstą pro rašybos tikrinimo įrankius, ko gero, pirmą kartą to teksto istorijoje. Bet bėda! False positives...
Pažiūrėkit patys (vaizdas pasididina):
Vim yra pakankamai protingas, kad netikrintų rašybos kode, tik komentaruose. Bet raktiniai Doxygen'o žodžiai bei nuorodos į kintamuosius, funkcijas ir konstantas taip pat duoda false positives.
Truputį pagooglinau ir radau, kad Vim moka suprasti Doxygen'ą, tik pagal nutylėjimą tai nėra įjungta:
Valio, raktiniai žodžiai ir parametrų vardai jau nebetrukdo! Bet nuorodos į vidines/išorines API funkcijas bei kryžminės nuorodos... Teko padirbėti. Truputį palaksčius ratais, pašokus šamaniškus šokius bei pamušus būgnelį, pavyko pasiekti štai tokį vaizdą:
Vietoj pradinių dešimties raportuotų rašybos klaidų, viena. Tas vienintelis tikras mistaipas, visi kiti 9 buvo false positives.
Techninių detalių čia nekartosiu, jas, kartu su reikiamais kodo pavyzdžiais rasite čia.
O ar jūsų mėgstamas redaktorius taip gali? ;-)
Šis rašinys yra labai techniškas ir mokslo populiarinimo prasme moksliškas. Programuotojams rekomenduoju jį perskaityti dėl abiejų priežasčių, visiems kitiems rekomenduoju neišsigąsti pirmosios ir perskaityti bent jau dėl antrosios.
Kažkada „seniai seniai“, viename forume įvyko įdomi keisto reiškinio analizė. Reiškinys: neįtikėtinai didelė skaičiavimo paklaida, atliekant trivialius skaičiavimus su slankiojo kablelio skaičiais. Šiaip jau tiek reiškinys, tiek kapstymo procesas gana nuobodūs, o tiems, kam tenka darbo reikalais su juo susidurti, tai dar ir labai skaudi tema.
Ir visgi visus tuos metus ta analizė mane kažkuo žavėjo. Kelis kartus perskaičiau forumo giją iš naujo, ir tik neseniai supratau kas gi ten tokio svarbaus. Ogi svarbu tai, kad ta analizė yra puiki iliustracija iškart keliems dalykams:
Paskutiniam punktui tai, ko gero, ne toks jau chrestomatinis pavyzdys, kaip pirmiems dviems, bet visgi.
Taigi, problematika. Vienas jaunuolis ėmė ir paklausė kodėl 1020 kartų prie nulio pridedant po 0.1 gaunama ne 102, kaip kad norisi tikėtis, o 101.99901580810547, jei dirbama su float ir 102.00000151991844, jei dirbama su double. Paklaida tikrai neįtikėtinai didelė.
Kitas kolega jam paantrino, papasakodamas baisesnių atvejų:
------------------------------------------------------
double stat = count_wins () / count_loses ();
if (stat != count_wins () / count_loses ())
// sąlyga _niekada_ neturėtų būti tenkinama, bet...
------------------------------------------------------
beigi:
------------------------------------------------------
if (a + b + c != a + c + b)
// sąlyga _niekada_ neturėtų būti tenkinama, bet...
------------------------------------------------------
Daugiau nevarginsiu, štai kodas, kuris išgavo aukščiau minėtas paklaidas (kodas minimaliai paredaguotas, išlaikant esmę, bet patrumpinant):
------------------------------------------------------
1: float f = 0.0f;
2: double d = 0.0f;
3:
4: for (int i = 1020; --i; )
5: {
6: f += 0.1f;
7: d += 0.1f;
8: }
9: printf ("\n %.20f \t %.20f\n", f, d);
------------------------------------------------------
Patyręs C programuotojas iškart pamatys, kad čia triskart pasikartoja viena ir ta pati klaida: neteisingai naudojamasi double tipu.
Antroje ir septintoje eilutėse nepridera naudoti literalo 0.1f. Mat skaičius su kableliu C kalboje automatiškai traktuojamas kaip double tipo. Tuo tarpu postfiksas 'f' reikalingas tam, kad jis būtų traktuojamas kaip float. Koks iš to skirtumas išsiaiškinsim mažumėlę vėliau, o kol kas trečia tos pačios klaidos apraiška.
Devintoje eilutėje taip pat neteisingai nurodomas antro kintamojo tipas formate: %.20f reiškia, kad parametras yra float tipo, ir spausdinti jį reikia iki 20-ies skaitmenų po kablelio tikslumu. Bet juk kintamasis yra double tipo! Taip ir reikia nurodyti: %.20lf.
Naudojant float tipą, klaidų neprivelta, bet kadangi float yra ženkliai mažesnio tikslumo, paklaida didesnė.
Dviem raidelėm per daug, ir viena per mažai. Ir dar tokios „neesminės“... Kokią tai gali turėti įtaką tikslumui? Štai, originalių skaičiavimų paklaida nuo norimo rezultato:
102.00000151991844000000 / 102 =
= 1.0000000149011611764705882352941 (7 nuliai po kablelio)
O štai rezultatas ir jo paklaida ištaisius klaidas:
101.99999999999848000000 / 102 =
= 0.99999999999998509803921568627451 (13 devynetų po kablelio)
Pataisykit mane, jei klystu, bet mano skaičiavimais, milijoną kartų tiksliau.
Labai įdomu pasiaiškinti koks gi tiksliai gaunasi skirtumas skaičiavimuose, naudojant šiek-tiek-ne-visiškai-bet-visgi-nevisai suderinamus tipus. Būtinai tai padarysim, kad pamatytume kiek daug visko sumuojasi į bet kurios programos galutinį sudėtingumą. Bet pradžioj atlikim mokslinį eksperimentą.
Kaip ir daugelį mokslinių eksperimentų, šį sufleruoja ne specialistui netikėtas, bet patirties diktuojamas smalsumas: kas, jeigu šią trumpą, paprastą programą, sukompiliuosime su optimizacijomis?
Kam? Tuoj paaiškinsiu, pradžiai pažiūrėkim, kas gavosi.
Originalių skaičiavimų su float paklaida (prisiminkite, jokios klaidos ten nebuvo, paklaidą sąlygojo iš prigimties mažas float tipo tikslumas):
101.99901580810547000000 / 102 =
= 0.99999035105985754901960784313725 (5 devynetai po kablelio)
Optimizuotų skaičiavimų su float paklaida:
102.00000182539225000000 / 102 =
= 1.0000000178960024509803921568627 (7 nuliai po kablelio)
Ir pagaliau optimizuotų skaičiavimų su double paklaida:
102.00000000000000000000 / 102 =
= skaičiuokit patys ;-)
Kas įvyko? Kodėl vien tik optimizavimo įjungimas 100x sumažino paklaidą, susikaupiančią float kintamajame? Kodėl double kintamojo tikslumas šoktelėjo iki palubių, kokių, regis, jau ir nebesitikėjome?
Žinantis žmogus iškart paaiškintų, bet aš apsimesiu, kad nežinau ir parodysiu kaip sužinojau. Kad suprasti kokį skirtumą sukėlė optimizacijos, reikia žiūrėti, ką konkrečiai kompiliatorius iškrėtė vienu ir kitu atveju iš identiško išeities kodo.
(Keletas pastraipų N-14, nagrinėsim asemblerį :-))
Neoptimizuotas kodas (smarkiai apkastruotas, kad liktų tik esmė):
------------------------------------------------------
LC1:
.long 1036831949 // (float) 0.1f
LC2:
.long -1717986918 // (double) 0.1 (apatiniai 4 baitai iš 8)
.long 1069128089 // (double) 0.1 (viršutiniai 4 baitai iš 8)
// ...
// Ciklas:
movl $1020, -4(%ebp) // "for (i = 1020;"
L6:
leal -4(%ebp), %eax // eax = 1020
decl (%eax) // sumažinam i vienetu
cmpl $-1, -4(%ebp) // ar i >= 0?
jne L9 // jei taip, vykdom ciklą
jmp L7 // jei ne, ciklą baigiam ir spausdinam
L9:
flds -8(%ebp) // parsiunčiam iš atminties kintamąjį f
flds LC1 // parsiunčiam iš atminties 0.1f
faddp %st, %st(1) // sudedam juos
fstps -8(%ebp) // dedam rezultatą atgal į atmintį
fldl -16(%ebp) // parsiunčiam iš atminties kintamąjį d
fldl LC2 // parsiunčiam iš atminties 0.1
faddp %st, %st(1) // sudedam juos
fstpl -16(%ebp) // dedam rezultatą atgal į atmintį
jmp L6 // grįžtam prie ciklo sąlygos
L7:
// čia, jau po ciklo, spausdinami rezultatai
------------------------------------------------------
O štai optimizuotas:
------------------------------------------------------
LC3:
.long 1036831949 // (float) 0.1f
LC4:
.long -1717986918 // (double) 0.1 (apatiniai 4 baitai iš 8)
.long 1069128089 // (double) 0.1 (viršutiniai 4 baitai iš 8)
// ...
// Ciklas:
movl $1019, %ebx // for (i = 1020
// ties čia, st(0) registre yra kintamasis d,
// o st(1) registre -- kintamasis f. Ciklas dar neprasidėjo
L11:
fxch %st(1) // sukeičiam reikšmes tarp st(0) ir st(1)
decl %ebx // sumažinam i vienetu
fadds LC3 // pridedam 1.0f prie st(0) (t.y. f)
fxch %st(1) // sukeičiam reikšmes tarp st(0) ir st(1)
faddl LC4 // pridedam 1.0 prie st(0) (t.y. d)
cmpl $-1, %ebx // ar i >= 0?
jne L11 // jei taip, tęsiam ciklą
// čia, jau po ciklo, spausdinami rezultatai
------------------------------------------------------
Įgudę pastebės greitai, neįgudę tik labai pasigilinę, bet visgi matosi vienas esminis skirtumas: neoptimizuota versija cikle nuolat siunčia duomenis iš kintamojo atmintyje į FPU (slankiojo kablelio skaičiavimų koprocesorių), sumuoja ir siunčia atgal į atmintį. Tuo tarpu optimizuota versija vieną kartą prieš ciklą sukiša duomenis į FPU registrų steką, ir visą ciklą „neišleidžia“ skaičių iš FPU.
Taigi, padarėm eksperimentą: pažiūrėjom kas vyksta, jei suoptimizuojam. Rezultatas: tikslumas ženkliai didėja. Paanalizavom eksperimento duomenis, matom skirtumus. Iškelkime hipotezę:
O gal FPU viduje visi skaičiavimai atliekami didesniu tikslumu, ir tik tam, kad tilptų į reikiamo dydžio kintamuosius atmintyje, jų tikslumas mažinamas?
Tikrinam hipotezę, ir štai ką turim:
„However, x87 does not perform operations according to strict IEEE-754 formats, since it uses wide registers internally“.
(IEEE-754 yra standartas, apibrėžiantis slankiojo kablelio skaičius technikoje. Ir jeigu būti visai tiksliems, tai modernūs x87-ieji FPU pagal nutylėjimą viduje atlieka skaičiavimus 80 bitų tikslumu (long double), bet tą galima pakeisti per FPU kontrolinius registrus).
Hipotezė pasitvirtino. Atkreipkime dėmesį, kad hipotezė buvo itin sėkminga: ji ne tik paaiškino eksperimento rezultatus, bet ir paaiškino anksčiau empiriškai pataisytas klaidas originaliam kode; paaiškino kodėl naudojant „beveik suderinamus“ kintamojo ir literalo tipus, paklaida būdavo didesnė, bei kaip gali nutikti a + b + c != a + c + b ir panašios „neįmanomybės“.
O dabar pabandykime šią hipotezę išplėsti būsimiems rezultatams: kas, jeigu optimizuotą kodą dar šiek tiek pajudinsime rankomis ir padarysime, kad cikle prie float tipo kintamojo (kuris, kaip jau žinome, visai ne float, kol FPU viduje) sumuosime ne mažo tikslumo 0.1f, o didelio tikslumo 0.1? Štai šiek tiek pakeistas kodas, kur skiriasi vos viena eilutė -- naudojamas tikslesnis literalas, bei jo dydį atitinkanti instrukcija:
------------------------------------------------------
// kaip ir anksčiau, st(0) registre jau yra kintamasis d,
// o st(1) registre -- kintamasis f
L11:
fxch %st(1)
decl %ebx
// skirtumas tik šioje eilutėje: faddl vietoj fadds,
// LC4 (kuris rodo į 0.1) vietoj LC3 (kuris rodo į 0.1f)
faddl LC4
fxch %st(1)
faddl LC4
cmpl $-1, %ebx
jne L11
------------------------------------------------------
Dabar jau nenuostabu, kad rezultatai štai tokie:
float: double:
102.00000000000000000000 102.00000000000000000000
Matome, kad visus skaičiavimus atlikus didesniu tikslumu, atsakymas suskaičiuojamas be paklaidos. Tai, be abejo, yra tam tikra apgaulė, nes procesoriaus viduje skaičiavimai buvo atliekami didesniu tikslumu, nei nurodyta C kalboje, bet siekiant rezultato, nulinė paklaida yra lemiamas kriterijus.
Na ir pabaigai, iš kur išvis, net teoriškai gali rastis netikslumai, atliekant tokius trivialius skaičiavimus su tokiais paprastais skaičiais. Čia juk ne kokia nors šaknis iš trijų?
Ogi netikslumai atsiranda iš to, kad 0.1 ir sqrt(3) dvejetainiam pavidale yra vienodai neparankūs skaičiai:
------------------------------------------------------
IEEE-754 single precision floating-point:
0.1f: 0-01111011-10011001100110011001101
sqrtf (3): 0-01111111-10111011011001111010111
------------------------------------------------------
Šis, paskutinis, pavyzdys, viso rašinio kontekste, turėtų paaiškinti tiems, kas dar nesuprato, kam universitete reikėjo klausyti viso to „beprasmio ir nenaudingo“ Mitašiūno kurso ;-)
Programavimas iš prigimties sudėtingas užsiėmimas, ir štai jums buvo pavyzdys. Tokias klaidas galima išgauti programuojant bet kuria kalba. Ar tai būtų Java, ar C#, ar Lisp, ar bet kuri kita kalba. Ir kaip matėte, tam, kad atkapstyti visus niuansus, reikėjo ir asemblerio žinių, ir šiek tiek procesorių architektūros, ir transliatorių bent minimaliai pažinoti.
Ačiū už dėmesius. Ypač tiems, kas ištvėrė šitą technomaninę kankynę iki galo :-)
Originali gija forume: http://gamedev.lt/viewtopic.php?f=18&t=297
Pirmoji šio serialo serija čia, antroji čia.
"O mein Gott! Kas čia per klausimas! Kaip gi galima programuoti be debugerio?!"
Bla bla. Ne apie programavimą kalbam. O apie vidurinę mokyklą. Ten niekas neprogramuoja, ten žmonės mokosi. Mokosi rašyti paprastas programas. Jas rašo ir skaito tik autoriai ir mokytojai. Jos yra tuoj pat išmetamos. Jos yra mažos.
Nematau kaip debugeris čia galėtų padaryti juntamą įtaką. Ypač jeigu vaikams yra paaiškinami kiti būdai ieškoti klaidų, iš kurių svarbiausias -- introspekcinis print.
Dar vienas akmuo į debugerio daržą -- vėl, interpretatorius. Kai kas nors negero įvyksta su interpretuojama programa, padorus interpretatorius parodys ir steką, ir kintamųjų reikšmes. O tai yra du trečdaliai to, ką aš, profesionalas, pirmiausiai noriu matyti, kai įsijungiu debugerį. Kam moksleiviui daugiau?
Taigi, debugeris lemiamos rolės negroja.
Mane labai stebina kai kurių žmonių fobija dinamiškai tipizuotoms kalboms ir jų taikymui mokykloje. Žmonės sugeba pareikšti, kad vaikas gali pradėti painioti kur 3, o kur "3". Arba, dar geriau, paporina, kad statiškai tipizuotose kalbose, atsiprašant, "anksčiau" sužinoma apie vienokį ar kitokį tipų nesuderinamumą.
Nėra skirtumo!
Kai EuroPython'2007 Guido pasakė, kad Python 3000 bus galima kintamuosius vadinti bet kuria kalba, vieni žmonės sutiko šią žinią aplodismentais, kiti šaltai. Aš buvau prie pastarųjų. Dėl to, kad šia tema mane drasko dvejonės.
Viena vertus, akivaizdu, kad iš šių trijų eilučių pirma yra gražiausia:
sąrašas = [1, 2, 3] # (1) sarasas = [1, 2, 3] # (2) listas = [1, 2, 3] # (3)
Kita vertus, neseniai parsisiunčiau vienos atvirojo kodo programos išeities tekstus. Išpakavau, pažiūrėjau į failus, vienas iš jų buvo pavadintas vokiškai. Pakvipo negeruoju. Netruko išaiškėti, kad kode esama angliškai pavadintų kintamųjų, esama ir vokiškai. Kai kurie komentarai angliški, kai kurie vokiški.
Nepaisant to, kad projektas mane iš principo domina, tokios betvarkės per akis pakanka, kad aš prie jo neprisiliesčiau. Ir neprisiliesiu.
Žiūrint toliau, kas jeigu tokia pati betvarkė komercinės įmonės kode? Ar norėtųsi dirbti tokioje kontoroje prie tokio kodo? Man ne.
Todėl aš atsargiai žiūriu į moksleivių skatinimą rašyti lietuvišką kodą. Vienas dalykas yra to nedrausti (juk transliatoriui vienodai šviečia, ar kintamasis pavadintas sarasas, ar list, ar x), o kitas dalykas skatinti. Juk paskui teks perauklėti!
Žinoma, mano nuogąstavimus pagrindžia tik tie moksleiviai, kurie vėliau taps programuotojais ir juos reikės atpratinti nuo mokykloje įgytų blogų įpročių. Tuo tarpu didžiąjai daliai moksleivių -- tai, kuriai programavimo pamokos bus tik susipažinimas, lietuvybės įvedimas tik palengvins supratimą, sumažins atgrasumą.
Tiesą pasakius, nežinau...
Manau, šitas punktas nekvescionuojamas. Apie jį papildomai rašyti būtų laiko švaistymas, prirašyta jau tiek ir šitiek. Pakaks paminėti, kad tai turi tokią pat svarbą, kaip ir kalbos komerciškumas. Kalbos realizacija turi būti pasiekiama bent keliose populiariose platformose, būtinai bent vienoje nemokamoje. Kad nekainuotų ir nekvaršintų galvos.
O jeigu kas turite argumentų prieš, pateikite juos šitam vaikui: "mano tėtė alchitektaš, il paš muš namuoše tik Mašintokai; Tulbo Paškališ nedilba" ;-)
Neprisirišimas būtinas. Ir į jį reikia atkreipti daug dėmesio.
Rytoj baigiam.