या साइटवरील सामग्री कृत्रिम बुद्धिमत्ता (AI) किंवा मशीन भाषांतर तंत्रज्ञानाचा वापर करून भाषांतरित केली आहे आणि त्यात त्रुटी असू शकतात.

Skip to content

लुआउमधील प्रकार अनुमान

२००६ पासून, Roblox विकसक Lua प्रोग्रामिंग भाषा वापरून Roblox वर गेम्स आणि परस्परसंवादी अनुभव तयार करत आहेत. Roblox विकसक जीवनाच्या सर्व क्षेत्रांतून आणि सर्व अनुभवस्तरांवरून येतात आणि त्यांची निर्मितीही तितकीच विविध आहे.

त्यापैकी काही निर्मिती खरोखरच प्रगत सॉफ्टवेअर आहेत. अनेक कोडच्या दहा हजाराहून अधिक ओळींचे असतात.

Lua ही एक अद्भुत प्रोग्रामिंग भाषा आहे आणि ती आम्हाला खूप आवडते, तरीही आम्ही वेब डेव्हलपर समुदायाने शिकत असलेला तोच धडा शिकत आहोत: डायनॅमिकली टाइप केलेल्या प्रोग्रामिंग भाषांसह मोठ्या अनुप्रयोगांची निर्मिती करणे कठीण आहे!

आम्ही या अंतर भरण्यासाठी Luau तयार केले.

मूळतः, Luau प्रथम एक प्रकार अनुमान इंजिन आहे आणि दुसरे म्हणजे एक प्रकार तपासणी करणारे. ही तत्त्वज्ञान आम्ही OCaml आणि TypeScript संकलकांसारख्या यशस्वी पूर्वीच्या कामांमधून घेतले आहे.

तथापि, Lua खरोखरच OCaml किंवा JavaScript या दोन्हीसारखी नाही. Luau शक्य तितकी उत्कृष्ट बनवण्यासाठी, Lua ला खास बनवणार्‍या गोष्टींचे अचूक मॉडेलिंग करणे अत्यंत महत्त्वाचे आहे.

प्रथम, काही मूलभूत गोष्टी समजावून घेऊया.

प्रकार अनुमान 101

प्रकार अनुमान हा जवळजवळ नेहमीच एखाद्या प्रकार A आणि एखाद्या इतर प्रकार B समान असावेत, हे निरीक्षण करण्याबद्दल असतो. हे एक साधीकरण आहे, परंतु जितके वाटते तितके ते साधीकरण नाही.

चला खूपच लहान उदाहरण घेऊया:

function id(x)
    return x
end

local a = 5
local b = id(a)

जेव्हा आपण id चा प्रकार तपासतो, तेव्हा आपण दोन प्लेसहोल्डर प्रकार तयार करतो: x चा प्रकार आणि फंक्शनचा परतावा प्रकार.

हे प्लेसहोल्डर्स फक्त एक गोष्ट सूचित करतात: आपल्याला त्यांच्याबद्दल काहीच माहिती नाही.

नंतर आम्ही return विधान विश्लेषित करतो. आम्ही पाहतो की, फंक्शनने कोणताही प्रकार परत दिला तरी, तो x च्या प्रकारासारखाच असतो. x वर इतर कोणतीही बंधने नसल्यामुळे, id चा अंतिम अनुमानित प्रकार generic फंक्शन (T) -> T असा होतो.

(Luau अद्याप generic functions साठी सिंटॅक्स प्रदान करत नाही, परंतु अंतर्गत डेटा संरचना त्यांना प्रतिनिधित्व करू शकतात.)
जेव्हा b साठी प्रकार अनुमान करण्याची वेळ येते, तेव्हा आपण id विषयीचे आपले ज्ञान वापरू शकतो. आपण id चा प्रकार घेतो आणि त्याचा पॅरामीटर प्रकार आपल्याकडे असलेल्या ठोस आर्गुमेंट प्रकाराशी बांधतो. कारण फंक्शनचा परतावा प्रकार आधीच त्याच्या पॅरामीटर प्रकाराशी बांधलेला असतो, त्यामुळे (T) -> T हे (number) -> number म्हणून साकार होते. यावरून आपण निष्कर्ष काढू शकतो की b चा प्रकार number आहे.

