باکسینگ

در علوم رایانه، **«باکسینگ»** یا **«بسته‌بندی»** (که با عنوان *wrapping* نیز شناخته می‌شود)، به فرایند قرار دادن یک نوع داده‌ی ابتدایی (primitive type) درون یک شیء اطلاق می‌شود؛ به‌گونه‌ای که بتوان از آن مقدار به‌عنوان یک مرجع (reference) استفاده کرد. **«آن‌باکسینگ»** یا **«بازگشایی»** (unboxing) به فرایند معکوس این عملیات اشاره دارد، یعنی استخراج مقدار اولیه از شیء بسته‌بندی‌شده. همچنین، اصطلاح **«اتوباکسینگ» یا «بازگشایی خودکار»** (autoboxing) به اعمال خودکار عملیات باکسینگ و/یا آن‌باکسینگ در زمان نیاز گفته می‌شود.

## '''بسته‌بندی'''
کاربرد برجستهٔ بسته‌بندی در زبان جاوا دیده می‌شود؛ جایی که به‌دلایلی مانند بهینه‌سازی عملکرد در زمان اجرا و تفاوت‌های نحوی و معنایی، میان نوع‌های ارجاعی (reference types) و مقداری (value types) تمایز وجود دارد. در جاوا، یک ساختار داده مانند `LinkedList` تنها می‌تواند مقادیری از نوع `Object` را در خود ذخیره کند. اگرچه ممکن است بخواهیم یک `LinkedList` از نوع `int` داشته باشیم، این کار به‌صورت مستقیم امکان‌پذیر نیست. در عوض، جاوا برای هر نوع دادهٔ ابتدایی (primitive type)، یک کلاس بسته‌بندی (primitive wrapper class) متناظر تعریف کرده‌است، مانند:

* `Integer` برای `int`
* `Character` برای `char`
* `Float` برای `float`
* و دیگر انواع مشابه.

بدین ترتیب، می‌توان یک `LinkedList` با استفاده از نوع بسته‌بندی‌شدهٔ `Integer` تعریف کرد و مقادیر `int` را از طریق باکسینگ، به‌صورت شیءهای `Integer` در آن قرار داد. (با معرفی نوع‌های عمومی پارامتری (generic parameterized types) در نسخهٔ J2SE 5.0، این ساختار به‌صورت `LinkedList<Integer>` تعریف می‌شود.)

از سوی دیگر، زبان #C کلاس‌های بسته‌بندیِ نوع‌های ابتدایی (*primitive wrapper classes*) را ندارد، اما امکان باکس‌کردن هر نوع مقداری (value type) را فراهم می‌کند؛ به‌طوری‌که نتیجه به‌صورت یک مرجع از نوع کلی `Object` بازگردانده می‌شود.در زبان Objective-C نیز می‌توان هر مقدار ابتدایی را با قراردادن نماد `@` در ابتدای آن به یک شیء از نوع `NSNumber` تبدیل کرد (برای مثال: `@123` یا `@(123)`). این قابلیت امکان افزودن چنین مقادیری را به مجموعه‌های استانداردی مانند `NSArray` فراهم می‌سازد.

در زبان Haskell، تقریباً هیچ مفهومی تحت عنوان «نوع ارجاعی» (reference type) وجود ندارد؛ با این حال، از اصطلاح «باکس‌شده» (boxed) برای اشاره به نمایش یکنواختِ «اشاره‌گر به ساختار union دارای برچسب» در زمان اجرا استفاده می‌شود.

شیء باکس‌شده همواره نسخه‌ای کپی از مقدار اولیه است و معمولاً این شیء تغییرناپذیر (immutable) می‌باشد. بازگشایی (unboxing) نیز نسخه‌ای کپی از مقدار ذخیره‌شده را بازمی‌گرداند. تکرار عملیات بسته‌بندی و بازگشایی می‌تواند تأثیر منفی چشم‌گیری بر عملکرد داشته باشد؛ چراکه بسته‌بندی به‌صورت پویا اشیای جدیدی ایجاد می‌کند و بازگشایی، در صورتی که مقدار باکس‌شده دیگر استفاده نشود، باعث می‌شود آن اشیا برای بازیافت حافظه (garbage collection) در دسترس قرار گیرند. با این حال، بازیاب‌های حافظهٔ مدرن، مانند بازیاب پیش‌فرض Java HotSpot، می‌توانند اشیای کوتاه‌عمر را با کارایی بیشتری مدیریت کنند. بنابراین، در صورتی که اشیای باکس‌شده عمر کوتاهی داشته باشند، تأثیر آن‌ها بر عملکرد ممکن است چندان محسوس نباشد.

