The textbooks explain this topic in sufficient detail, so this page exists to add further to the information already there.
This website also captures the informtaion very well: https://haoran-jie.github.io/Notes/ALCS/Chapter13.1_User-definedDataTypes/
While under the auspices of UDTs, this is a classification that applies to any and all data types, including UDTs.
A non-composite data type is a single data type that does not involve a reference to another type. They are usually built into a programming language. The key difference is that a non-composite cannot be broken down into parts in that it is a single-unit type. I.e. they are atomic.
Examples:
Integer (i.e. stores a single number)
Char
Date/Time
Floats
Boolean
Enumerated types
Pointers
Strings are in-between, as they do store characters, but each is formed as a single piece of data. It also depends on the language. C for example, only supports char and so a string is a composite UDT.
Composite data types are the opposite, in that they group related data, which can be homogeneous (the same type) or heterogeneous (different types), into a single, cohesive unit.
Examples:
Arrays
Records (struct)
Classes
Lists
Arrays
Tuples
Dictionaries
There is a lot of overlap between the two concepts, as you will see. A composite data type is a category of data types, while a user-defined type (UDT) is defined by its source. The two concepts often overlap, but they are not the same.
Composite Data Type (The Playlist)
A composite type is any data type that is a collection of other data. It's like a playlist on your favorite music app.
You don't create the playlist app, it's built into the system, just like arrays (int[]) and other collections are built into a programming language.
The playlist can hold lots of individual songs (the data items).
The songs themselves can be from different genres, but the playlist as a whole is a container for all of them.
Examples:
An array of high scores in a game. It holds a bunch of numbers, but the array itself is a composite type.
A string, which is a collection of individual characters.
User-Defined Type (The Custom Playlist)
A UDT is something you build yourself. It's not just a standard playlist, it's a playlist you meticulously curate and give a special name.
You created it, so it's a "user-defined" type. You used the tools the language gave you (class, struct) to build your own custom data structure.
This custom playlist has a specific name and rules that you set. For example, you might create a GamingPlaylist that is designed for a specific vibe or mood.
Your custom playlist is also a composite type because it holds a bunch of songs (individual data items).
How they relate:
Overlap: Most of the time, the things you create (UDTs) are composite. A class for a Player that holds a username, a score, and a level is both a UDT (you made it) and a composite type (it holds multiple pieces of data).
UDT, but not composite: You could also create a UDT that isn't a composite. For example, if you just gave a new name to an existing data type, like a special kind of integer that can only be positive. It's a UDT because you defined it, but it's not composite because it still only holds one value.
Composite, but not UDT: The basic, built-in arrays are composite, but they aren't UDTs because the programming language created them for you to use.
So, in short: a UDT is about who created it, and a composite type is about what it's made of. Most custom things you build are made of other things, so they are both.
A UDT exists to extend the data needs of the programmer by allowing customisable data types, built from primitives (those built into the language) and other UDTs.
Examples of UDTs:
Class/Object
Pointer (CAIE class this as a UDT, but many experts do not)
Set
Enumerated Type (Enum)
Record
Purpose of user-defined data types:
To create new data type (from existing data types)
To allow data types not available in a programming language to be constructed // To extend the flexibility of the programming language
Why user-defined data types are necessary:
No suitable data type is provided by the language used
The programmer needs to specify a new data type
… that meets the requirement of the application
State what is meant by user-defined data types:
Derived from one or more existing data types
Used to extend the built-in data types
Creates data types specific to applications
Enumerated
This is a data type used to store constant values. It is a list of possible values. It is user-defined and non-composite (stores only one value). The pseudocode guide lists the different way sthis can be used. It is important to note that the values are ordered. That is, their position within the list of possible values matters because you can do comparisons. E.g. storing the days of the week, you can do a check to see if the current day is less than or greater than another value. If enumToday > enumTarget then...
Pointers
A pointer is a variable that stores a memory address. That is, instead of storing the data, the pointer stores the address of the data.
Pointers are used to store the addresses of other variables or memory items. Pointers are very useful for another type of parameter passing, usually referred to as Pass By Address (think about ByRef when passing in parameters). Pointers are essential for dynamic memory allocation and behind the scenes, all languages use pointers when you create a variable. Remember, pointers are referenced as a data type (composite or non-composite type), because the language needs to know how many bytes of memory to read when dereferencing the pointer. We use @ to reference a pointer.
Once a pointer is declared, you can refer to the thing it points to, known as the target of the pointer, by "dereferencing the pointer". To do this, use the ^ (circumflex) operator.
Languages such as Python and VB.NET do not support pointers, as memory is tightly managed.
Structures are covered on page 60 in the VB.NET companion Booklet
Structures are covered on page 60 in the VB.NET companion Booklet