लुआउद्वारे केलेल्या प्रकार-तपासणीच्या जवळजवळ सर्व कामाचे मूळ हे कल्पनेच्या विस्तारात आहे.

अनेक परतावे

जवळजवळ प्रत्येक व्यापकपणे वापरल्या जाणाऱ्या प्रोग्रामिंग भाषेत, फंक्शन्स नेमके एकच मूल्य परत करतात. अनेक भाषा (विशेषतः फंक्शनल भाषा) अनेक मूल्ये परत करणे सोपे आणि सोयीस्कर करण्यासाठी हलक्या वजनाचे ट्यूपल्स उपलब्ध करून देतात.

Lua या प्रवृत्तीला आव्हान देते कारण प्रत्येक फंक्शनला 0 किंवा त्याहून अधिक मूल्ये परत करण्याची परवानगी आहे. येथे कोणतीही ट्यूपल यंत्रणा वापरली जात नाही कारण संपूर्ण ट्यूपल एका नावाशी बांधण्याचा कोणताही मार्ग नाही.

function take_five(a, b, c, d, e)
    print(a, b, c, d, e)
end

function get_five()
    return 1, 2, 3, 4, 5
end
-- a receives 1.  The other return values are discarded.
local a = get_five()
-- foo, bar, and baz receive 1, 2, and 3, respectively.
-- Arguments 4 and 5 are discarded.
local foo, bar, baz = get_five()
-- the 5 return values from get_five are passed as
-- parameters to take_five
take_five(get_five())

यामुळे काही नवीन आव्हाने निर्माण होतात. खालील compose चा परतावा प्रकार काय आहे?

function compose(f, g)
    return function(...)
        return f(g(...))
    end
end

इतर भाषांमध्ये, आपण असा निष्कर्ष काढू शकतो की g चा परतावा प्रकार हा f च्या आर्गुमेंट प्रकारासारखाच असावा. Lua मध्ये, f ला g द्वारे परत केलेल्या आर्गुमेंट्सची संख्या आणि प्रकार स्वीकारणे आवश्यक आहे.

Luau मध्ये, आम्ही याचे प्रतिनिधित्व 'type pack' नावाच्या संचाद्वारे करतो. हे प्रकार वर्णन करण्यासाठी वापरल्या जाणाऱ्या डेटा संरचनेसारखेच असते, परंतु हे 0 किंवा त्याहून अधिक प्रकारांचे प्रतिनिधित्व करते.

प्रकारांप्रमाणे, टाइप पॅकमध्ये प्लेसहोल्डरची संकल्पना असते जी नंतर इतर पॅकशी बांधता येते. टाइप पॅकची काही इतर वैशिष्ट्ये आहेत: त्यांची लांबी ज्ञात किंवा अज्ञात असू शकते आणि जर ज्ञात असेल तर ती निश्चित किंवा बदलती असू शकते.

Luau फंक्शन्सना प्रकार पॅकच्या जोडीने मॉडेल करते: एक आर्गुमेंट यादीसाठी आणि एक परताव्यासाठी.
जर आपण generic type pack दर्शविण्यासाठी A... ही सिंटॅक्स मानली, तर आपण compose साठी प्रकार लिहू शकतो:

((B...) -> C..., (A...) -> B...) -> (A...) -> C...

(Luau अजूनही हा सिंटॅक्स समर्थन करत नाही. लवकरच येणार!)

टेबल्स

Lua लिहिताना टेबल्स खूप महत्त्वाची असतात. त्या आमच्या अ‍ॅरे, हॅश मॅप्स आणि ऑब्जेक्ट्स सर्व एकाच वेळी आहेत. त्यामुळे Lua कोडमधून टेबल प्रकारांचे अचूक अनुमान करणे खूप महत्त्वाचे आहे.