در برخی زبان‌های برنامه‌نویسی، میان نوع‌های ابتداییِ بدون بسته‌بندی (unboxed primitives) و ارجاع به اشیای بسته‌بندی‌شدهٔ تغییری‌ناپذیر (immutable boxed objects)، برابری مستقیمی وجود دارد. در واقع، این امکان وجود دارد که تمامی نوع‌های ابتداییِ به‌کاررفته در یک برنامه با نوع‌های شیء بسته‌بندی‌شده جایگزین شوند. در حالی‌که انتساب از یک نوع ابتدایی به نوع ابتدایی دیگر، مقدار را کپی می‌کند، انتساب از یک ارجاع به شیء بسته‌بندی‌شده به ارجاع دیگر، تنها مقدار ارجاع را منتقل می‌کند؛ به‌گونه‌ای که هر دو ارجاع به یک شیء یکسان اشاره می‌کنند. با این حال، این مسئله مشکلی ایجاد نمی‌کند، زیرا این اشیاء تغییری‌ناپذیر هستند، و از نظر معنایی تفاوتی میان دو ارجاع به یک شیء یا ارجاع به دو شیء جداگانه با مقدار برابر وجود ندارد مگر آن‌که برابری فیزیکی (physical equality) مورد نظر باشد. برای تمام عملیات به‌جز انتساب، مانند عملیات ریاضی، مقایسه‌ای و منطقی، می‌توان ابتدا مقدار بسته‌بندی‌شده را بازگشایی کرد (unbox)، عملیات را انجام داد، و در صورت نیاز، نتیجه را مجدداً بسته‌بندی نمود (re-box). بنابراین، از نظر نظری، این امکان وجود دارد که نوع‌های ابتدایی به‌طور مستقیم ذخیره نشوند

## '''بسته‌بندی خودکار'''
اصطلاح «بسته‌بندی خودکار» (Autoboxing) به فرایندی اطلاق می‌شود که طی آن یک نوع ارجاعی (reference type) تنها از طریق تبدیل نوع (چه به‌صورت ضمنی و چه به‌صورت صریح) از یک نوع مقداری (value type) به‌دست می‌آید. در این حالت، کامپایلر به‌طور خودکار کدی را اضافه می‌کند که شیء مربوطه را ایجاد می‌نماید.

به‌عنوان مثال، در نسخه‌های پیش از J2SE 5.0 از زبان جاوا، قطعه‌کد زیر قابل کامپایل نبود:
```java
Integer i = new Integer(9);
Integer i = 9; // خطا در نسخه‌های پیش از 5.0!
```
کامپایلرهای نسخه‌های پیش از 5.0 خط آخر را نمی‌پذیرفتند. `Integer` یک شیء ارجاعی (reference object) است و در ظاهر تفاوتی با نوع‌هایی مانند `List`، `Object` و غیره ندارد. برای تبدیل یک مقدار `int` به یک شیء `Integer`، برنامه‌نویس مجبور بود شیء `Integer` را به‌صورت دستی ایجاد کند. اما از نسخهٔ J2SE 5.0 به بعد، کامپایلر این خط را می‌پذیرد و به‌طور خودکار آن را طوری بازنویسی می‌کند که شیئی از نوع `Integer` برای ذخیرهٔ مقدار ۹ ایجاد شود. این بدان معناست که از نسخهٔ J2SE 5.0 به بعد، نوشتن عبارتی مانند `Integer c = a + b` ــ در حالی که `a` و `b` خودشان از نوع `Integer` باشند ــ قابل کامپایل است. در این حالت، `a` و `b` به‌صورت خودکار «بازگشایی» می‌شوند (unboxed)، مقادیر عددی آن‌ها با هم جمع می‌شود، و نتیجه به‌طور خودکار دوباره «بسته‌بندی» شده (autoboxed) و در متغیر `c` به‌صورت یک شیء جدید `Integer` ذخیره می‌شود. با این حال، نمی‌توان از عملگرهای مقایسه‌ای به همین صورت استفاده کرد؛ زیرا این عملگرها برای نوع‌های ارجاعی تعریف شده‌اند و تنها برابریِ ارجاع‌ها (references) را بررسی می‌کنند، نه مقدار درون آن‌ها را. برای مقایسهٔ مقدار در نوع‌های بسته‌بندی‌شده، همچنان باید آن‌ها را به‌صورت دستی بازگشایی کرد و مقادیر ابتدایی را مقایسه نمود، یا از متد `Objects.equals` استفاده کرد.

مثال دیگر: در نسخهٔ J2SE 5.0، برنامه‌نویس می‌تواند با مجموعه‌هایی مانند `LinkedList` طوری رفتار کند که گویی شامل مقادیر `int` هستند، نه اشیای `Integer`. این موضوع با آنچه پیش‌تر گفته شد تناقضی ندارد؛ زیرا مجموعه همچنان تنها شامل ارجاع‌هایی به اشیای پویا است و نمی‌تواند نوع‌های ابتدایی را مستقیماً در خود نگه دارد. در واقع، نمی‌توان از `LinkedList<int>` استفاده کرد، بلکه باید از `LinkedList<Integer>` بهره برد. با این حال، کامپایلر به‌طور خودکار کد را به‌گونه‌ای بازنویسی می‌کند که لیست «بی‌سروصدا» اشیای بسته‌بندی‌شده را دریافت کند، در حالی که در کد منبع تنها به مقادیر ابتدایی اشاره شده است. برای مثال، برنامه‌نویس می‌تواند بنویسد `list.add(3)` و تصور کند که مقدار ۳ از نوع `int` به لیست افزوده شده‌ است؛ اما در عمل، کامپایلر این خط را به شکل زیر بازنویسی می‌کند: `list.add(new Integer(3))`.

