প্রিমিটিভ ও কম্পোজিট ডেটা টাইপ
এই পাঠে যা শিখবেন
- প্রিমিটিভ ডেটা টাইপ — সংজ্ঞা এবং ভাষার মৌলিক বিল্ডিং ব্লক হিসেবে তাদের ভূমিকা
- কম্পোজিট ডেটা টাইপ — অন্যান্য টাইপ থেকে তৈরি টাইপ
- হোমোজিনিয়াস বনাম হেটেরোজিনিয়াস কম্পোজিশন — দুটো মৌলিক কম্পোজিট-টাইপ-নির্মাণ স্ট্র্যাটেজি
- Python দিয়ে নেস্টেড টাইপের একটি রিকার্সিভ সাইজ-এস্টিমেশন ফাংশন বাস্তবায়ন ও হাতে-ভেরিফিকেশন
১ · প্রিমিটিভ ডেটা টাইপ — ভাষার মৌলিক বিল্ডিং ব্লক
প্রিমিটিভ ডেটা টাইপPrimitive Data Typeভাষা সরাসরি প্রদান করে এমন মৌলিক, বিভাজন-অযোগ্য টাইপ — অন্য কোনো টাইপ থেকে তৈরি নয়, বরং নিজেই সবকিছুর ভিত্তি।
(বিল্ট-ইন/স্কেলার টাইপও বলা হয়) হলো একটি ভাষা সরাসরি প্রদান করে এমন মৌলিক টাইপ — অন্য কোনো টাইপ থেকে তৈরি
নয়। সাধারণ উদাহরণ — integer, floating-point number
(সরাসরি ক্রস-রেফারেন্স: ../computer-architecture/-এর IEEE 754 পাঠে এদের হার্ডওয়্যার-লেভেল
বিট-রিপ্রেজেন্টেশন কভার করা হয়েছে), boolean, character — প্রতিটি অন্য টাইপ শেষ পর্যন্ত এগুলো দিয়েই তৈরি,
এরাই সেই মৌলিক ভিত্তি যার উপর বাকি সব টাইপ সিস্টেম দাঁড়িয়ে থাকে।
২ · কম্পোজিট ডেটা টাইপ — দুটো মৌলিক কম্পোজিশন স্ট্র্যাটেজি
কম্পোজিট ডেটা টাইপComposite Data Typeঅন্যান্য টাইপ (প্রিমিটিভ অথবা কম্পোজিট) একত্র করে তৈরি টাইপ — স্ট্রাকচার্ড/অ্যাগ্রিগেট টাইপও বলা হয়। অন্যান্য টাইপ (প্রিমিটিভ, বা এমনকি অন্য কম্পোজিট টাইপ) একত্র করে তৈরি হয়। এই পাঠের মূল ধারণাগত বিন্দু — প্রায় প্রতিটি বাস্তব ভাষার কম্পোজিট টাইপ দুটো মৌলিকভাবে ভিন্ন কম্পোজিশন স্ট্র্যাটেজির একটি (বা মিশ্রণ) থেকে তৈরি —
একই টাইপের অনেকগুলো এলিমেন্ট একত্র করা — ক্লাসিক উদাহরণ array (বিস্তারিত L47-এ)।
একটি নির্দিষ্ট, ছোট সেট এলিমেন্টের, যেগুলোর টাইপ ভিন্ন ভিন্ন হতে পারে — ক্লাসিক উদাহরণ record/struct (বিস্তারিত L47-এ)।
এই দুই স্ট্র্যাটেজি রিকার্সিভভাবে মিশ্রিত হতে পারে — একটি record-এর একটি ফিল্ড নিজেই একটি array হতে পারে, সেই array-এর প্রতিটি এলিমেন্ট আবার একটি record হতে পারে, এবং সেই ভেতরের record-এরও কোনো ফিল্ড আরও একটি record হতে পারে। এই রিকার্সিভ নেস্টিংই বাস্তব ভাষার জটিল ডেটা স্ট্রাকচার (যেমন "শিক্ষার্থীদের একটি ক্লাসরুম, প্রতি শিক্ষার্থীর একটি অবস্থান রেকর্ড") বর্ণনা করার ক্ষমতা দেয় — নিচের কোড সেলে ঠিক এই ধরনের একটি নেস্টেড উদাহরণের প্রকৃত সাইজ গণনা করা হয়েছে।
৩ · কোড: নেস্টেড টাইপের রিকার্সিভ সাইজ-এস্টিমেশন
নিচের কোড সেলে একটি ছোট, রিকার্সিভ টাইপ-বর্ণনা ডেটা স্ট্রাকচার (নেস্টেড ডিকশনারি) এবং একটি
type_size_estimate ফাংশন আছে, যা প্রিমিটিভ টাইপের জন্য একটি নির্দিষ্ট বাইট-সাইজ, array-এর
জন্য element_size × count, ও record-এর জন্য সব ফিল্ডের সাইজের যোগফল হিসেব করে — এবং সবশেষে
একটি genuinely নেস্টেড কম্পোজিট উদাহরণ (একটি record, যার একটি ফিল্ড record-এর একটি array) এর সাইজ গণনা করে,
হাতে-হিসাব করা প্রত্যাশিত মানের সাথে মিলিয়ে দেখা হয়েছে।
def type_size_estimate(type_descriptor):
kind = type_descriptor["kind"]
if kind == "primitive":
return type_descriptor["size"]
elif kind == "array": # হোমোজিনিয়াস: element_size x count
elem_size = type_size_estimate(type_descriptor["element"])
return elem_size * type_descriptor["count"]
elif kind == "record": # হেটেরোজিনিয়াস: সব ফিল্ডের সাইজের যোগফল
return sum(type_size_estimate(f) for f in type_descriptor["fields"])
else:
raise ValueError(f"অজানা টাইপ কাইন্ড: {kind!r}")
# প্রিমিটিভ টাইপ (বাইটে সাইজ)
INT = {"kind": "primitive", "size": 4}
FLOAT = {"kind": "primitive", "size": 8}
CHAR = {"kind": "primitive", "size": 1}
# record Point { x: float, y: float } -- হেটেরোজিনিয়াস
POINT = {"kind": "record", "fields": [FLOAT, FLOAT]}
# array[10] of char -- হোমোজিনিয়াস
GRADES_ARRAY = {"kind": "array", "element": CHAR, "count": 10}
# record Student { id: int, gpa: float, grades: char[10], position: Point }
STUDENT = {"kind": "record", "fields": [INT, FLOAT, GRADES_ARRAY, POINT]}
# array[3] of Student -- হোমোজিনিয়াস, কিন্তু এলিমেন্ট নিজেই একটি হেটেরোজিনিয়াস record
CLASSROOM = {"kind": "array", "element": STUDENT, "count": 3}
# record School { school_id: int, classroom: Student[3] } -- record-এর ভেতরে array of records
SCHOOL = {"kind": "record", "fields": [INT, CLASSROOM]}
print("INT সাইজ:", type_size_estimate(INT), "বাইট")
print("POINT (record: float+float) সাইজ:", type_size_estimate(POINT), "বাইট")
print("STUDENT (নেস্টেড record) সাইজ:", type_size_estimate(STUDENT), "বাইট")
print("CLASSROOM (array of records) সাইজ:", type_size_estimate(CLASSROOM), "বাইট")
print("SCHOOL (record containing array of records) সাইজ:", type_size_estimate(SCHOOL), "বাইট")
# হাতে-ভেরিফাই
expected_student = 4 + 8 + 10 * 1 + 2 * 8 # id(4) + gpa(8) + grades(10x1) + position(2x8)
expected_classroom = 3 * expected_student
expected_school = 4 + expected_classroom # school_id(4) + classroom
print()
print(f"STUDENT হাতে-গণনা: {expected_student}, মিলছে: {expected_student == type_size_estimate(STUDENT)}")
print(f"CLASSROOM হাতে-গণনা: {expected_classroom}, মিলছে: {expected_classroom == type_size_estimate(CLASSROOM)}")
print(f"SCHOOL হাতে-গণনা: {expected_school}, মিলছে: {expected_school == type_size_estimate(SCHOOL)}")
type_size_estimate নিজেই রিকার্সিভ: SCHOOL-এর সাইজ বের
করতে গিয়ে এটি CLASSROOM-কে কল করে, যা আবার STUDENT-কে কল করে, যা আবার
GRADES_ARRAY ও POINT-কে কল করে। প্রতিটি স্তরেই ফাংশনের একই তিনটি নিয়ম (primitive
→ fixed size, array → element × count, record → sum of fields) প্রযোজ্য — এটাই দেখায় হোমোজিনিয়াস ও
হেটেরোজিনিয়াস কম্পোজিশন যেকোনো গভীরতায় মিশ্রিতভাবে নেস্ট হতে পারে, আর একটি সাধারণ রিকার্সিভ ফাংশনই সেই
পুরো নেস্টেড স্ট্রাকচারের সাইজ সঠিকভাবে গণনা করতে পারে।
প্রিমিটিভ টাইপ হলো ভিত্তি, কম্পোজিট টাইপ হলো সেই ভিত্তির উপর দুটো মৌলিক কম্পোজিশন স্ট্র্যাটেজি (হোমোজিনিয়াস/হেটেরোজিনিয়াস) দিয়ে তৈরি কাঠামো — এবং এই দুই স্ট্র্যাটেজি যেকোনো গভীরতায় রিকার্সিভভাবে মিশ্রিত হতে পারে, যা বাস্তব ভাষার প্রায় যেকোনো জটিল ডেটা মডেল বর্ণনা করার ক্ষমতা দেয়।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ একটি array ও একটি record — দুটোই "একাধিক জিনিস একসাথে ধরে রাখে", তাহলে তাদের মধ্যে মূল পার্থক্য কী?
পার্থক্যটা কম্পোজিশন স্ট্র্যাটেজিতে, শুধু "কতগুলো জিনিস ধরে রাখে" তাতে নয়। একটি array
হোমোজিনিয়াস — প্রতিটি এলিমেন্ট একই টাইপের, এবং সংখ্যা সাধারণত বড় বা ভেরিয়েবল হতে পারে (যেমন ১০০০টি
integer)। একটি record হেটেরোজিনিয়াস — এলিমেন্টের সংখ্যা ফিক্সড ও ছোট (নির্দিষ্ট কয়েকটি ফিল্ড), কিন্তু
প্রতিটি ফিল্ডের টাইপ সম্পূর্ণ ভিন্ন হতে পারে (একটি int, একটি float, একটি array)। উপরের কোড সেলের
STUDENT এই পার্থক্যটাই দেখায় — এতে চারটি ফিল্ড আছে, প্রতিটির টাইপ ভিন্ন, যেখানে
GRADES_ARRAY-এর সব এলিমেন্ট একই টাইপের (char)।
প্র ০২ উপরের কোড সেলে CLASSROOM (array of Student) ও SCHOOL (record with a classroom field) এর মধ্যে গঠনগত পার্থক্য কী?
CLASSROOM নিজেই একটি array — এর kind হলো "array", আর এর
এলিমেন্ট টাইপ হলো STUDENT (একটি record) — এটি হোমোজিনিয়াস কম্পোজিশন, কারণ প্রতিটি
এলিমেন্ট একই টাইপের (STUDENT), শুধু সেই টাইপটা নিজেই হেটেরোজিনিয়াস। অন্যদিকে SCHOOL একটি
record — এর kind হলো "record", আর এর দুটো ফিল্ড (INT ও
CLASSROOM) সম্পূর্ণ ভিন্ন টাইপের — এটি হেটেরোজিনিয়াস কম্পোজিশন, যার একটি ফিল্ড নিজেই
একটি হোমোজিনিয়াস কম্পোজিশন (array)। এটাই ঠিক "record-এর ভেতরে array of records" প্যাটার্নের একটি
কংক্রিট উদাহরণ — দুই কম্পোজিশন স্ট্র্যাটেজির রিকার্সিভ মিশ্রণ।
প্র ০৩ type_size_estimate ফাংশনটি কেন রিকার্সিভভাবে লেখা হয়েছে, ইটারেটিভভাবে কেন নয়?
কারণ ইনপুট ডেটা স্ট্রাকচারটাই রিকার্সিভভাবে নেস্টেড — একটি টাইপ-বর্ণনা নিজেই অন্য টাইপ-বর্ণনা ধারণ করে
(array-এর element ফিল্ড, record-এর fields লিস্ট), যা আবার আরও গভীরে নেস্টেড
হতে পারে। একটি ইটারেটিভ সমাধান লিখতে গেলে ম্যানুয়ালি একটি স্ট্যাক বা কিউ ব্যবহার করে "এখনো প্রসেস করা
বাকি" টাইপগুলো ট্র্যাক করতে হতো — যেটা রিকার্সনের চেয়ে অনেক বেশি জটিল কোড হতো। রিকার্সিভ সমাধানে প্রতিটি
type_size_estimate কল স্বয়ংক্রিয়ভাবে (কল স্ট্যাকের মাধ্যমে) সেই "এখনো বাকি" অংশটুকু ট্র্যাক
করে ফেলে — নেস্টেড ডেটা স্ট্রাকচার প্রসেস করার জন্য এটি একটি স্বাভাবিক, প্রায়-সবসময়-সঠিক পছন্দ।
অনুশীলন
-
চিন্তা করুন: একটি নতুন প্রিমিটিভ টাইপ
BOOL = {"kind": "primitive", "size": 1}যোগ করেSTUDENT-এর ফিল্ড তালিকায় একটিis_active: BOOLযোগ করলে নতুন সাইজ কত হবে? হাতে হিসাব করুন।পুরনো
STUDENTসাইজ ছিল ৩৮ বাইট (4 + 8 + 10 + 16)। নতুনBOOLফিল্ড (১ বাইট) যোগ করলে মোট হবে ৩৮ + ১ = ৩৯ বাইট। যেহেতুSTUDENTএখনCLASSROOMওSCHOOL-এর ভেতরেও ব্যবহৃত হচ্ছে, সেই পরিবর্তনটাও উপরের দিকে "প্রোপাগেট" হবে —CLASSROOM= 3 × 39 = ১১৭ বাইট,SCHOOL= 4 + 117 = ১২১ বাইট। এটাই দেখায় রিকার্সিভ কম্পোজিশনের একটি সরাসরি ফলাফল — ভেতরের একটি টাইপ বদলালে সব বাইরের নেস্টেড টাইপের সাইজও স্বয়ংক্রিয়ভাবে বদলে যায়। -
পরীক্ষা করুন: উপরের কোড সেলে
GRADES_ARRAY-এরcount১০ থেকে বদলে ২০ করে Run চেপে দেখুনSTUDENT,CLASSROOM, ওSCHOOL-এর সাইজে কী পরিবর্তন হয়।GRADES_ARRAY-এর সাইজ ১০ থেকে ২০ বাইটে বেড়ে যাবে (২০ × ১ বাইট char)। ফলেSTUDENT-এর সাইজ ৩৮ থেকে ৪৮ বাইটে বাড়বে (10 বাড়তি বাইট)।CLASSROOM(৩টি স্টুডেন্ট) ১১৪ থেকে ১৪৪ বাইটে বাড়বে (3 × 10 = 30 বাড়তি), আরSCHOOL১১৮ থেকে ১৪৮ বাইটে বাড়বে। এই ক্যাসকেডিং পরিবর্তনটাই রিকার্সিভ টাইপ-সাইজ গণনার একটি বাস্তব, প্র্যাক্টিক্যাল পরিণতি — একটি ছোট ইনার টাইপের পরিবর্তন পুরো নেস্টেড হায়ারার্কি জুড়ে ছড়িয়ে পড়ে।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৮টি পাঠ পরবর্তী পাঠ — অ্যাবস্ট্রাক্ট ডেটা টাইপ ও এনক্যাপসুলেশন — এই পাঠের কম্পোজিট টাইপের উপর একটি ভাষা-মেকানিজম স্তর যোগ করবে।
- Computer Architecture & Digital Logic কোর্স সহোদর কোর্স এই পাঠের প্রিমিটিভ টাইপের বাইট-সাইজ ধারণা সেই কোর্সের IEEE 754 ও মেমরি রিপ্রেজেন্টেশন পাঠের সরাসরি ভিত্তি — সেখানে হার্ডওয়্যার-লেভেল বিট প্যাটার্ন বিস্তারিত কভার করা হয়েছে।
- সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity, Cloud Computing & DevOps, Computer Networks, Operating Systems, Computer Architecture ও Programming Languages & Compiler Design — সব এক জায়গায়।