मैंने हाल ही में प्रोग्रामिंग भाषाओं पर एक ऑनलाइन पाठ्यक्रम में भाग लिया, जिसमें अन्य अवधारणाओं के बीच, क्लोजर प्रस्तुत किए गए थे। मैं अपना प्रश्न पूछने से पहले कुछ संदर्भ देने के लिए इस पाठ्यक्रम से प्रेरित दो उदाहरण लिखता हूं।
पहला उदाहरण एक एसएमएल फ़ंक्शन है जो 1 से x तक की संख्याओं की सूची तैयार करता है, जहां x फ़ंक्शन का पैरामीटर है:
fun countup_from1 (x: int) =
let
fun count (from: int) =
if from = x
then from :: []
else from :: count (from + 1)
in
count 1
end
SML REPL में:
val countup_from1 = fn : int -> int list
- countup_from1 5;
val it = [1,2,3,4,5] : int list
countup_from1
समारोह सहायक बंद का उपयोग करता है count
कि कैप्चर और चर का उपयोग करता है x
उसके संदर्भ से।
दूसरे उदाहरण में, जब मैं किसी फ़ंक्शन का आह्वान करता हूं, तो मुझे create_multiplier t
एक फ़ंक्शन (वास्तव में, एक क्लोजर) मिलता है जो इसके द्वारा गुणा करता है:
fun create_multiplier t = fn x => x * t
SML REPL में:
- fun create_multiplier t = fn x => x * t;
val create_multiplier = fn : int -> int -> int
- val m = create_multiplier 10;
val m = fn : int -> int
- m 4;
val it = 40 : int
- m 2;
val it = 20 : int
इसलिए वेरिएबल m
फ़ंक्शन कॉल द्वारा लौटाए गए क्लोजर के लिए बाध्य है और अब मैं इसे इच्छानुसार उपयोग कर सकता हूं।
अब, जीवन भर ठीक से काम करने के लिए बंद होने के लिए, हमें कैप्चर किए गए चर के जीवनकाल का विस्तार करने की आवश्यकता है t
(उदाहरण में यह पूर्णांक है लेकिन यह किसी भी प्रकार का मान हो सकता है)। जहां तक मुझे पता है, एसएमएल में यह कचरा संग्रहण द्वारा संभव बनाया गया है: क्लोजर कैप्चर किए गए मूल्य का संदर्भ रखता है जिसे बाद में कचरा कलेक्टर द्वारा निपटान किया जाता है जब क्लोजर नष्ट हो जाता है।
मेरा प्रश्न: सामान्य तौर पर, कचरा संग्रहण केवल यह सुनिश्चित करने के लिए संभव तंत्र है कि क्लोजर सुरक्षित हैं (अपने पूरे जीवनकाल के दौरान कॉल करने योग्य)?
या क्या अन्य तंत्र हैं जो कचरा संग्रह के बिना बंद होने की वैधता सुनिश्चित कर सकते हैं: कैप्चर किए गए मूल्यों को कॉपी करें और इसे बंद करने के अंदर स्टोर करें? स्वयं को बंद करने के जीवनकाल को प्रतिबंधित करें ताकि इसके पकड़े गए चर समाप्त हो जाने के बाद इसे लागू न किया जा सके?
सबसे लोकप्रिय दृष्टिकोण क्या हैं?
संपादित करें
मुझे नहीं लगता कि ऊपर दिए गए उदाहरण को कैप्चर किए गए चर (ओं) को बंद करके कॉपी किया जा सकता है। सामान्य तौर पर, कैप्चर किए गए चर किसी भी प्रकार के हो सकते हैं, उदाहरण के लिए वे बहुत बड़ी (अपरिवर्तनीय) सूची में बंधे हो सकते हैं। इसलिए, कार्यान्वयन में इन मूल्यों को कॉपी करना बहुत ही अक्षम होगा।
पूर्णता के लिए, संदर्भों (और दुष्प्रभावों) का उपयोग करके यहां एक और उदाहरण दिया गया है:
(* Returns a closure containing a counter that is initialized
to 0 and is incremented by 1 each time the closure is invoked. *)
fun create_counter () =
let
(* Create a reference to an integer: allocate the integer
and let the variable c point to it. *)
val c = ref 0
in
fn () => (c := !c + 1; !c)
end
(* Create a closure that contains c and increments the value
referenced by it it each time it is called. *)
val m = create_counter ();
SML REPL में:
val create_counter = fn : unit -> unit -> int
val m = fn : unit -> int
- m ();
val it = 1 : int
- m ();
val it = 2 : int
- m ();
val it = 3 : int
इसलिए, चर को संदर्भ द्वारा भी कैप्चर किया जा सकता है और फ़ंक्शन कॉल के बाद अभी भी जीवित हैं (उन्हें create_counter ()
) पूरा कर लिया है।