### بازگشایی خودکار
در حالت «بازگشایی خودکار» (automatic unboxing)، کامپایلر به‌طور خودکار کدی اضافه می‌کند که مقدار را از شیء بسته‌بندی‌شده استخراج می‌کند؛ این کار ممکن است با فراخوانی یک متد روی آن شیء یا به روش‌های دیگر انجام شود.

برای نمونه، در نسخه‌های پیش از J2SE 5.0 از زبان جاوا، قطعه‌کد زیر قابل کامپایل نبود:
```java
Integer k = new Integer(4);
int l = k.intValue(); // همیشه مجاز است
int m = k;            // در گذشته خطا بود، اما اکنون مجاز است
```
زبان #C از «بازگشایی خودکار» (automatic unboxing) به همان شکلی که در زبان جاوا پشتیبانی می‌شود، پشتیبانی نمی‌کند؛ زیرا در #C مجموعه‌ای مجزا از نوع‌های ابتدایی (primitive types) و نوع‌های شیء (object types) وجود ندارد. تمامی نوع‌هایی که در جاوا به‌صورت جداگانه به‌عنوان نوع ابتدایی و نوع شیء تعریف شده‌اند، در #C توسط کامپایلر به‌صورت خودکار به یکی از دو شکلِ «نوع مقداری» (value type) یا «نوع ارجاعی» (reference type) پیاده‌سازی می‌شوند.

در هر دو زبان، «بسته‌بندی خودکار» به‌طور پیش‌فرض عملیات «پایین‌ریزی نوع» (downcast) را انجام نمی‌دهد؛ به‌عبارت دیگر، کد زیر قابل کامپایل نخواهد بود:

C:
```csharp
int i = 42;
object o = i;         //  بسته‌بندی(boxing)
int j = o;            // بازگشایی(boxing) - خطا!
Console.WriteLine(j); // این خط اجرا نمی‌شود؛ نویسنده احتمالاً انتظار داشت خروجی "42" باشد
```
جاوا:
```java
int i = 42;
object o = i;         //  بسته‌بندی(boxing)
int j = o;            // بازگشایی(boxing) - خطا!
System.out.println(j); // این خط اجرا نمی‌شود؛ نویسنده احتمالاً انتظار داشت خروجی "42" باشد
```


## '''بسته‌بندی در زبان Rust:'''
در زبان **[[راست (زبان برنامه‌نویسی)|Rust]]**، ساختاری به نام `Box` وجود دارد:
```rust
let number = Box::new(42);
```
اگر قرار باشد مقدار به یک نخ (thread) دیگر منتقل شود، باید از ساختار `Arc` استفاده شود.

## '''کمک‌کننده‌های نوع (Type Helpers):'''
در زبان Modern Object Pascal، روشی دیگر برای انجام عملیات بر روی نوع‌های ساده وجود دارد که شباهت زیادی به باکسینگ (boxing) دارد و با عنوان «کمک‌کننده‌های نوع» (*type helpers*) در FreePascal یا «کمک‌کننده‌های رکورد» (*record helpers*) در Delphi و FreePascal (در حالت Delphi) شناخته می‌شود.

گویش‌های اشاره‌شده، همگی از خانوادهٔ زبان‌های Object Pascal هستند که به کد بومی (native) کامپایل می‌شوند و از این رو برخی از قابلیت‌هایی را که در زبان‌هایی مانند #C و Java وجود دارد، پشتیبانی نمی‌کنند. از جملهٔ این قابلیت‌ها می‌توان به «استنباط نوع در زمان اجرا» (runtime type inference) برای متغیرهایی با نوع ایستا (strongly typed) اشاره کرد.

با این‌حال، این قابلیت تا حدی با مفهوم باکسینگ مرتبط است؛ چرا که به برنامه‌نویس اجازه می‌دهد از ساختارهایی مانند موارد زیر استفاده کند:
```pascal
{$ifdef fpc}{$mode delphi}{$endif}
uses sysutils;  // این واحد شامل کمک‌کننده‌هایی برای نوع‌های ساده است
var
  x:integer=100;
  s:string;
begin
  s:= x.ToString;
  writeln(s);
end.
```


## '''منابع'''

رده:علوم رایانه
رده:انواع داده
رده:جاوا (زبان برنامه‌نویسی)
رده:مفاهیم زبان برنامه‌نویسی