পাঠ ৪৫ · ৫৮-এর মধ্যে · মডিউল ১০
Home / Courses / Concepts of Programming Languages & Compiler Design / প্রিমিটিভ ও কম্পোজিট ডেটা টাইপ

প্রিমিটিভ ও কম্পোজিট ডেটা টাইপ

Primitive & composite data types
৭ মিনিট পড়া মধ্যবর্তী · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • প্রিমিটিভ ডেটা টাইপ — সংজ্ঞা এবং ভাষার মৌলিক বিল্ডিং ব্লক হিসেবে তাদের ভূমিকা
  • কম্পোজিট ডেটা টাইপ — অন্যান্য টাইপ থেকে তৈরি টাইপ
  • হোমোজিনিয়াস বনাম হেটেরোজিনিয়াস কম্পোজিশন — দুটো মৌলিক কম্পোজিট-টাইপ-নির্মাণ স্ট্র্যাটেজি
  • Python দিয়ে নেস্টেড টাইপের একটি রিকার্সিভ সাইজ-এস্টিমেশন ফাংশন বাস্তবায়ন ও হাতে-ভেরিফিকেশন

১ · প্রিমিটিভ ডেটা টাইপ — ভাষার মৌলিক বিল্ডিং ব্লক

প্রিমিটিভ ডেটা টাইপPrimitive Data Typeভাষা সরাসরি প্রদান করে এমন মৌলিক, বিভাজন-অযোগ্য টাইপ — অন্য কোনো টাইপ থেকে তৈরি নয়, বরং নিজেই সবকিছুর ভিত্তি। (বিল্ট-ইন/স্কেলার টাইপও বলা হয়) হলো একটি ভাষা সরাসরি প্রদান করে এমন মৌলিক টাইপ — অন্য কোনো টাইপ থেকে তৈরি নয়। সাধারণ উদাহরণ — integer, floating-point number (সরাসরি ক্রস-রেফারেন্স: ../computer-architecture/-এর IEEE 754 পাঠে এদের হার্ডওয়্যার-লেভেল বিট-রিপ্রেজেন্টেশন কভার করা হয়েছে), boolean, character — প্রতিটি অন্য টাইপ শেষ পর্যন্ত এগুলো দিয়েই তৈরি, এরাই সেই মৌলিক ভিত্তি যার উপর বাকি সব টাইপ সিস্টেম দাঁড়িয়ে থাকে।

২ · কম্পোজিট ডেটা টাইপ — দুটো মৌলিক কম্পোজিশন স্ট্র্যাটেজি

কম্পোজিট ডেটা টাইপComposite Data Typeঅন্যান্য টাইপ (প্রিমিটিভ অথবা কম্পোজিট) একত্র করে তৈরি টাইপ — স্ট্রাকচার্ড/অ্যাগ্রিগেট টাইপও বলা হয়। অন্যান্য টাইপ (প্রিমিটিভ, বা এমনকি অন্য কম্পোজিট টাইপ) একত্র করে তৈরি হয়। এই পাঠের মূল ধারণাগত বিন্দু — প্রায় প্রতিটি বাস্তব ভাষার কম্পোজিট টাইপ দুটো মৌলিকভাবে ভিন্ন কম্পোজিশন স্ট্র্যাটেজির একটি (বা মিশ্রণ) থেকে তৈরি —

হোমোজিনিয়াস কম্পোজিশন
একই টাইপের অনেকগুলো এলিমেন্ট একত্র করা — ক্লাসিক উদাহরণ array (বিস্তারিত L47-এ)।
হেটেরোজিনিয়াস কম্পোজিশন
একটি নির্দিষ্ট, ছোট সেট এলিমেন্টের, যেগুলোর টাইপ ভিন্ন ভিন্ন হতে পারে — ক্লাসিক উদাহরণ record/struct (বিস্তারিত L47-এ)।
ডেটা টাইপ প্রিমিটিভ (int, float, char, bool) কম্পোজিট হোমোজিনিয়াস: array হেটেরো: record
প্রতিটি কম্পোজিট টাইপ শেষ পর্যন্ত হোমোজিনিয়াস (array-জাতীয়) অথবা হেটেরোজিনিয়াস (record-জাতীয়) কম্পোজিশন — অথবা দুটোর রিকার্সিভ মিশ্রণ।
নেস্টিং — রিকার্সিভ কম্পোজিশন