Luau मध्ये, आम्ही टेबल्स 4 श्रेणींमध्ये विभागतो:

  • ज्यांची अचूक रचना आपल्याला माहित आहे अशा टेबल्स
  • खंडा-खंडाने तयार केलेली टेबल्स
  • फंक्शन पॅरामीटर्स म्हणून पास होणारी टेबल-सदृश संरचना, आणि
  • Roblox API डेटा प्रकार

आम्ही त्यांना सीलबंद टेबल, अनसीलबंद टेबल, सामान्य टेबल आणि नेटिव्ह क्लासेस असे म्हणतो.

सील केलेल्या टेबल्स

आम्हाला पकडायचा असलेला एक अतिशय सामान्य बग म्हणजे टेबल गुणधर्माच्या असाइनमेंटमध्ये गुणधर्म नावाची चुकीची स्पेलिंग.

local some_table = {some_property=0}
-- oops.  I got the name of the property wrong
some_table.sone_property = 55

टेबल्स सामान्यतः डीफॉल्टनुसार सील केलेले असतात.

अनसील्ड टेबल्स

Lua च्या नैसर्गिक शैलीत सुरळीत काम करण्यासाठी, आपल्याला एकापेक्षा जास्त स्टेटमेंट्समध्ये टेबल तयार करणाऱ्या फंक्शन्स आणि मॉड्यूल्सना समर्थन देण्याचा काही मार्ग हवा आहे.

local Counter = {}
Counter.value = 0

function Counter.increment()
    Counter.value = Counter.value + 1
    return Counter.value
end

या उदाहरणात, पहिली ओळ पाहून, {} हा प्रकार समजून घेणे आणि दुसऱ्या ओळीवर प्रकाराची त्रुटी निर्माण करणे मूर्खपणाचे ठरेल, कारण आम्ही Counter ने सदैव रिकामेच राहण्याची अपेक्षा करतो.

म्हणून आम्ही असा दृष्टिकोन घेतो की Counter ही एक अनसील केलेली टेबल आहे. Luau सहजपणे या टेबलचा अचूक आकार ओळखू शकतो, परंतु आम्ही त्याला विस्तारासाठी खुले मानतो.

आम्ही टेबल अनसील करणे खूप सोपे होऊ देऊ इच्छित नाही, म्हणून आम्ही काही सोपी heuristics लागू करतो:

  • टेबलचा प्रकार अनसील केलेला मानला जातो जेव्हा तो शाब्दिक रिक्त टेबलने आरंभ केला जातो, आणि
  • जेव्हाही आम्हाला फंक्शन सिग्नेचरमध्ये अनसील केलेली टेबल सापडते, तेव्हा ती सील टेबलमध्ये रूपांतरित केली जाते.

यामुळे आपल्याला चांगली वापरसुलभता मिळते.

function new_counter()
    local Counter = {}
    Counter.value = 0 -- OK.  Counter is unsealed.

    function Counter.increment()
        Counter.value = Counter.value + 1
        return Counter.value
    end

    return Counter
end

local c = new_counter()
c.value_ = 5 -- Not allowed.  c is a sealed table here.

सामान्य टेबल्स

अनोटेशन नसलेल्या फंक्शन पॅरामीटर्ससह काम करताना, टेबलसारख्या पद्धतीने वापरल्या जाणाऱ्या आर्गुमेंटच्या अचूक आकाराची खात्री करणे क्वचितच शक्य असते:

local function print_point(p)
    print(‘X =’, p.X, ‘Y =’, p.Y)
end

आपण जाणतो की p मध्ये X आणि Y आहेत, परंतु print फंक्शन काहीही प्रिंट करू शकते, त्यामुळे इतकंच. त्या गुणधर्मांचा कोणताही प्रकार असू शकतो. इतर अनेक गुणधर्मही असू शकतात. प्रत्यक्षात ते टेबल असण्याची गरजही नाही; ते Vector3 सारखे Roblox API प्रकार असू शकते.

(Roblox API विषयी थोड्याच वेळात अधिक)

