GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||
GeezerVison is showing en.wikipedia.org — Union type - Wikipedia Not to be confused with Union (set theory) or Union (SQL).
In computer science, a union is a value that may have any of multiple representations or formats within the same area of memory, or a variable that may hold such a data structure. Some programming languages support a union type for such a data type. In other words, a union type specifies the permitted types that may be stored in its instances, e.g., A union can be pictured as a chunk of memory that is used to store variables of different data types. Once a new value is assigned to a field, the existing data is overwritten with the new data. The memory area storing the value has no intrinsic type (other than just bytes or words of memory), but the value can be treated as one of several abstract data types, having the type of the value that was last written to the memory area. In type theory, a union has a sum type; this corresponds to disjoint union in mathematics. Depending on the language and type, a union value may be used in some operations, such as assignment and comparison for equality, without knowing its specific type. Other operations may require that knowledge, either by some external information, or by the use of a tagged union. Untagged unionsBecause of the limitations of their use, untagged unions are generally only provided in untyped languages or in a type-unsafe way (as in C). They have the advantage over simple tagged unions of not requiring space to store a data type tag. The name "union" stems from the type's formal definition. If a type is considered as the set of all values that that type can take on, a union type is simply the mathematical union of its constituting types, since it can take on any value any of its fields can. Also, because a mathematical union discards duplicates, if more than one field of the union can take on a single common value, it is impossible to tell from the value alone which field was last written. However, one useful programming function of unions is to map smaller data elements to larger ones for easier manipulation. A data structure consisting, for example, of 4 bytes and a 32-bit integer, can form a union with an unsigned 64-bit integer, and thus be more readily accessed for purposes of comparison etc. Unions in various programming languagesALGOL 68ALGOL 68 has tagged unions, and uses a case clause to distinguish and extract the constituent type at runtime. A union containing another union is treated as the set of all its constituent possibilities, and if the context requires it a union is automatically coerced into the wider union. A union can explicitly contain no value, which can be distinguished at runtime. An example is: mode node = union (real, int, string, void);
node n := "abc";
case n in
(real r): print(("real:", r)),
(int i): print(("int:", i)),
(string s): print(("string:", s)),
(void): print(("void:", "EMPTY")),
out print(("?:", n))
esac
The syntax of the C/C++ union type and the notion of casts was derived from ALGOL 68, though in an untagged form.[1] C/C++In C and C++, untagged unions are expressed nearly exactly like structures (structs), except that each data member is located at the same memory address. The data members, as in structures, need not be primitive values, and in fact may be structures or even other unions. C++ (since C++11) also allows for a data member to be any type that has a full-fledged constructor/destructor and/or copy constructor, or a non-trivial copy assignment operator (for example, a The primary use of a union is allowing access to a common location by different data types, for example hardware input/output access, and bitfield and word sharing. Unions can also provide low-level polymorphism. However, there is no checking of types, so it is up to the programmer to be sure that the proper fields are accessed in different contexts. The relevant field of a union variable is typically determined by the state of other variables, possibly in an enclosing struct. One common C programming idiom uses unions to perform type punning, by assigning to one field of a union and reading from another, as is done in code which depends on the raw representation of the values. In C++, the equivalent feature is similar to a
— ANSI/ISO 9899:1990 (the ANSI C standard) Section 6.5.2.1 Anonymous unionIn C (since C11) and C++, unions may also be anonymous. Their data members do not need to be referenced, are instead accessed directly. They have some restrictions as opposed to traditional unions: in C11, they must be a member of another structure or union,[2] and in C++, they can not have methods or access specifiers. Simply omitting the class-name portion of the syntax does not make a union an anonymous union. For a union to qualify as an anonymous union, the declaration must not declare an object. Example: union { float f; uint32_t d; // Assumes float is 32 bits wide }; f = 3.14f; printf("Hexadecimal representation of 3.14f: %x\n", d); Anonymous unions are also useful in C Transparent unionIn compilers such as GCC, Clang, and IBM XL C for AIX, a COBOLIn COBOL, union data items are defined in two ways. The first uses the 01 PERSON-REC. 05 PERSON-NAME. 10 PERSON-NAME-LAST PIC X(12). 10 PERSON-NAME-FIRST PIC X(16). 10 PERSON-NAME-MID PIC X. 05 PERSON-ID PIC 9(9) PACKED-DECIMAL. 01 PERSON-DATA RENAMES PERSON-REC. The second way to define a union type is by using the 01 VERS-INFO. 05 VERS-NUM PIC S9(4) COMP. 05 VERS-BYTES PIC X(2) REDEFINES VERS-NUM PascalIn Pascal, there are two ways to create unions. One is the standard way through a variant record. The second is a nonstandard means of declaring a variable as absolute, meaning it is placed at the same memory location as another variable or at an absolute address. While all Pascal compilers support variant records, only some support absolute variables. For the purposes of this example, the following are all integer types: a byte consists of 8 bits, a word is 16 bits, and an integer is 32 bits. The following example shows the non-standard absolute form: var A: Integer; B: array[1..4] of Byte absolute A; C: Integer absolute 0; In the first example, each of the elements of the array B maps to one of the specific bytes of the variable A. In the second example, the variable C is assigned to the exact machine address 0. In the following example, a record has variants, some of which share the same location as others: type Shape = (Circle, Square, Triangle); Dimensions = record case Figure: Shape of Circle: (Diameter: real); Square: (Width: real); Triangle: (Side: real; Angle1, Angle2: 0..360) end; PL/IIn PL/I the original term for a union was cell,[5] which is still accepted as a synonym for union by several compilers. The union declaration is similar to the structure definition, where elements at the same level within the union declaration occupy the same storage. Elements of the union can be any data type, including structures and array.[6]: pp192–193 Here 1 vers_info union, 5 vers_num fixed binary, 5 vers_bytes pic '(2)A'; An alternative to a union declaration is the RustRust implements both tagged and untagged unions. In Rust, tagged unions are implemented using the Rust also supports untagged unions using the Syntax and exampleCIn C, a union is most commonly used to save memory by storing different data types in the same memory location. union FloatBits { float f; uint32_t u; }; A struct can also be a member of a union. In the following example, a struct with bit fields specified is a member of a union. For example, the following example represents a type that may be used as a single raw byte, or individual configuration flags. union ControlRegister { uint8_t full_register; struct { uint8_t enable : 1; uint8_t mode : 3; uint8_t status : 4; } bits; }; union ControlRegister config = { .bits = { .enable = 1, .mode = 2, } }; Additionally, unions are most widely used for type punning, i.e. interpreting the raw binary representation of one data type as another. #include <stdio.h> union Ipv4Addr { uint32_t address; uint8_t octets[4]; }; // Write individual octets Ipv4Addr ip = { .octets = {192, 168, 1, 1} } // Read the octets as an integer: 0x0101A8C0 printf("0x%08X\n", ip.address); // Write as a 32-bit integer ip.address = 0x0A000001; // Read the integer as octets: 1.0.0.10 printf("%u.%u.%u.%u\n", ip.octets[0], ip.octets[1], ip.octets[2], ip.octets[3]); C++C++ supports C's import std; struct Circle { double radius; }; struct Rectangle { double width; double height; }; using Shape = std::variant<Circle, Rectangle>; int main() { Shape s = Circle { .radius = 5.0 }; // check if s holds a Circle if (std::holds_alternative<Circle>(s)) { // interpret s as a circle if so const Circle& circle = std::get<Circle>(s); std::println("s is a Circle with radius {}", circle.radius); } // s can be reassigned to another alternative s = Rectangle { .width = 2.0, .height = 3.0 }; } C#Until C# 15, there were no union types in C#. The closest way to emulate them was through records and pattern matching. namespace Wikipedia.Examples; using System; abstract record Shape; record Circle(double Radius) : Shape; record Rectangle(double Width, double Height) : Shape; public class Example { public static double Area(Shape s) => s switch { Circle c => Math.PI * c.Radius * c.Radius, Rectangle r => r.Width * r.Height, _ => throw new NotSupportedException() }; } They could also be closely simulated using low-level layout. The following demonstrates such a union, where the fields occupy the same memory, but is not type-safe. This can be used for interoperability, serialization, and unsafe manipulation. using System.Runtime.InteropServices; // closest to C union FloatBits { float f; uint32_t u; }; [StructLayout(LayoutKind.Explicit)] struct FloatBits { [FieldOffset(0)] public float f; [FieldOffset(0)] public uint u; } In C# 15, the public record class Car(string Model); public record class Bicycle(string Model); public record class Bus(string Model); public union Vehicle(Car, Bicycle, Bus); Vehicle car = new Car("Tesla Model 3"); Console.WriteLine(car.Value); // Car { Model = Tesla Model 3 } Vehicle bike = new Bicycle("Giant Escape 3"); Console.WriteLine(bike.Value); // Bicycle { Model = Giant Escape 3 } Vehicle bus = new Bus("Volvo 9700"); Console.WriteLine(bus.Value); // Bus { Model = Volvo 9700 } Vehicle v = /* some vehicle here */; string model = v switch { Car c => c.Model, Bicycle bk => b.Model, Bus bs => bs.Model, }; The JavaUnion types do not exist in Java, although they can be somewhat emulated using sealed interfaces. // "Shape" can be thought of as a union of "Circle", "Rectangle", // and other types that implement "Shape" // we can explicitly restrict what is in the union using a sealed interface sealed interface Shape permits Circle, Rectangle {} record Circle(double radius) implements Shape {} record Rectangle(double width, double height) implements Shape {} class Example { double area(Shape s) { return switch (s) { case Circle(double r) -> Math.PI * r * r; case Rectangle(double w, double h) -> w * h; }; } } A class FooException extends RuntimeException { String name() { return "Foo"; } } class BarException extends RuntimeException { String name() { return "Bar"; } } void main() { try { throw Math.random() < 0.5 ? new FooException() : new BarException(); } catch (FooException | BarException e) { // e has type RuntimeException, the common supertype of FooException and BarException System.out.println(e); e.printStackTrace(); // System.out.println(e.name()); // Because there is no name() method in RuntimeException, this fails to compile } } PHPUnion types were introduced to PHP in PHP 8.0.[15] The values are implicitly "tagged" with a type by the language, and may be retrieved by class Example { private int|float $foo; public function squareAndAdd(float|int $bar): int|float { return $bar ** 2 + $this->foo; } } PythonSupport for type hints was introduced to Python in Python 3.5.[16] The new syntax for union types were introduced in Python 3.10.[17] from typing import Union class Example: foo: int = 0 # old style: def square_and_add(self, bar: Union[int, float]) -> Union[int, float]: return bar ** 2 + self.foo # new style: def square_and_add(self, bar: int | float) -> int | float: return bar ** 2 + self.foo TypeScriptUnion types are supported in TypeScript.[18] When TypeScript code is transpiled to JavaScript, all type-related information is lost.[19] This means that there is no one way to identify the type of a value at runtime as it appears in TypeScript. However, all JavaScript values are implicitly "tagged" with a type by the language, which may be retrieved using the function length(v: string | any[]): number { // Because both strings and arrays have a "length" property, // we can use it without having to figure out the actual type of v. return v.length; } function containsTheLetterA(v: string | string[] | number): boolean { // sometimes, it is important to know the exact type of a value. if (typeof v === "string") { return v.includes("a"); } else if (v instanceof Array) { // Because v is an Array, we want to check if any element includes the letter A. return v.some((element) => element.includes("a")); } else { // Because we know it isn't an array or string, it must be a number. // Numbers don't ever contain the letter a. return false; } } RustTagged unions in Rust use the enum Shape { Circle { radius: f64 }, Rectangle { width: f64, height: f64 }, } fn main() { let mut s = Shape::Circle { radius: 5.0 }; if let Shape::Circle { radius } = s { println!("s is a Circle with radius {radius}"); } s = Shape::Rectangle { width: 2.0, height: 3.0 }; } Untagged unions in Rust use the union Foo { bar: i32, baz: bool, } Reading from the fields of an untagged union results in undefined behavior if the data in the union is not valid as the type of the field, and thus requires an let x = Foo { bar: 10 }; let y = unsafe { x.bar }; // This will set y to 10, and does not result in undefined behavior. let z = unsafe { x.baz }; // This results in undefined behavior, as the value stored in x is not a valid bool. References
External links
| ||
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |