რამდენიმე დღის წინ ბათუმში გამართულ კონფერენციაზე ფურიო ჰონსელს გავესაუბრე. ფურიო ერთ-ერთი ყველაზე საინტერესო ადამიანია, ვისაც კი ოდესმე შევხვედრივარ. გამიმართლა, რომ ჩემს საბაკალავრო ნაშრომსაც ის ხელმძღვანელობდა.
მას ქართული კულტურა აინტერესებს და ხშირად მეკითხება მის შესახებ. რადგან მათემატიკოსია, საუბარი ხშირად მათემატიკურ ჭრილში გადადის. მეც სიამოვნებით ვეძებ ქართულ კულტურასა და ენაში პატარა, მოულოდნელ დეტალებს, რომლებიც შემიძლია მას გავუზიარო.
იმ საღამოს ვფიქრობდი, კიდევ რა საინტერესო მაგალითი გამეზიარებინა მისთვის, როცა ჩემმა შეყვარებულმა ქართული ხალხური ზღაპარი „რწყილი და ჭიანჭველა“ გამახსენა. ამბავი მოკლეა, ამიტომ აქვე შევაჯამებ.
თუ პროგრამისტი ხართ, ალბათ უკვე მიხვდით, საით მიმყავს ეს ამბავი.
თხოვნათა ეს ჯაჭვი ძალიან ჰგავს პროგრამაში ფუნქციების გამოძახების სტეკს (Call Stack). თითოეულ პერსონაჟს რაღაც აქვს გასაკეთებელი, მაგრამ საქმეს ჯერ ვერ ასრულებს, ამიტომ დახმარებას სხვას სთხოვს და პასუხს ელოდება.
ფუნქციის გამოძახების დროსაც იგივე ხდება. როცა ერთი ფუნქცია მეორეს იძახებს, პირველი დროებით ჩერდება, სტეკს კი ახალი ჩარჩო (Stack Frame) ემატება. ასე გრძელდება, სანამ ბოლოს გამოძახებული ფუნქცია შედეგს არ დააბრუნებს. შემდეგ სტეკი თანდათან, საპირისპირო რიგით იცლება: ყოველი ფუნქცია თავის საქმეს ასრულებს და მართვას გამომძახებელ ფუნქციას უბრუნებს.
ინტერაქტიული ახსნა
თვალი მივადევნოთ გამოძახების სტეკს
ნაბიჯებს შორის გადასასვლელად გამოიყენეთ ღილაკები, ეკრანზე თითი გადაუსვით ან კლავიატურის მარცხენა და მარჯვენა ისრებს დააჭირეთ.
Our Story მუშაობს Our Story ელოდება antFalls() მუშაობს Our Story ელოდება antFalls() ელოდება rescueAnt() მუშაობს Our Story ელოდება antFalls() ელოდება rescueAnt() ელოდება makeRope() მუშაობს Our Story ელოდება antFalls() ელოდება rescueAnt() ელოდება makeRope() ელოდება getBristle() მუშაობს Our Story ელოდება antFalls() ელოდება rescueAnt() ელოდება makeRope() ელოდება getBristle() ელოდება getAcorn() მუშაობს Our Story ელოდება antFalls() ელოდება rescueAnt() ელოდება makeRope() ელოდება getBristle() ელოდება getAcorn() ელოდება moveCrow() მუშაობს Our Story ელოდება antFalls() ელოდება rescueAnt() ელოდება makeRope() ელოდება getBristle() ელოდება getAcorn() ელოდება moveCrow() ელოდება getChick() მუშაობს Our Story ელოდება antFalls() ელოდება rescueAnt() ელოდება makeRope() ელოდება getBristle() ელოდება getAcorn() ელოდება moveCrow() ელოდება getChick() ელოდება getMillet() მუშაობს Our Story ელოდება antFalls() ელოდება rescueAnt() ელოდება makeRope() ელოდება getBristle() ელოდება getAcorn() ელოდება moveCrow() ელოდება getChick() ელოდება getMillet() ელოდება moveMouse() მუშაობს Our Story ელოდება antFalls() ელოდება rescueAnt() ელოდება makeRope() ელოდება getBristle() ელოდება getAcorn() ელოდება moveCrow() ელოდება getChick() ელოდება getMillet() ელოდება moveMouse() ელოდება getMilk() მუშაობს Our Story ელოდება antFalls() ელოდება rescueAnt() ელოდება makeRope() ელოდება getBristle() ელოდება getAcorn() ელოდება moveCrow() ელოდება getChick() ელოდება getMillet() ელოდება moveMouse() ელოდება getMilk() ელოდება getGrass() მუშაობს Our Story ელოდება antFalls() ელოდება rescueAnt() ელოდება makeRope() ელოდება getBristle() ელოდება getAcorn() ელოდება moveCrow() ელოდება getChick() ელოდება getMillet() ელოდება moveMouse() ელოდება getMilk() იღებს: ბალახი getGrass() აბრუნებს: ბალახი Our Story ელოდება antFalls() ელოდება rescueAnt() ელოდება makeRope() ელოდება getBristle() ელოდება getAcorn() ელოდება moveCrow() ელოდება getChick() ელოდება getMillet() ელოდება moveMouse() იღებს: რძე getMilk() აბრუნებს: რძე Our Story ელოდება antFalls() ელოდება rescueAnt() ელოდება makeRope() ელოდება getBristle() ელოდება getAcorn() ელოდება moveCrow() ელოდება getChick() ელოდება getMillet() იღებს: თაგვი მოშორდა moveMouse() აბრუნებს: თაგვი მოშორდა Our Story ელოდება antFalls() ელოდება rescueAnt() ელოდება makeRope() ელოდება getBristle() ელოდება getAcorn() ელოდება moveCrow() ელოდება getChick() იღებს: ფეტვი getMillet() აბრუნებს: ფეტვი Our Story ელოდება antFalls() ელოდება rescueAnt() ელოდება makeRope() ელოდება getBristle() ელოდება getAcorn() ელოდება moveCrow() იღებს: წიწილი getChick() აბრუნებს: წიწილი Our Story ელოდება antFalls() ელოდება rescueAnt() ელოდება makeRope() ელოდება getBristle() ელოდება getAcorn() იღებს: ყვავი მოშორდა moveCrow() აბრუნებს: ყვავი მოშორდა Our Story ელოდება antFalls() ელოდება rescueAnt() ელოდება makeRope() ელოდება getBristle() იღებს: რკო getAcorn() აბრუნებს: რკო Our Story ელოდება antFalls() ელოდება rescueAnt() ელოდება makeRope() იღებს: ჯაგარი getBristle() აბრუნებს: ჯაგარი Our Story ელოდება antFalls() ელოდება rescueAnt() იღებს: თოკი makeRope() აბრუნებს: თოკი Our Story ელოდება antFalls() იღებს: ჭიანჭველა გადარჩა rescueAnt() აბრუნებს: ჭიანჭველა გადარჩა Our Story იღებს: გზა გრძელდება antFalls() აბრუნებს: გზა გრძელდება Our Story დასრულდა: გზა გრძელდება ნაბიჯი 1 / 24
იმავე სტეკის 3D ვერსია
გამოძახების სტეკი სივრცეში
დაატრიალეთ გადათრევით. ჩარჩოზე დაჭერით იმ ნაბიჯზე გადახტებით, სადაც ის სტეკს დაემატა.
3D სცენა იტვირთება…
ნაბიჯი 1 / 24
რატომ აქვს თანმიმდევრობას მნიშვნელობა
რწყილი ღორს დახმარებას ამბის დასაწყისშივე სთხოვს, თუმცა ღორი ვერ დაეხმარება, სანამ ჯაჭვის ყველა დანარჩენი მონაწილე თავის საქმეს არ შეასრულებს. ძროხა თხოვნას ბოლოს იღებს, მაგრამ პასუხს პირველი სწორედ ის გასცემს. ამის შემდეგ შედეგი ჯაჭვს საპირისპირო მიმართულებით მიუყვება.
სწორედ ეს საპირისპირო მიმდევრობაა მთავარი. სტეკი პრინციპით „ბოლოს შესული, პირველი გამოსული“ (LIFO) მუშაობს: ბოლოს გამოძახებული ფუნქცია პირველი სრულდება. მისი ჩარჩო სტეკიდან ამოიღება, მის ქვემოთ მოთავსებული ფუნქცია კი მუშაობას იქიდან აგრძელებს, სადაც შეჩერდა.
მაგალითად, getMilk() მუშაობას აჩერებს, როცა getGrass()-ს იძახებს. getGrass() ბალახს აბრუნებს და მისი ჩარჩო სტეკიდან მოშორდება. ამის შემდეგ getMilk() მუშაობას აგრძელებს, რძეს მოიპოვებს და moveMouse()-ს უბრუნებს. გაცილებით მოგვიანებით getBristle() ჯაგარს makeRope()-ს გადასცემს, ის კი მისგან თოკს დაგრეხს და rescueAnt()-ს დაუბრუნებს.
რითი ჰგავს ზღაპარი პროგრამას
ეს ზღაპარი, რა თქმა უნდა, კომპიუტერული პროგრამა არ არის და ნაკლებად სავარაუდოა, რომ მისი შექმნისას ვინმეს გამოძახების სტეკზე ეფიქრა. მათ სტრუქტურაში მსგავსება მაინც აშკარაა: თხოვნები ერთი მიმართულებით გროვდება, პასუხები კი საპირისპირო მიმართულებით ბრუნდება.
ფუნქციის თითოეულ ჩარჩოში ინახება ინფორმაცია, რომელიც მას მუშაობის გასაგრძელებლად დასჭირდება, მათ შორის, ლოკალური ცვლადები და დაბრუნების მისამართი. ზღაპრის პერსონაჟებიც გარკვეულწილად მსგავსად იქცევიან: სანამ მომდევნო თხოვნის შესრულებას ელოდებიან, თითოეულ მათგანს ახსოვს, რას დაჰპირდა რწყილს.
დასასრულს
ზღაპრის მთავარი სათქმელი მეგობრობა, შეუპოვრობა და გასაჭირში მყოფის დახმარებაა. გამოძახების სტეკთან მსგავსება კი მხოლოდ მოულოდნელი პარალელია. სწორედ ამ პარალელის დანახვამ გამაცოცხლებინა ნაცნობი ამბავი ახლებურად.
ახლა ფურიოს მომდევნო კითხვაზეც კარგი პასუხი მაქვს: შემიძლია ვუთხრა, რომ ერთ ქართულ ხალხურ ზღაპარში ფუნქციების გამოძახების სტეკის საოცრად ზუსტი მოდელი იმალება.