জেনেরিক্স জাভায় টাইপ-সেফ কোড নিশ্চিত করতে ব্যবহৃত হয়, এবং এটি Subtyping ও Inheritance এর সাথে কাজ করার ক্ষমতাও প্রদান করে। তবে, জেনেরিক্সের ক্ষেত্রে সাবটাইপিং এবং ইনহেরিটেন্স নিয়মিত টাইপের থেকে কিছুটা আলাদা ভাবে কাজ করে।
Subtyping in Generics
1. Regular Subtyping:
জাভায় সাবটাইপিং একটি সাধারণ নিয়ম। উদাহরণস্বরূপ, Integer হল Number এর একটি সাবটাইপ।
Number num = new Integer(10); // Valid because Integer is a subtype of Number
2. Generic Subtyping:
জেনেরিক্সের ক্ষেত্রে, List<Integer> এবং List<Number> আলাদা এবং কোনো সাবটাইপিং সম্পর্ক নেই।
List<Number> numList = new ArrayList<Integer>(); // Compilation Error
সমাধান: Wildcards (?) ব্যবহার করা
List<? extends Number> numList = new ArrayList<Integer>(); // Valid
Inheritance in Generics
জেনেরিক টাইপের ক্ষেত্রে ইনহেরিটেন্স সরাসরি না হলেও, সাধারণ ক্লাস বা ইন্টারফেসের ইনহেরিটেন্সের মতো নিয়ম কাজ করে।
উদাহরণ: Generic Class Inheritance
class GenericParent<T> {
T data;
public GenericParent(T data) {
this.data = data;
}
public T getData() {
return data;
}
}
class GenericChild<T> extends GenericParent<T> {
public GenericChild(T data) {
super(data);
}
public void display() {
System.out.println("Data: " + getData());
}
}
ব্যবহারের উদাহরণ:
public class Main {
public static void main(String[] args) {
GenericChild<String> child = new GenericChild<>("Hello, Generics!");
child.display(); // Output: Data: Hello, Generics!
}
}
Subtyping এবং Wildcards
Wildcards (?) ব্যবহার করে সাবটাইপিংয়ের সমস্যা সমাধান করা যায়।
1. Upper Bounded Wildcard (<? extends Type>):
- একটি টাইপ তার নির্দিষ্ট ক্লাস বা সাবক্লাসের মধ্যে সীমাবদ্ধ থাকে।
public static void displayNumbers(List<? extends Number> list) {
for (Number num : list) {
System.out.println(num);
}
}
public static void main(String[] args) {
List<Integer> intList = List.of(1, 2, 3);
displayNumbers(intList); // Valid
}
2. Lower Bounded Wildcard (<? super Type>):
- একটি টাইপ নির্দিষ্ট ক্লাস বা তার সুপারক্লাসের মধ্যে সীমাবদ্ধ থাকে।
public static void addNumbers(List<? super Integer> list) {
list.add(10);
list.add(20);
}
public static void main(String[] args) {
List<Number> numList = new ArrayList<>();
addNumbers(numList); // Valid
}
Generic Method এবং Inheritance
জেনেরিক মেথড ব্যবহার করে সাবটাইপ এবং ইনহেরিটেন্স সহজ করা যায়।
public static <T extends Number> void printSum(List<T> list) {
double sum = 0.0;
for (T num : list) {
sum += num.doubleValue();
}
System.out.println("Sum: " + sum);
}
public static void main(String[] args) {
List<Integer> intList = List.of(1, 2, 3);
List<Double> doubleList = List.of(1.1, 2.2, 3.3);
printSum(intList); // Output: Sum: 6.0
printSum(doubleList); // Output: Sum: 6.6
}
Covariance এবং Contravariance
Covariance (Upper Bound with ? extends):
একটি সাবটাইপের জন্য উপযুক্ত, তবে মডিফাই করার অনুমতি নেই।
List<? extends Number> list = new ArrayList<Integer>();
list.add(10); // Compilation Error
Number num = list.get(0); // Valid
Contravariance (Lower Bound with ? super):
একটি সুপারটাইপের জন্য উপযুক্ত এবং মডিফাই করার অনুমতি দেয়।
List<? super Integer> list = new ArrayList<Number>();
list.add(10); // Valid
Object obj = list.get(0); // Valid, but needs explicit casting
Generics এর Subtyping এবং Inheritance এর সুবিধা
- টাইপ সেফটি নিশ্চিত করে: Compile-time এ টাইপ চেকিং হয়।
- কোড পুনঃব্যবহারযোগ্য করে: একাধিক টাইপের জন্য একই কোড ব্যবহার করা যায়।
- ফ্লেক্সিবিলিটি প্রদান করে: Wildcards ব্যবহার করে টাইপের গন্ডি বাড়ানো যায়।
জাভা জেনেরিক্সে Subtyping এবং Inheritance টাইপ সেফটি এবং পুনঃব্যবহারযোগ্য কোড তৈরিতে সহায়ক। Wildcards এবং Bounded Types ব্যবহার করে জেনেরিক্সের সাবটাইপিং এবং ইনহেরিটেন্স কার্যকরীভাবে ব্যবহৃত হয়।
জাভাতে Subtyping এবং Inheritance হল মূল ভিত্তি, যা জেনেরিক্স ব্যবহার করার সময়ও গুরুত্বপূর্ণ। এই দুটি ধারণা জেনেরিক ক্লাস, মেথড, এবং ডেটা টাইপের মধ্যে টাইপ সম্পর্ক স্থাপন এবং টাইপ সেফটি নিশ্চিত করতে সহায়তা করে।
Subtyping এবং Inheritance কি?
- Subtyping:
- Subtyping একটি টাইপ সিস্টেমের মধ্যে সম্পর্ক স্থাপন করে, যেখানে একটি টাইপ অন্য টাইপের subtype হয়।
- উদাহরণ:
IntegerহলNumberএর একটি subtype।ArrayList<Integer>হলList<Integer>এর একটি subtype।
- Inheritance:
- Inheritance হল ক্লাসের মধ্যে সম্পর্ক যেখানে একটি ক্লাস অন্য ক্লাসের বৈশিষ্ট্য এবং আচরণ উত্তরাধিকার সূত্রে পায়।
উদাহরণ:
class Animal {} class Dog extends Animal {}
Generics এ Subtyping এবং Inheritance এর ভূমিকা
জেনেরিক্স ব্যবহার করার সময়, Subtyping এবং Inheritance কিছু নিয়ম অনুযায়ী কাজ করে।
Generics এবং Subtyping এর উদাহরণ
সাধারণ উদাহরণ:
List<Integer> intList = new ArrayList<>();
List<Number> numList = new ArrayList<>();
// numList = intList; // Compile-time error: incompatible types
নিয়ম:
List<Integer>এবংList<Number>একে অপরের subtype নয়, যদিওIntegerহলNumberএর subtype।
Wildcards দিয়ে Subtyping:
Wildcards (?) ব্যবহার করে Subtyping সম্পর্ক স্থাপন করা যায়।
List<? extends Number> numList = new ArrayList<Integer>();
List<? super Integer> intList = new ArrayList<Number>();
Generics এবং Inheritance এর উদাহরণ
Generics এবং Inheritance:
class Animal {}
class Dog extends Animal {}
class GenericClass<T> {}
public class Main {
public static void main(String[] args) {
GenericClass<Animal> animalObj = new GenericClass<>();
GenericClass<Dog> dogObj = new GenericClass<>();
// animalObj = dogObj; // Compile-time error
}
}
কারণ:
GenericClass<Dog>এবংGenericClass<Animal>একে অপরের subtype নয়, যদিওDogহলAnimalএর subclass।
Wildcards দিয়ে Subtyping এবং Inheritance
Upper Bounded Wildcards (
<? extends T>):- টাইপ প্যারামিটার
Tবা তার সাবটাইপগুলিকে মেনে চলে।
public static void printAnimals(List<? extends Animal> animals) { for (Animal animal : animals) { System.out.println(animal); } } public static void main(String[] args) { List<Dog> dogs = new ArrayList<>(); printAnimals(dogs); // Works }- টাইপ প্যারামিটার
Lower Bounded Wildcards (
<? super T>):- টাইপ প্যারামিটার
Tবা তার সুপারটাইপগুলিকে মেনে চলে।
public static void addDogs(List<? super Dog> animals) { animals.add(new Dog()); } public static void main(String[] args) { List<Animal> animals = new ArrayList<>(); addDogs(animals); // Works }- টাইপ প্যারামিটার
Generics, Subtyping এবং Polymorphism
Generics এর মাধ্যমে Subtyping এবং Polymorphism একত্রে ব্যবহারের সুবিধা পাওয়া যায়।
উদাহরণ:
class Shape {}
class Circle extends Shape {}
public class Main {
public static void drawShapes(List<? extends Shape> shapes) {
for (Shape shape : shapes) {
System.out.println("Drawing shape: " + shape);
}
}
public static void main(String[] args) {
List<Circle> circles = new ArrayList<>();
drawShapes(circles); // Works because of `<? extends Shape>`
}
}
Generics এ Subtyping এবং Inheritance এর ব্যবহার: Advantages
- টাইপ সেফটি: Subtyping এবং Inheritance টাইপ সেফ কোড নিশ্চিত করে।
- কোড পুনঃব্যবহার: Wildcards দিয়ে বিভিন্ন টাইপের জন্য একই জেনেরিক কোড ব্যবহার করা যায়।
- Flexibility: Generics এর মাধ্যমে Subtyping ব্যবহার করে Polymorphic কোড তৈরি করা যায়।
- Compile-Time Checking: টাইপ সম্পর্কিত ত্রুটি কম্পাইল-টাইমে ধরা পড়ে, Runtime ত্রুটি কমায়।
Generics এ Subtyping এবং Inheritance ব্যবহার করার মাধ্যমে জাভায় টাইপ সেফ এবং ফ্লেক্সিবল কোড তৈরি করা যায়। Wildcards (<? extends T>, <? super T>) এই দুটি ধারণার কার্যকারিতা বাড়ায় এবং জেনেরিক ক্লাস বা মেথডগুলোর পুনঃব্যবহারযোগ্যতা বাড়ায়।
জাভার জেনেরিক্সে Covariance এবং Contravariance ধারণাগুলো জেনেরিক টাইপগুলোর সাবটাইপিং সম্পর্ক নিয়ে কাজ করে। এই ধারণাগুলো টাইপ ইনহেরিটেন্সের সাথে মিল রেখে কাজ করে এবং জেনেরিক টাইপগুলোতে ফ্লেক্সিবিলিটি প্রদান করে।
Covariance
Covariance টাইপ সম্পর্কিত এমন একটি ধারণা যেখানে একটি জেনেরিক টাইপ তার সাবটাইপ গ্রহণ করতে পারে। এটি read-only অপারেশনের জন্য ব্যবহৃত হয়।
Covariance-এর জন্য Wildcards: <? extends Type>
<? extends Type>নির্দেশ করে যে টাইপটি Type বা তার সাবক্লাস হতে হবে।- Covariance সাধারণত ডেটা পড়তে ব্যবহৃত হয়, তবে নতুন ডেটা যোগ করা যায় না।
উদাহরণ:
import java.util.List;
import java.util.ArrayList;
public class CovarianceExample {
public static void printNumbers(List<? extends Number> list) {
for (Number num : list) {
System.out.println(num);
}
}
public static void main(String[] args) {
List<Integer> intList = new ArrayList<>();
intList.add(10);
intList.add(20);
List<Double> doubleList = new ArrayList<>();
doubleList.add(3.14);
doubleList.add(1.23);
printNumbers(intList); // Works with Integer (subtype of Number)
printNumbers(doubleList); // Works with Double (subtype of Number)
}
}
আউটপুট:
10
20
3.14
1.23
Contravariance
Contravariance টাইপ সম্পর্কিত এমন একটি ধারণা যেখানে একটি জেনেরিক টাইপ তার সুপারটাইপ গ্রহণ করতে পারে। এটি write-only অপারেশনের জন্য ব্যবহৃত হয়।
Contravariance-এর জন্য Wildcards: <? super Type>
<? super Type>নির্দেশ করে যে টাইপটি Type বা তার সুপারক্লাস হতে হবে।- Contravariance সাধারণত ডেটা যোগ করতে ব্যবহৃত হয়, তবে ডেটা পড়া সম্ভব নয় (অবজেক্ট হিসেবে পড়া ছাড়া)।
উদাহরণ:
import java.util.List;
import java.util.ArrayList;
public class ContravarianceExample {
public static void addNumbers(List<? super Integer> list) {
list.add(10);
list.add(20);
}
public static void main(String[] args) {
List<Number> numberList = new ArrayList<>();
addNumbers(numberList); // Works with Number (supertype of Integer)
List<Object> objectList = new ArrayList<>();
addNumbers(objectList); // Works with Object (supertype of Integer)
System.out.println(numberList); // Output: [10, 20]
System.out.println(objectList); // Output: [10, 20]
}
}
আউটপুট:
[10, 20]
[10, 20]
Covariance বনাম Contravariance
| Aspect | Covariance | Contravariance |
|---|---|---|
| Wildcards | <? extends Type> | <? super Type> |
| Subtyping Direction | Accepts subtypes of the type | Accepts supertypes of the type |
| Usage | Used for reading data | Used for writing data |
| Flexibility | Provides flexibility in reading | Provides flexibility in writing |
| Example | List<? extends Number> | List<? super Integer> |
Covariance এবং Contravariance একত্রে ব্যবহার
import java.util.ArrayList;
import java.util.List;
public class CovarianceContravarianceExample {
public static void processList(List<? extends Number> inputList, List<? super Number> outputList) {
for (Number num : inputList) {
outputList.add(num); // Writing to the output list
}
}
public static void main(String[] args) {
List<Integer> integers = new ArrayList<>();
integers.add(10);
integers.add(20);
List<Object> objects = new ArrayList<>();
processList(integers, objects); // Covariance for input, Contravariance for output
System.out.println(objects); // Output: [10, 20]
}
}
কোডের ভুলের সম্ভাব্যতা কমানোর জন্য নিয়ম
- Covariance (
<? extends Type>) ব্যবহার করুন যখন ডেটা শুধু পড়া হবে। - Contravariance (
<? super Type>) ব্যবহার করুন যখন ডেটা শুধু লেখা হবে। - একই সময়ে Covariance এবং Contravariance ব্যবহার করুন যখন একটি লিস্ট থেকে পড়া এবং আরেকটি লিস্টে লেখা দরকার।
জাভার জেনেরিক্সে Covariance এবং Contravariance টাইপ সাবটাইপিং পরিচালনা করার একটি কার্যকর উপায়।
- Covariance ডেটা পড়ার জন্য কার্যকর, যেখানে টাইপের সাবক্লাসগুলোকে অনুমতি দেয়।
- Contravariance ডেটা লেখার জন্য কার্যকর, যেখানে টাইপের সুপারক্লাসগুলোকে অনুমতি দেয়। এই ধারণাগুলো টাইপ-সেইফ এবং ফ্লেক্সিবল কোড তৈরি করতে সাহায্য করে।
Generic Methods
জাভায় Generic Methods হলো এমন মেথড যা জেনেরিক টাইপ প্যারামিটার ব্যবহার করে। এর মাধ্যমে মেথডকে যেকোনো টাইপের ডেটার জন্য ব্যবহার করা যায়।
Generic Method এর গঠন:
public <T> ReturnType methodName(T param) {
// Method body
}
<T>: টাইপ প্যারামিটার ডিক্লারেশন।T: টাইপ প্যারামিটার মেথডের প্যারামিটার বা রিটার্ন টাইপে ব্যবহার করা হয়।
Generic Method এর উদাহরণ:
public class GenericMethodExample {
// Generic Method
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
public static void main(String[] args) {
Integer[] intArray = {1, 2, 3, 4};
String[] strArray = {"Java", "Generics", "Example"};
printArray(intArray); // Prints: 1 2 3 4
printArray(strArray); // Prints: Java Generics Example
}
}
Generic Methods with Multiple Parameters
public class MultipleGenericMethod {
// Generic Method with Multiple Parameters
public static <T, U> void displayPair(T first, U second) {
System.out.println("First: " + first + ", Second: " + second);
}
public static void main(String[] args) {
displayPair("Java", 100); // First: Java, Second: 100
displayPair(3.14, "Generics"); // First: 3.14, Second: Generics
}
}
Generic Methods with Bounded Types
public class BoundedGenericMethod {
// Generic Method with Upper Bound
public static <T extends Number> double calculateSum(T num1, T num2) {
return num1.doubleValue() + num2.doubleValue();
}
public static void main(String[] args) {
System.out.println(calculateSum(10, 20)); // Output: 30.0
System.out.println(calculateSum(3.14, 2.71)); // Output: 5.85
}
}
Subclassing in Generics
জেনেরিক্স ব্যবহার করে সাবক্লাস তৈরি করলে, একটি ক্লাস অন্য একটি জেনেরিক ক্লাসকে প্রসারিত করতে পারে।
Generic Class Subclassing
// Generic Superclass
class GenericSuperclass<T> {
private T value;
public GenericSuperclass(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
// Non-Generic Subclass
class StringSubclass extends GenericSuperclass<String> {
public StringSubclass(String value) {
super(value);
}
}
// Generic Subclass
class GenericSubclass<T> extends GenericSuperclass<T> {
public GenericSubclass(T value) {
super(value);
}
}
ব্যবহার:
public class SubclassExample {
public static void main(String[] args) {
// Non-Generic Subclass Example
StringSubclass stringObject = new StringSubclass("Hello");
System.out.println("Value: " + stringObject.getValue()); // Output: Value: Hello
// Generic Subclass Example
GenericSubclass<Integer> integerObject = new GenericSubclass<>(100);
System.out.println("Value: " + integerObject.getValue()); // Output: Value: 100
}
}
Generic Interfaces এবং Subclassing
জেনেরিক ইন্টারফেস ব্যবহার করে সাবক্লাস তৈরি করা যায়।
// Generic Interface
interface GenericInterface<T> {
void display(T data);
}
// Subclass Implementing Generic Interface
class GenericInterfaceImpl<T> implements GenericInterface<T> {
@Override
public void display(T data) {
System.out.println("Data: " + data);
}
}
ব্যবহার:
public class GenericInterfaceExample {
public static void main(String[] args) {
GenericInterface<String> stringImpl = new GenericInterfaceImpl<>();
stringImpl.display("Java Generics"); // Output: Data: Java Generics
GenericInterface<Integer> intImpl = new GenericInterfaceImpl<>();
intImpl.display(123); // Output: Data: 123
}
}
Generic Methods এবং Subclassing এর সুবিধা
- Reusable Code:
- একবার লিখে একাধিক টাইপের জন্য ব্যবহার করা যায়।
- Type Safety:
- টাইপ মিসম্যাচের ঝুঁকি কমিয়ে দেয়।
- Flexible Design:
- সাবক্লাস এবং মেথড উভয় ক্ষেত্রেই জেনেরিক্স ডিজাইন সহজ করে।
- Compile-Time Checking:
- টাইপ সংক্রান্ত ত্রুটি কম্পাইল টাইমেই ধরা পড়ে।
জেনেরিক মেথড এবং সাবক্লাসিং জাভার জেনেরিক্সের শক্তিশালী বৈশিষ্ট্য। এগুলোর মাধ্যমে টাইপ সেফ এবং পুনঃব্যবহারযোগ্য কোড লেখা সহজ হয়। বড় প্রজেক্টে কোডের ফ্লেক্সিবিলিটি বাড়াতে এগুলো অত্যন্ত কার্যকরী।
জাভার জেনেরিক্সের ক্ষেত্রে Inheritance Hierarchies এবং Type Compatibility গুরুত্বপূর্ণ ভূমিকা পালন করে। জেনেরিক্স ব্যবহার করার সময় টাইপ ইনহেরিটেন্স এবং কম্প্যাটিবিলিটি পরিচালনা করতে হলে কিছু নিয়ম এবং সীমাবদ্ধতা জানা প্রয়োজন।
Inheritance Hierarchies
জাভায় জেনেরিক ক্লাস এবং ইন্টারফেসের ক্ষেত্রেও ইনহেরিটেন্স নিয়ম প্রযোজ্য।
উদাহরণ: জেনেরিক ক্লাসে ইনহেরিটেন্স
class Parent<T> {
T value;
public Parent(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
class Child<T> extends Parent<T> {
public Child(T value) {
super(value);
}
public void display() {
System.out.println("Value: " + getValue());
}
}
ব্যবহারের উদাহরণ:
public class Main {
public static void main(String[] args) {
Child<String> child = new Child<>("Java Generics");
child.display(); // Output: Value: Java Generics
}
}
Type Compatibility
জেনেরিক টাইপের ইনহেরিটেন্স সাধারণ ক্লাসের মতো সরাসরি কাজ করে না। জেনেরিক্স ব্যবহার করলে টাইপ ইনহেরিটেন্স এবং কম্প্যাটিবিলিটির নিয়মগুলো আরও কঠোর।
উদাহরণ: ইনহেরিটেন্স এবং টাইপ কম্প্যাটিবিলিটি
import java.util.ArrayList;
import java.util.List;
public class CompatibilityExample {
public static void main(String[] args) {
List<Object> objectList = new ArrayList<>();
List<String> stringList = new ArrayList<>();
// Compile-time error: incompatible types
// objectList = stringList;
// Correct: Using wildcards
List<? extends Object> wildcardList = stringList;
System.out.println("Compatibility with wildcards works!");
}
}
কারণ:
List<Object>এবংList<String>ইনহেরিটেন্স সম্পর্কিত নয়।- Wildcards ব্যবহার করে টাইপ কম্প্যাটিবিলিটি অর্জন করা যায়।
Wildcards এবং ইনহেরিটেন্স
1. Upper-Bounded Wildcards
public void processList(List<? extends Number> list) {
for (Number num : list) {
System.out.println(num);
}
}
- ব্যবহার:
List<Integer>,List<Double>ইত্যাদি পাঠানো যাবে।
2. Lower-Bounded Wildcards
public void addNumbers(List<? super Integer> list) {
list.add(100); // Adding elements is allowed
}
- ব্যবহার:
List<Number>বাList<Object>পাঠানো যাবে।
জেনেরিক ক্লাস ইনহেরিটেন্সের সময় টাইপ কম্প্যাটিবিলিটি
উদাহরণ:
class GenericParent<T> {
public void display(T value) {
System.out.println("Parent: " + value);
}
}
class GenericChild<T> extends GenericParent<T> {
@Override
public void display(T value) {
System.out.println("Child: " + value);
}
}
ব্যবহারের উদাহরণ:
public class Main {
public static void main(String[] args) {
GenericParent<String> parent = new GenericParent<>();
parent.display("Hello");
GenericChild<String> child = new GenericChild<>();
child.display("World");
// Using parent reference to child object
GenericParent<String> parentRef = new GenericChild<>();
parentRef.display("Inheritance with Generics");
}
}
আউটপুট:
Parent: Hello
Child: World
Child: Inheritance with Generics
Raw Types এবং Type Compatibility
Raw Type ব্যবহার করলে টাইপ কম্প্যাটিবিলিটির সমস্যা তৈরি হতে পারে। উদাহরণ:
List rawList = new ArrayList();
rawList.add("Hello");
rawList.add(100); // Mixed types allowed
for (Object obj : rawList) {
System.out.println(obj); // No type safety
}
Bounded Type Parameters এবং ইনহেরিটেন্স
উদাহরণ:
class BoundedParent<T extends Number> {
public void show(T value) {
System.out.println("Value: " + value);
}
}
class BoundedChild<T extends Integer> extends BoundedParent<T> {
@Override
public void show(T value) {
System.out.println("Integer Value: " + value);
}
}
ব্যবহারের উদাহরণ:
public class Main {
public static void main(String[] args) {
BoundedChild<Integer> child = new BoundedChild<>();
child.show(123); // Output: Integer Value: 123
}
}
Key Differences Between Generics and Non-Generics Inheritance
| Aspect | Non-Generics | Generics |
|---|---|---|
| Type Safety | No type safety | Compile-time type safety |
| Inheritance Compatibility | Directly compatible | Requires wildcards or explicit typing |
| Flexibility | High but prone to runtime errors | Limited but safe |
- জেনেরিক্স টাইপ ইনহেরিটেন্সের সময় টাইপ সেফটি নিশ্চিত করে।
- টাইপ কম্প্যাটিবিলিটি নিশ্চিত করার জন্য Wildcards (
?) অপরিহার্য। - ইনহেরিটেন্সের ক্ষেত্রে সঠিক টাইপ ব্যবহারে টাইপ-সেফ এবং পুনঃব্যবহারযোগ্য কোড তৈরি করা যায়।
- Raw Types ব্যবহার এড়ানো উচিত, কারণ এটি টাইপ কম্প্যাটিবিলিটির সমস্যা তৈরি করতে পারে।
Read more