OCaml आणि काही इतर प्रोग्रामिंग भाषांप्रमाणे, Luau टेबल पॅरामीटर्स ओळींसाठी बहुआकार (row polymorphic) असतात. Luau मध्ये, आम्ही त्यांना generic tables म्हणतो. generic table वर उपस्थित असल्याचे गृहीत धरलेल्या फील्ड्स कॉल करणाऱ्यांवर लादलेल्या आवश्यकता असतात. आवश्यक संरचना अस्तित्वात असल्यास इतर गुणधर्म देखील परवानगी आहेत:

local a = print_point({X=3, Y=4})
local c = print_point({X=4, Y=3, Name='The Best Point'})
local b = print_point(Vector3.new(3, 4, 0))

Roblox API

Roblox API आमच्या महत्त्वाकांक्षी विकासक समुदायासाठी बरीच शक्तिशाली साधने उपलब्ध करून देते. ही API बऱ्याच C++ वर्गांचा समावेश करते, ज्यांचे प्रतिबिंब Lua मध्ये केले गेले आहे.

हे स्पष्ट आहे की लुआउला या API बद्दल माहिती असणे आवश्यक आहे. त्या जाणीवेचा एक भाग म्हणजे हे ज्ञान की Roblox क्लास उदाहरणे प्रत्यक्षात लुआउ टेबल नसतात. उदाहरणार्थ, अंगभूत pairs() फंक्शनचा वापर Roblox API प्रकाराच्या गुणधर्मांवर पुनरावृत्ती करण्यासाठी करता येत नाही.

आम्ही आतापर्यंत Luau साठी वर्णन केलेली प्रकार प्रणाली ही पूर्णपणे संरचनात्मक प्रकार प्रणाली आहे. Lua (आणि Luau) टेबल्सना त्यांच्या गुणधर्मांच्या संचापेक्षा काहीच अधिक किंवा कमी मानत नाहीत. Roblox API या मॉडेलमध्ये बसत नाही. C++ एक नाममात्र प्रकार प्रणाली प्रदान करते जिथे प्रत्येक वर्गाची स्वतःची "स्वत्व" असते. अगदी समान संरचना सामायिक असूनही दोन वर्ग भिन्न असणे पूर्णपणे सामान्य आहे. अशा काही वास्तविक Roblox वर्ग आहेत जे या गुणधर्माची पूर्तता करतात आणि Luau ला त्यांना अचूकपणे मॉडेल करणे आवश्यक आहे.

आम्ही अंगभूत Roblox क्लास उदाहरणांसाठी टेबल-सदृश प्रकार (table-like type) सादर करून हे सोडवतो. क्लास प्रकार टेबल प्रकारांपेक्षा वेगळे असतात कारण त्यांची ओळख त्यांना वेगळे करते, जरी ते सर्व समान प्रकारांसह सर्व समान पद्धतींना समर्थन देत असले तरीही. ते वारसाहक्काची संकल्पना देखील समर्थन करतात, अगदी त्या C++ क्लासप्रमाणे ज्यांचे ते मॉडेल करण्यासाठी बनवले गेले आहेत.

निष्कर्ष

Lua सारख्या डायनॅमिक भाषेतून स्टॅटिक प्रकार काढणे अनेक आव्हाने निर्माण करते. यापैकी अनेक आव्हाने Lua विशिष्ट आहेत, परंतु ती चांगल्या प्रकारे सोडवता येऊ शकतात. आम्हाला वाटते की हे खूप चांगले कार्य करते! 🙂

अँडी फ्रिसेन हे लुअउ टाइप चेकरचे तांत्रिक प्रमुख आहेत. त्यांना व्हिडिओ गेम्स, डेव्हलपर साधने आणि प्रोग्रामिंग भाषा यांच्या संगमावर काम करण्यास उत्साह आहे.

Roblox कॉर्पोरेशन किंवा हा ब्लॉग कोणत्याही कंपनी किंवा सेवेला समर्थन किंवा अनुमोदन करत नाहीत. तसेच, या ब्लॉगमध्ये दिलेल्या माहितीच्या अचूकता, विश्वसनीयता किंवा पूर्णतेबाबत कोणतीही हमी किंवा वचनबद्धता दिली जात नाही.