ডার্ট ১০১ - ফাংশন
ডার্ট ১০১ - ফাংশন
আজকের টপিক- ফাংশন। এবং আজকের পর থেকে আমরা অন্তত প্রোগ্রামিং চ্যালেঞ্জ টাইপ প্রব্লেম সল্ভ করতে পারব ফ্লাটার দিয়ে।
তবে এর আগে হালকা ঘোষণা। আজকে অফিস থেকে আসার পথে হাসিন হায়দার ভাইয়ের সাথে কথা হচ্ছিল। তো উনি আমাকে বললেন ভিডিও বানাতে। তাহলে সময়ও বাঁচবে, টপিকও অনেক বেশি দেওয়া যাবে। হাসিন ভাইয়ের টিউটোরিয়াল স্কিল সম্পর্কে কে না জানে, কাজেই আমি বাসায় আসামাত্র বসে পড়লাম ভিডিও বানাতে, বানিয়ে ফেললাম ফাংশন এর উপর একটা ভিডিও, ১০/১৫ মিনিট লাগলো! কিন্তু, ওনার শেষের দিকের একটা উপদেশ নেয়া হয়নি আর তা হল, ভালো একটা মাইক্রোফোন! তাই যখন শুনতে গেলাম নিজের রেকর্ডেড কণ্ঠ, বুঝলাম না ঠিক তা কি আমি নাকি শিলা বৃষ্টি হচ্ছে টিনের বাড়ির নিচে! কাজেই, ভিডিও ডিলিট, আইডিয়া আমাজন (ভাই কিন্তু লিংক দিয়েছিলেন!) এর উপর নির্ভরশীল এবং ফিরে এলাম লিখার দিকে!
ব্যাকরণ ও কোডিং এর সস্পর্ক অনেক ইন্টারেস্টিং। আর তার জন্য আমাদের ন্যাচারাল ল্যাঙ্গুয়েজে প্রসেসিং পর্যন্তও যাওয়া লাগবে না। “পদ” থেকে প্রোগ্রামিং যে খুব দূরে না তা সামনের প্যারাগ্রাফ পরেই জানতে পারবেন।
কয়েকটা বাক্য বলি-
আমি আজকে মাইক্রোফোন ছাড়া ভিডিও বানিয়েছিলাম।
আমি ভিডিওটি ডিলিট করে ফেলেছি
আমি এখন বাংলা টাইপ করছি
উপরের বাক্যগুচ্ছের ক্রিয়াপদগুলি লক্ষ্য করা যাক- “বানিয়েছিলাম”, “ডিলিট করে ফেলেছি”, “টাইপ করছি”, এরা বুঝাচ্ছে যে আমি কিছু একটা করছিলাম, আমার কর্মকাণ্ডের ফলশ্রুতিতে কোনো একটা পরিবর্তন এসেছিল আমার পরিবেশে, হয়ত কিছু উদ্দেশ্য সফল হয়েছিল? আমার উদ্দেশ্য ছিল আজকের টপিক নিয়ে কাজ করার এবং উপরের বাক্য গুলি আমার সেই কার্যসিদ্ধির অংশমাত্র। তবে, আজকের টপিকের শুরু থেকে শেষ পর্যন্ত যদি আমরা প্রত্যেকটা গুরুত্বপূর্ণ কাজকে যদি বাক্যে পরিণত করে গল্পের মতো বলি, তাহলে কিন্তু আমার পুরো কাজটার একটা রেকর্ড পাব।
তো আমি যদি কম্পিউটার হতাম এবং এই টপিক লিখাটা যদি একটা প্রোগ্রামের মাধ্যমে হতো তাহলে কিন্তু, বাক্যগুলি হত কোডের মূল উপাদান, “লিখছি” যখন “লিখেছি” তে পরিণত হত তখনি কিন্তু বেড়িয়ে আসত আস্ত একটা পোস্ট। যদি বাক্যগুলিকে সময়ের ক্রমানুযায়ী সাজাই এবং অনুজ্ঞাসূচক বাক্যে পরিণত করে শুধু ক্রিয়াগুলিকে রাখি তাহলে তা দাঁড়াবে-
ভিডিও বানাও ডিলিট করো ওপেন করো টাইপ করো সেভ করো পাবলিশ করো
জানি “পাবলিশ করো” না বলে “ছাপাও” লিখলেও হত, তবে “সেভ করো” না বলে কি বাচাও বলতাম? ব্যাকরণিক খাঁটিত্বকে বিসর্জন দিয়ে আমি একটুও গর্বিত না, তবে এর প্রোগ্রামিয় কানেকশন বুঝানো আমার মূল উদ্দেশ্য এখানে। বাংলা দ্বিতীয় পত্রে আমি কখনোই ভাল ছিলাম না!
ফাংশন হল প্রোগ্রামিংয়ের ক্রিয়াপদ। যে কোন প্রোগ্রামই কোন না কোন গল্প বলে, এবং সেই গল্পের প্রতিটা বাক্যের প্রতিটা পদ প্রোগ্রামিং এর কোন না কোন আর্র্টিফ্যাক্ট। সর্বনাম- ভ্যারিয়েবল এসাইনমেন্ট, ক্রিয়াপদ- ফাংশন, অকর্মক ক্রিয়া- প্যারামিটার বিহীন ফাংশন, সমষ্টিবাচক বিশেষ্য- কালেকশন ক্লাস, নামবাচক/বস্তুবাচক বিশেষ্য- অবজেক্ট, জাতিবাচক বিশেষ্য- ক্লাস ইত্যাদি। অব্যয় পদ হয়ত সেসব গালি যা প্রোগ্রামারের মুখ থেকে বের হয় প্রব্লেম সলভিং এ আটকে গেলে (আমার ক্ষেত্রে, জাভাস্ক্রিপ্টে কাজ করতে গেলে (সমাধান হোক আর না হোক))। বলতে পারবেন প্রমিস/ফিউচার, ক্লোজার অথবা জেনেরিক্স এর ব্যাকরনিয় প্রতিস্থাপক কে কে?
যে কোন প্রব্লেম স্টেটমেন্টকে যদি সুন্দরভাবে লিখে, সেগুলোর কারক, পদ (মূলত বিশেষ্য অথবা ক্রিয়াপদ), অথবা কাল/ভাব ইত্যাদির সাথে এক-এক সম্পর্ক স্থাপন করতে পারি আমরা প্রোগ্রামিং এর বিভিন্ন টার্মকে, তবে আমরা কিন্তু মোটামোটি একটা বয়েলারপ্লেট পাব আমাদের সমাধানের। ভাষা থেকে প্রোগ্রামিং ভাষার প্রতিস্থাপন কিরূপ হবে তা নির্ভর করবে প্রোগ্রামিং ল্যাঙ্গুয়েজটি ফাংশনাল, অবজেক্ট ওরিয়েন্টেড নাকি লজিকাল, তার উপর।
তবে আজকে আমি ফাংশন নিয়ে কথা বলব, এবং ডার্ট ফাংশনের সিনট্যাক্স এবং এর প্রয়োগ নিয়ে আলোচনা করবো। আমার হাতে এই পোস্টটি লিখার জন্য সময় তেমন একটা ছিল না, তার উপর অফিসের কাজ, বাসার কাজ, মুভি দেখা ইত্যাদি, কাজেই সুন্দর উদাহরণ হয়ত চিন্তা করে বের করতে পারিনি, আপনাদের সাহায্য পেলে খুশি হব এইক্ষেত্রে। অগ্রিম ধন্যবাদ।
“আমি দাবা খেলছি” বাক্যটিতে “খেলা” হল (সকর্মক) ক্রিয়া, “দাবা” কর্ম। অর্থাৎ “খেলা” হতে পারে কোন “কিছু”-র, তা দাবা হোক, বল হোক, “আমি গতকাল ব্যাডমিন্টন খেলছিলাম” কিন্তু ওই একই খেলা-র কথা বলে, তবে এর প্রসঙ্গ প্রথম খেলা থেকে ভিন্ন, বুঝা যাচ্ছে, “খেলা” দিয়ে আমরা বাক্য গঠন করতে পারি, আবার এর বর্ণনা দিতে পারি। খেলা-র সংজ্ঞাকে বিস্তৃত করে কিন্তু আমরা শব্দটির প্রতিস্থাপন করতে পারতাম, তবে তা শ্রুতিকটু হত।
ডার্ট ফাংশন কিন্তু সেরকমই, এর সংজ্ঞা এবং ব্যবহার দুটোই রয়েছে। উপরের বাক্যগুলিকে আরেকটু প্রোগ্রামিং এর ধরণে লিখি-
"ক" খেলা হল- পর বাইরের জগৎ "খেলা" হিসেবেই তাকে চিনবে
"ক" যদি হয় "ব্যাডমিন্টন" তাহলে- (ব্যাডমিনটনের নিয়ম)
"ক" যদি হয় "দাবা" তাহলে- (দাবা খেলার নিয়ম)
মাফিনার - খেলে "দাবা" // এখানে "ক" হল দাবা
মারুফ - খেলে ব্যাডমিন্টন // এখানে "ক" হল ব্যাডমিন্টন
দেখতে পাচ্ছি যে, খেলার সংজ্ঞা দেবার সময় আমাদের কিছু জায়গা ও সময় নিতে হয়েছে এদের কলকব্জা ব্যাখ্যা করতে, তবে ওই কলকব্জা কিন্তু সেই সংজ্ঞা পর্যন্তই, আমাদের বর্ণনা শেষ হবার পর কিন্তু, আমরা “খেলা” বলতেই বুঝে যাবো কি বলা হচ্ছে, অনেকটা ভ্যারিয়েবল এসাইনমেন্টের মতো, শুধু এখানে আমরা একটা কর্ম-কে এসাইন করেছি।
১, ২, ৩ ইত্যাদিকে ভ্যারিয়েবলভুক্ত করা এবং একটি ক্রিয়াকে ভ্যারিয়েবলভুক্ত করার মধ্যে তফাৎ রয়েছে। আমাদের প্রেক্ষাপটের এই “খেলা” কিন্তু একটা কর্ম নেয়, অর্থাৎ, কি খেলছে? এবং এর বর্ণনা দেবার সময়ে কিন্তু আমাদের “ক” হিসেবে চিহ্নিত করতে হয়েছে ওই “কর্ম” টিকে, প্রোগ্রামিং এর ভাষায় তা হয়ে যায় প্যারামিটার, যা বর্ণনা কালীন সময়ে “ফর্মাল পারমিটার” এবং ব্যবহারকালীন সময়ে “অ্যাকচুয়াল প্যারামিটার” হিসেবে চিহ্নিত হয়। প্রতিটি ফাংশন এর বর্ণনা তে, কিছু সাময়িক ভ্যারিয়েবল, ফাংশন ইত্যাদির দরকার পরতে পারে (ওই যে, কলকব্জার কথা বলেছিলাম যে), কিন্তু সেগুলোর সাথে বাইরের জগতের কোন লেনদেন নেই, প্রতিটি ফাংশন একেকটা সিস্টেম যা খুবই সীমিত বহিরাগত গ্রহণ করে। ফর্মাল প্যারামিটার একটা বহিরাগত (আরও রয়েছে, যা অবজেক্ট/ক্লাস নিয়ে পোস্ট দেওয়ার সময়ে বলব)। ফাংশনকে বর্ণনা করার সময়েই তা বাইরে থেকে কি নিবে, এবং কি ফেরত দেবে তা বলে রাখতে হবে। কি দেবে বলতে? ধরুন বাক্যটি, “১ কাপ পানিকে ফুটিয়ে তার উপর ১ চা চামচ কায়েন মরিচের গুঁড়া দিন এবং একে ঢেকে রাখুন দিন ৫ মিনিট, এরপর অর্ধেক লেবুর রস দিয়ে মিলিয়ে তা একটা কাপে রাখুন ও পরিবেশন করুন” বাক্যটিতে, যদি আমরা ক্রিয়াগুলি দেখি, তাহলে বলতে পাব- “ধরি ক হল ফুটান(১ কাপ পানি)", “খ হল মিশান(ক, ১ চা চামচ, মরিচের গুঁড়া)", “গ হল মিশান(খ, চিপরান(অর্ধলেবু))", “ঘ হল ঢালুন(গ, কাপ)", “খান(ঘ)", অর্থাৎ প্রতিটা ক্রিয়ার একটা প্রতিক্রিয়া রয়েছে যা বাইরের জগত দেখতে পায়।
এবার আসা যাক ডার্ট এর জগতে।
- ডার্ট যেহেতু একটি স্ট্যাটিক্যালি টাইপড ল্যাঙ্গুয়েজ তাই এর প্যারামিটার ও রিটার্ন টাইপ দুটোরি ডিক্লারেশন লাগবে।
- ডার্ট ফাংশনের বর্ণনা
{}
এর মধ্যে হয়, এর ভেতরকার যত ভ্যারিয়েবল, এসাইনমেন্ট সব{
এবং}
এর মধ্যেই সীমাবদ্ধ থাকে, এর বাইরে না কেউ তাদের চিনে আর না তাদের কোন অস্তিত্ব রয়েছে। return
কিওয়ার্ডের মাধ্যমে আমরা ফাংশনের রিটার্ন ভ্যালু দিয়ে থাকি।<রিটার্ন টাইপ> ফাংশনের নাম(প্যারামিটার ১, প্যারামিটার ২, প্যারামিটার ৩) { <ফাংশনের বর্ণনা> }
হল ডার্ট ফাংশনের টেমপ্লেট। যেমন- আমরা যদি ইনসার্শন সর্টিং ফাংশন দেখি-
List insertionSort(List list) {
for (var i = 1; i < list.length; i++) {
var key = list[i];
var j = i - 1;
while (j >= 0 && list[j] <= key) {
list[j + 1] = list[j];
j--;
}
list[j + 1] = key;
}
return list;
}
-
এই যে
i
,j
,key
ইত্যাদি বর্ণনাতে রয়েছে, এদের কারও কিন্ত ফাংশন বহির্ভুত অস্তিত্ব নেই। যদিi
,j
,key
নামক কোন কিছু থাকেও ফাংশনের বাইরে, এরা তাদের থেকে ফেলে। -
ডার্টে
{
এর ভেতর সৃষ্ট ভ্যারিয়েবল তার}
পর্যন্ত বেঁচে থাকে। একে স্কোপিং বলে। -
যদি এক এক্সপ্রেশনের ফাংশন হয়, তাহলে
{}
ও রিটার্ন না লিখলেও চলবে।=>
এর মাধ্যমে আমরা এক এক্সপ্রেশনের ফাংশন বর্ণনা করতে পারি।
bool isOdd1(int n) => n%2 == 1;
bool isOdd2(int n) {
return n%2 == 1;
}
দুটি ফাংশন কিন্তু একই উপরের কোডটিতে।
-
ফাংশনে টাইপ না লিখলেও চলবে। তাহলে প্যারামিটার ও রিটার্ন টাইপ সব হবে ডাইনামিক। তবে তা না করাই ভাল।
-
তবে এক্সপ্লোরেটোরী প্রোগ্রামিং এর সময়ে, যখন আমরা ঠিক জানি না আমরা কিরূপ ডাটা আশা করছি, তখন কিন্তু আমরা একটা টাইপ-বিহীন ফাংশন তৈরী করে, এর উপর বিভিন্ন ডাটা ও এলগোরিদম প্রয়োগ করতে পারি এবং ম্যান সম্মত সল্যুশন পেলে টাইপ নির্ধারণ করতে পারি।
-
ফাংশন যখন কল করি, তখন তার সিনট্যাক্স হল
functionName(parameter_1, parameter_2)
, যদি তা কিছু রিটার্ন করে, তাহলে আমরাvar r = functionName(parameter_1, parameter_2)
যেখানেr
এর টাইপ ইনফার্ড হবে ফাংশনের রিটার্ন টাইপের মাধ্যমে। -
নিচের ফাংশনটি দেখি-
bool isRightTriangle(int hypotenuse, int leg_1, int leg_2) {
return hypotenuse * hypotenuse == leg_1*leg_1 + leg_2*leg_2;
}
পিথাগোরাসের কথা মনে আছে (নাকি আর্কিমিডিস? আমার তো গণিত মনে নাই কিছু)? ফাংশনকে কল করি যদি- isRightTriangle(5, 3, 4)
তাহলে তা true
দেখাবে। তবে, যদি আমাদের খেয়াল না থাকে কে ভুজ, কে কোটি, আর কে অতিভুজ? ভাল হতো না যদি আমরা- isRightTriangle(hypotenuse: 5, leg_1: 3, leg_2: 4)
হিসেবে কল করতে পারতাম? তাহলে অর্ডার এদিক ওদিক হলেও কিছু হতো না। এমনটা ডার্টে করা যায়, এদের বলে নেইমড প্যারামিটার এবং এহেন করতে হলে আমাদের কোড দাঁড়াবে-
bool isRightTriangle({int hypotenuse, int leg_1, int leg_2}) {
return hypotenuse * hypotenuse == leg_1 * leg_1 + leg_2 * leg_2;
}
প্যারামিটার লিস্ট যখন {}
দ্বারা আবদ্ধ থাকে তখন তাদেরকে নাম ধরে ডাকা যাবে।
- তবে নেইমড প্যারামিটারের পুরা নাম কিন্তু “অপশনাল নেইমড প্যারামিটার”, অর্থাৎ, আমরা যদি
isRightTriangle()
লিখি তাহলে এরর কিন্তু রানটাইম হবে (null
গুন্ করতে না পারার), এ থেকে বাঁচতে হলে আমাদের ডিফল্ট প্যারামিটার ভ্যালু দিতে হবে, যেমন-
bool isRightTriangle({int hypotenuse = 0, int leg_1 = 0, int leg_2 = 0}) {
return hypotenuse * hypotenuse == leg_1*leg_1 + leg_2*leg_2;
}
- তবে ডিফল্ট ভ্যালু শুধু দেওয়া যাবে নেইমড অথবা পজিশনাল প্যারামিটারের ক্ষেত্রে যার কথা আমরা এখন বলবো।
- তবে ডিফল্ট ভ্যালু শুধু দেওয়া যাবে নেইমড অথবা পজিশনাল প্যারামিটারের ক্ষেত্রে যার কথা আমরা এখন বলবো।
- পজিশনাল প্যারামিটার হল নামবিহীন প্যারামিটার (প্রথম উদাহরণের মতো), তবে তাদের কল করার সময়ে না দিলেও চলবে, আবার তাদের ডিফল্ট ভ্যালুও দেওয়া যাবে। যেমন-
String greet([name]) {
if (name == null) return "Hello, Stranger";
return "Hello, $name";
}
এইখানে greet()
কল করলে পাবেন- "Hello, Stranger"
, greet("Dart")
লিখলে পাবেন- "Hello, Dart"
।
-
ডিফল্ট ভ্যালু দিয়ে দেখুনতো কি হয়?
-
বাধ্যতামূলক প্যারামিটারের সাথে শুধু নেইমড অথবা পজিশনাল এর মিশ্রণ চলে! নেইমড ও পজিশনাল কখনোই একত্রে ব্যবহৃত হয় না।
-
গত পোস্টে আমি প্রশ্ন করেছিলাম এক্সপ্রেশন ও স্টেটমেন্টের পার্থক্য নিয়ে, তাহলে বলুনতো,
bool isOdd1(int n) => n%2 == 1;
কি এক্সপ্রেশন না স্টেটমেন্ট? এক কাজ করুন,var isOdd = (bool isOdd1(int n) => n%2 == 1);
লিখে দেখুন এরর পান নাকি? এটি স্টেটমেন্ট তাই না? এবারisOdd1
সরিয়ে দেখুন তো? এক্সপ্রেশান তাই না? -
বেনামি (অ্যানোনিমাস) ফাংশন ডার্টে এক্সপ্রেশান, যা কিনা অন্য ফাংশনের প্যারামিটার অথবা এসাইনমেন্টের ডান দিকে থাকতে পারে। বেনামি ফাংশন লিখার সিনট্যাক্স সাধারণ ফাংশনের মতোই, শুধু নামটা সরিয়ে দেওয়া-
int twice(int n) => n * n;
হয়ে দাঁড়াবে(int n) => n * n;
। আরো বড় উদাহরণ দিতে গেলে-
List insertionSort(List list, bool compare(int a, int b)) {
for (var i = 1; i < list.length; i++) {
var key = list[i];
var j = i - 1;
while (j >= 0 && compare(list[j], key)) {
list[j + 1] = list[j];
j--;
}
list[j + 1] = key;
}
return list;
}
এখানে সর্টিং শুধুমাত্র উর্ধক্রম অথবা নিম্নক্রমে না হয়ে, জিয়া ফাংশন দিব, সেই অনুযায়ী সর্টেড হবে। অর্থাৎ insertionSort([12, 24, -3, 204, 15], (a, b) => a > b)
দিলে তা হবে ছোট থেকে বড় এবং insertionSort([12, 24, -3, 204, 15], (a, b) => a < b)
দিলে তা হবে বড় থেকে ছোট।
- তো আমরা স্কোপ সম্পর্কে জেনেছি, আবার বেনামি ফাংশন বিষয়েও জানালাম। যেহেতু বেনামি ফাংশন এক্সপ্রেশান, তাই তা আরেকটা ফাংশনের রিটার্ন টাইপ হিসেবেও ব্যবহৃত হতে পারে? অর্থাৎ নিচের ফাংশনটি ভ্যালিড?
Function wrapWithHTML(tag) {
// এইখানে `tag` এর অস্তিত্ব আছে।
return (String s) => "<$tag>$s</$tag>";
} // এইখানে `tag` এর অস্তিত্ব নেই।
main() {
var link = wrapWithHTML("a"); // `tag` কে কিন্তু `link` ধরে রেখেছে।
var bold = wrapWithHTML("b"); // `tag` কে কিন্তু `bold` ধরে রেখেছে।
print(link(bold("DART")));
}
wrapWithHTML
একটি ফাংশন রিটার্ন করে, তাই, এর রিটার্ন ভ্যালুর উপর আমরা ()
দিয়ে ফাংশন ডাকতে করতে পারব। কিন্তু, ফাংশনগুলি (link, bold) যখন তৈরী হয়েছে, তারা কিন্তু তাদের পূর্বের ফাংশনের মানকে মনে রেখেছে, অর্থাৎ link
কিন্তু, "a"
কে মনে রেখেছে যা ছিল এর জন্মকালীন সময়ে এর বর্ণনার বাইরের স্কোপের বাসিন্দা। (কমেন্টে তা-ই কিন্তু বলা হয়েছে)
উপরের স্কোপের ভ্যারিয়েবলকে বাঁচিয়ে রাখার আরেকটি উদাহরণ দেখি-
/// Returns a function that adds [addBy] to the
/// function's argument.
Function makeAdder(num addBy) {
return (num i) => addBy + i;
}
void main() {
// Create a function that adds 2.
var add2 = makeAdder(2);
// Create a function that adds 4.
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
- তো আমরা স্কোপ সম্পর্কে জেনেছি, আবার বেনামি ফাংশন বিষয়েও জানালাম। যেহেতু বেনামি ফাংশন এক্সপ্রেশান, তাই তা আরেকটা ফাংশনের রিটার্ন টাইপ হিসেবেও ব্যবহৃত হতে পারে? অর্থাৎ নিচের ফাংশনটি ভ্যালিড?
Function wrapWithHTML(tag) {
// এইখানে `tag` এর অস্তিত্ব আছে।
return (String s) => "<$tag>$s</$tag>";
} // এইখানে `tag` এর অস্তিত্ব নেই।
main() {
var link = wrapWithHTML("a"); // `tag` কে কিন্তু `link` ধরে রেখেছে।
var bold = wrapWithHTML("b"); // `tag` কে কিন্তু `bold` ধরে রেখেছে।
print(link(bold("DART")));
}
wrapWithHTML
একটি ফাংশন রিটার্ন করে, তাই, এর রিটার্ন ভ্যালুর উপর আমরা ()
দিয়ে ফাংশন ডাকতে করতে পারব। কিন্তু, ফাংশনগুলি (link, bold) যখন তৈরী হয়েছে, তারা কিন্তু তাদের পূর্বের ফাংশনের মানকে মনে রেখেছে, অর্থাৎ link
কিন্তু, "a"
কে মনে রেখেছে যা ছিল এর জন্মকালীন সময়ে এর বর্ণনার বাইরের স্কোপের বাসিন্দা। (কমেন্টে তা-ই কিন্তু বলা হয়েছে)
উপরের স্কোপের ভ্যারিয়েবলকে বাঁচিয়ে রাখার আরেকটি উদাহরণ দেখি-
// `addBy` কে ধরে রেখেছে রিটার্নকৃত ফাংশন
Function makeAdder(num addBy) {
return (num i) => addBy + i;
}
void main() {
// এখানে `addBy` 2 ছিল, স্কোপের বাইরে হলেও তা-ই কিন্তু বাড়তে থাকবে।
var add2 = makeAdder(2);
// এখানে `addBy` 4 ছিল, স্কোপের বাইরে হলেও তা-ই কিন্তু বাড়তে থাকবে।
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
দেখতে পাচ্ছি, এক ফাংশনের ভেতরে নির্মিত ফাংশন যদি রিটার্ন্ড হয়, তাহলে সদ্য সৃষ্ট এই ফাংশনটি কিন্তু তার সৃষ্টিকারী ফাংশনের ভ্যারিয়েবল ধরে রাখতে পারে, এবং ওই ভ্যারিয়েবলদের জীবন তাদের নিজস্ব স্কোপের বাইরে থেকে যায়, তাদের বন্ধ (ক্লোজ) করার দায়িত্ব থাকে নবনিযুক্ত ফাংশনটির! এই ধরণের আচরণ যে অভ্যন্তরীণ বেনামি ফাংশন করে তাদের ক্লোজার বলে।
- স্কোপ টেস্ট! এই ফাংশনটি পড়ুন এবং এর ভ্যারিয়েবলদের জীবন/মরণ সম্পর্কে চিন্তা করুন-
bool topLevel = true;
void main() {
var insideMain = true;
void myFunction() {
var insideFunction = true;
void nestedFunction() {
var insideNestedFunction = true;
assert(topLevel);
assert(insideMain);
assert(insideFunction);
assert(insideNestedFunction);
}
}
}
আজকের পর্ব ছোট হওয়ার কথা ছিল কিন্তু মনে হয় না তা করতে পেরেছি, কাজেই আগামী দিনের ব্যাপারে কিছু বলতে চাইছি না।
ফাংশন এখানেই কিন্তু শেষ না, ফাংশন নিয়ে আরো অনেক কথা হবে, এ তো কেবল শুরু, তবে, ফাংশন হোক আর মেথড (আগামী পোস্টে), সিনট্যাক্স এবং ফিলোসোফি দুটোই কিন্তু একই রকম থাকবে, শুধু, আমাদের ক্রিয়ার সাথে যুক্ত হবে বিশেষ্য (উদ্দেশ্য ও বিধেয় দুই-ই কাজ করবে) আগামী পোস্টে!
আশা করি পোস্টটি ভাল লেগেছিল এবং পুরোটা পড়তে পেরেছিলেন। ধন্যবাদ!!