Boxing (computer programming)
| Industry | Computer science |
|---|---|
Area served | Software development |
| Products | Boxing, unboxing, autoboxing (concepts) |
In computer science, boxing (also known as wrapping) involves enclosing a primitive data type within an object to allow it to be utilized as a reference. The opposite operation, unboxing, extracts the primitive value from its wrapper object. When this conversion happens automatically as needed, it is called autoboxing.
Boxing
Boxing plays a significant role in Java, which differentiates between reference and value types to optimize runtime performance and maintain clear syntax. For instance, arrays store only primitive types directly, so to accommodate primitive values within collections or other reference-based structures, Java offers primitive wrapper classes such as for , for , among others. These wrapper classes enable defining arrays of objects where primitive values are inserted through boxing.
Conversely, C# does not provide dedicated primitive wrapper classes but allows any value type to be boxed into a generic reference. In Objective-C, the prefix converts primitive types into objects (e.g., ), facilitating their use in container classes like .
In Haskell, the term "boxed" describes its runtime’s unified pointer-to-tagged union representation, despite limited use of explicit reference types.
Boxed instances are copies of the original primitives and are generally immutable. Similarly, unboxing produces a copy of the contained value. Excessive boxing and unboxing can impact performance negatively due to dynamic memory allocation and increased garbage collection overhead. However, advanced garbage collectors such as Java's HotSpot efficiently handle ephemeral boxed objects, reducing this cost.
Some programming languages treat unboxed primitives and references to immutable boxed objects as interchangeable. Assigning boxed objects copies references rather than the underlying values; immutability ensures behavior remains consistent. Operations like arithmetic or comparisons typically involve unboxing operands, performing calculations on primitives, then boxing the result again. This strategy can remove the necessity for direct primitive storage in certain contexts.
Autoboxing
Autoboxing describes the compiler-driven automatic conversion between value types and reference types through implicit type conversion mechanisms.
Prior to J2SE 5.0, code such as:
<syntaxhighlight lang=Java> Integer i = new Integer(9); Integer i = 9; // error before 5.0 </syntaxhighlight>
would not compile because explicit instantiation of an from a primitive was mandatory. Starting with J2SE 5.0, the compiler generates the appropriate Integer object behind the scenes when assigning a literal like . This feature enables expressions such as , where both and are Integers: their values are unboxed for addition, then autoboxed into a new Integer assigned to . It is important to note that equality operators compare object references; thus, value comparison requires explicit unboxing or invoking methods like .
From J2SE 5.0 onward, collections such as can be written as if they hold primitive types like , while internally managing references to wrapper objects (e.g., ). For example, compiles into , simplifying syntax without sacrificing type safety.
Automatic unboxing
Automatic unboxing is the complementary process that extracts the primitive value from its reference type automatically.
Before J2SE 5.0, one had to write:
<syntaxhighlight lang=Java> Integer k = new Integer(4); int l = k.intValue(); // valid int m = k; // error before 5.0 </syntaxhighlight>
Unlike Java, C# does not distinguish between separate primitive and object types; instead, its compiler manages types as either value or reference types without explicit boxing/unboxing syntax.
In both Java and C#, automatic boxing/unboxing does not support downcasting conversions. For instance, attempting the following results in errors:
C#: <syntaxhighlight lang="csharp"> int i = 42; object o = i; // box int j = o; // unbox (error) Console.WriteLine(j); // unreachable </syntaxhighlight>
Java: <syntaxhighlight lang="java"> int i = 42; Object o = i; // box int j = o; // unbox (error) System.out.println(j); // unreachable </syntaxhighlight>
Boxing in Rust
The Box type in Rust denotes a heap-allocated value with exclusive ownership: <syntaxhighlight lang="rust"> let number: Box<i32> = Box::new(42); </syntaxhighlight> For scenarios requiring shared ownership between threads, Rust offers Arc, a reference-counted pointer designed for concurrency with heap-allocated data.
Type helpers
In contemporary Object Pascal, simple type operations are facilitated through type helpers (in FreePascal) or record helpers (in Delphi and FreePascal’s Delphi mode). Although these native-compiling dialects do not incorporate some capabilities such as run-time type inference found in languages like C# and Java, they still provide features related to boxing. For instance: <syntaxhighlight lang="pascal"> {$ifdef fpc}{$mode delphi}{$endif} uses sysutils; // includes wrappers for primitive types var
x: integer = 100; s: string;
begin
s := x.ToString; writeln(s);
end. </syntaxhighlight>