वैल्यू ब्लॉक, एक्सप्रेशन से जुड़े होते हैं. जब किसी वैल्यू ब्लॉक का इस्तेमाल इनर ब्लॉक के तौर पर किया जाता है, तो हो सकता है कि आपको अपने ब्लॉक के कोड में, उससे जनरेट हुए एक्सप्रेशन का इस्तेमाल एक से ज़्यादा बार करना पड़े. उदाहरण के लिए, किसी सूची का आखिरी एलिमेंट पाने वाला ब्लॉक, उस एक्सप्रेशन का इस्तेमाल करता है जो सूची को दो बार बनाता है.
// Incorrect block-code generator.
javascriptGenerator.forBlock['last_element'] = function(block, generator) {
// Get the expression that creates the list.
const listCode = generator.valueToCode(block, 'LIST', Order.MEMBER);
// listCode is used twice.
const code = `${listCode}[${listCode}.length - 1]`;
return [code, Order.MEMBER];
}
अगर इनर ब्लॉक का कोड हर बार अलग-अलग वैल्यू जनरेट करता है या कोड के साइड इफ़ेक्ट हैं, तो इससे समस्याएं आती हैं. उदाहरण के लिए, अगर अंदरूनी ब्लॉक का कोड असल में फ़ंक्शन कॉल है, तो इस खास कोड की वजह से, रेंज से बाहर की स्थिति हो सकती है:
randomList()[randomList().length - 1]
इस समस्या से बचने के लिए, आपके कोड में किसी भी इनर ब्लॉक का कोड सिर्फ़ एक बार इस्तेमाल होना चाहिए. ऐसा करने के दो तरीके हैं:
अस्थायी वैरिएबल: अस्थायी वैरिएबल में, अंदरूनी ब्लॉक के कोड का आकलन करने के नतीजे को कैश मेमोरी में सेव करें और इसके बजाय अस्थायी वैरिएबल का इस्तेमाल करें. इस तरीके का इस्तेमाल सिर्फ़ तब किया जा सकता है, जब आपका ब्लॉक स्टेटमेंट वाला ब्लॉक हो.
यूटिलिटी फ़ंक्शन: ऐसा फ़ंक्शन बनाएं जो आपके लिए ज़रूरी काम करता हो. साथ ही, अंदरूनी ब्लॉक के कोड का आकलन करने के नतीजे को इस फ़ंक्शन के आर्ग्युमेंट के तौर पर पास करें. इस तरीके का इस्तेमाल, वैल्यू और stmt ब्लॉक, दोनों के लिए किया जा सकता है.
अस्थायी वैरिएबल
टेम्पररी वैरिएबल, किसी इनर ब्लॉक की कोड स्ट्रिंग की वैल्यू को सेव करता है, ताकि कोड का इंप्रेशन सिर्फ़ एक बार किया जा सके. इसके बाद, वैल्यू का कई बार रेफ़रंस दिया जा सकता है.
वैल्यू ब्लॉक में, टेम्पररी वैरिएबल का इस्तेमाल नहीं किया जा सकता, क्योंकि वैल्यू ब्लॉक को कोड की एक लाइन दिखानी चाहिए. इसके बजाय, यूटिलिटी फ़ंक्शन का इस्तेमाल करें.
import {javascriptGenerator, Order} from 'blockly/javascript';
// Correct block-code generator for a statement block that prints the last element of a list.
javascriptGenerator.forBlock['print_last_element'] = function(block, generator) {
// Get the expression that creates the list.
const listCode = generator.valueToCode(block, 'LIST', Order.MEMBER);
// Get the name of a temporary variable.
const listVar = generator.nameDB_.getDistinctName(
'temp_list', Blockly.names.NameType.VARIABLE);
// Evaluate listCode once and assign the result to the temporary variable.
const code = `var ${listVar} = ${listCode};\n`;
// Print the last element of the list.
code += `print(${listVar}[${listVar}.length - 1]);\n`;
return code;
}
उदाहरण के लिए, अगर इनर ब्लॉक का कोड फ़ंक्शन कॉल randomList()
है, तो जनरेट किया गया कोड यह है:
var temp_list = randomList();
print(temp_list[temp_list.length - 1]);
getDistinctName
कॉल, आपके दिए गए वैरिएबल का नाम लेता है और ऐसा नाम दिखाता है जो उपयोगकर्ता के तय किए गए किसी भी वैरिएबल से मेल न खाता हो.
ग़ैर-ज़रूरी कोड कम करना
टेम्पररी वैरिएबल का एक नुकसान यह है कि अगर इनर ब्लॉक का कोड कोई फ़ंक्शन या एक्सप्रेशन नहीं, बल्कि कोई वैल्यू है, तो आपको ऐसा कोड मिलता है जो ग़ैर-ज़रूरी है:
// Assigning to temp_list is unnecessary.
var temp_list = foo;
print(temp_list[temp_list.length - 1]);
बेहतर कोड बनाने के लिए, यह देखा जा सकता है कि इनर ब्लॉक का कोड कोई वैल्यू है या नहीं. अगर यह वैल्यू नहीं है, तो सिर्फ़ अस्थायी वैरिएबल शामिल करें.
if (listCode.match(/^\w+$/)) {
const code = `print(${listCode}[${listCode}.length - 1]);\n`;
} else {
const listVar = generator.nameDB_.getDistinctName(
'temp_list', Blockly.names.NameType.VARIABLE);
const code = `var ${listVar} = ${listCode};\n`;
code += `print(${listVar}[${listVar}.length - 1]);\n`;
}
यूटिलिटी फ़ंक्शन
यूटिलिटी फ़ंक्शन, डेवलपर का तय किया गया फ़ंक्शन होता है. इसे जनरेट की गई कोड स्ट्रिंग के हिस्से के तौर पर शामिल किया जाता है. इनका इस्तेमाल करके यह पक्का किया जा सकता है कि इनर-ब्लॉक कोड का इंप्रेशन सिर्फ़ एक बार लिया जाए. इसके बाद, वैल्यू का कई बार रेफ़रंस लिया जा सकता है.
यूटिलिटी फ़ंक्शन का इस्तेमाल वैल्यू ब्लॉक और स्टेटमेंट ब्लॉक में किया जा सकता है. हालांकि, स्टेटमेंट ब्लॉक में आम तौर पर अस्थायी वैरिएबल का इस्तेमाल किया जाना चाहिए. ये वैरिएबल आम तौर पर ज़्यादा आसानी से पढ़े जा सकते हैं.
import {javascriptGenerator, Order} from 'blockly/javascript';
// Correct block-code generator for a value block that gets the last element of a list.
javascriptGenerator.forBlock['last_element'] = function(block, generator) {
// Get the expression that creates the list.
const listCode = generator.valueToCode(block, 'LIST', Order.NONE);
// Create a function that accepts a list and returns its last element. The
// language generator adds this function to your code.
const functionName = generator.provideFunction_(
'list_lastElement',
[
`function ${generator.FUNCTION_NAME_PLACEHOLDER_}(list) {`,
` return list[list.length - 1];`,
`}`
]
);
// Create an expression that calls the function with listCode as its argument.
// This evaluates listCode once and passes the resulting list to the function.
const code = `${functionName}(${listCode})`;
return [code, Order.FUNCTION_CALL];
}
उदाहरण के लिए, अगर इनर ब्लॉक का कोड फ़ंक्शन कॉल randomList()
है, तो जनरेट किया गया कोड यह है:
// This code is added to the overall code returned by the code generator.
function list_lastElement(list) {
return list[list.length - 1];
}
// This code is returned by your inner block.
list_lastElement(randomList());
फ़ंक्शन दें
provideFunction_
का इस्तेमाल करके, ब्लॉक-कोड जनरेटर में यूटिलिटी फ़ंक्शन तय किए जा सकते हैं. यह आपके यूटिलिटी फ़ंक्शन के लिए, आपका चुना गया नाम और कोड स्ट्रिंग का एक कलेक्शन लेता है. इसमें फ़ंक्शन की परिभाषा होती है. यह आपके यूटिलिटी फ़ंक्शन का नया नाम दिखाता है. ऐसा करने के लिए, यह उपयोगकर्ता के तय किए गए फ़ंक्शन से मेल न खाने के लिए, फ़ंक्शन में बदलाव करता है.
provideFunction_
, यूटिलिटी फ़ंक्शन की परिभाषाओं को भी डुप्लीकेट से हटा देता है, ताकि हर यूटिलिटी फ़ंक्शन सिर्फ़ एक बार मौजूद हो. भले ही, उसे तय करने वाला ब्लॉक टाइप कई बार मौजूद हो.
प्राथमिकताएं अपडेट करना
यूटिलिटी फ़ंक्शन तय करते समय, आपको ब्लॉक-कोड जनरेटर में शामिल प्राथमिकताएं भी अपडेट करनी चाहिए. इन प्राथमिकताओं से यह तय होता है कि ब्रैकेट कैसे डाले जाते हैं.
प्राथमिकता हमेशा ब्लॉक-कोड जनरेटर से मिली कोड स्ट्रिंग पर आधारित होती है. यह यूटिलिटी फ़ंक्शन में मौजूद ऑपरेटर की परवाह नहीं करता. इसलिए, पिछले उदाहरण में valueToCode
कॉल को Order.NONE
में बदल दिया गया और रिटर्न टपल को Order.FUNCTION_CALL
में बदल दिया गया.