এই দুই স্ট্র্যাটেজি রিকার্সিভভাবে মিশ্রিত হতে পারে — একটি record-এর একটি ফিল্ড নিজেই একটি array হতে পারে, সেই array-এর প্রতিটি এলিমেন্ট আবার একটি record হতে পারে, এবং সেই ভেতরের record-এরও কোনো ফিল্ড আরও একটি record হতে পারে। এই রিকার্সিভ নেস্টিংই বাস্তব ভাষার জটিল ডেটা স্ট্রাকচার (যেমন "শিক্ষার্থীদের একটি ক্লাসরুম, প্রতি শিক্ষার্থীর একটি অবস্থান রেকর্ড") বর্ণনা করার ক্ষমতা দেয় — নিচের কোড সেলে ঠিক এই ধরনের একটি নেস্টেড উদাহরণের প্রকৃত সাইজ গণনা করা হয়েছে।

৩ · কোড: নেস্টেড টাইপের রিকার্সিভ সাইজ-এস্টিমেশন

নিচের কোড সেলে একটি ছোট, রিকার্সিভ টাইপ-বর্ণনা ডেটা স্ট্রাকচার (নেস্টেড ডিকশনারি) এবং একটি type_size_estimate ফাংশন আছে, যা প্রিমিটিভ টাইপের জন্য একটি নির্দিষ্ট বাইট-সাইজ, array-এর জন্য element_size × count, ও record-এর জন্য সব ফিল্ডের সাইজের যোগফল হিসেব করে — এবং সবশেষে একটি genuinely নেস্টেড কম্পোজিট উদাহরণ (একটি record, যার একটি ফিল্ড record-এর একটি array) এর সাইজ গণনা করে, হাতে-হিসাব করা প্রত্যাশিত মানের সাথে মিলিয়ে দেখা হয়েছে।

Python
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) প্রযোজ্য — এটাই দেখায় হোমোজিনিয়াস ও হেটেরোজিনিয়াস কম্পোজিশন যেকোনো গভীরতায় মিশ্রিতভাবে নেস্ট হতে পারে, আর একটি সাধারণ রিকার্সিভ ফাংশনই সেই পুরো নেস্টেড স্ট্রাকচারের সাইজ সঠিকভাবে গণনা করতে পারে।
মূল কথা · Key takeaway

প্রিমিটিভ টাইপ হলো ভিত্তি, কম্পোজিট টাইপ হলো সেই ভিত্তির উপর দুটো মৌলিক কম্পোজিশন স্ট্র্যাটেজি (হোমোজিনিয়াস/হেটেরোজিনিয়াস) দিয়ে তৈরি কাঠামো — এবং এই দুই স্ট্র্যাটেজি যেকোনো গভীরতায় রিকার্সিভভাবে মিশ্রিত হতে পারে, যা বাস্তব ভাষার প্রায় যেকোনো জটিল ডেটা মডেল বর্ণনা করার ক্ষমতা দেয়।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ একটি 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 কল স্বয়ংক্রিয়ভাবে (কল স্ট্যাকের মাধ্যমে) সেই "এখনো বাকি" অংশটুকু ট্র্যাক করে ফেলে — নেস্টেড ডেটা স্ট্রাকচার প্রসেস করার জন্য এটি একটি স্বাভাবিক, প্রায়-সবসময়-সঠিক পছন্দ।

অনুশীলন

  1. চিন্তা করুন: একটি নতুন প্রিমিটিভ টাইপ BOOL = {"kind": "primitive", "size": 1} যোগ করে STUDENT-এর ফিল্ড তালিকায় একটি is_active: BOOL যোগ করলে নতুন সাইজ কত হবে? হাতে হিসাব করুন।

    পুরনো STUDENT সাইজ ছিল ৩৮ বাইট (4 + 8 + 10 + 16)। নতুন BOOL ফিল্ড (১ বাইট) যোগ করলে মোট হবে ৩৮ + ১ = ৩৯ বাইট। যেহেতু STUDENT এখন CLASSROOM ও SCHOOL-এর ভেতরেও ব্যবহৃত হচ্ছে, সেই পরিবর্তনটাও উপরের দিকে "প্রোপাগেট" হবে — CLASSROOM = 3 × 39 = ১১৭ বাইট, SCHOOL = 4 + 117 = ১২১ বাইট। এটাই দেখায় রিকার্সিভ কম্পোজিশনের একটি সরাসরি ফলাফল — ভেতরের একটি টাইপ বদলালে সব বাইরের নেস্টেড টাইপের সাইজও স্বয়ংক্রিয়ভাবে বদলে যায়।

  2. পরীক্ষা করুন: উপরের কোড সেলে 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 — সব এক জায়গায়।
আগের পাঠ
কোরুটিন ও কন্টিনিউয়েশন