- Basic compound data structures (product types). Most imperative languages don't have sum types, which is the root of a lot of problems in that style
- Interfaces (some more enlightened imperative languages separate these out) and the adapter/impl/typeclass/what-have-you that ties together an implementation of that interface for that datastructure
- Mutable references - some way of associating an identity or name with a value that can be switched for a different value accessed via the same identity/name
What I can't tell you is if data types in computer programs are related to type theory.
When I hear “type theory” - I think Martin-Löf, Girard’s Proofs and Types, Curry-Howard, etc.
Which is not a “theory of programming language types” - although the subjects are not completely isolated from each other.
Then again, it’s been decades since I actually studied this stuff and haven’t really followed either subject since.
As far as the latter is concerned (programming language type systems), as an engineer, I’ve seen nothing in mainstream programming languages that advances the state-of-the-art compared to what was known back in the 1980s - when Hindley-Milner became mainstream and Luca Cardelli wrote the seminal survey papers on the subject.
I'm far from an expert on this, but my understanding is that there is some relation between the two notions. But I couldn't even begin to quantify the strength of that relation, or explain any of the details. Which is sort of what led me down this path in the first place. Some random thing I read got me thinking that deeper knowledge of type theory could be useful from an AI perspective, and that led me down the rabbit hole of looking for info on type theory. And from what I've read so far, it seems like type theory (more so than, say, set theory, or maybe even category theory) is "closer" in some sense to computer science and does in some sense relate to how types (as used in programming languages) can be constructed and reasoned about.
I have a lot more to learn, needless to say. :-)
- a factory for objects, that hides some internal state of the object;
- a static construct that gives a name to some (‘public’) subset of the behaviour of those objects, and which a type-checker can then use to ensure that the use of the objects adheres to the intended contract.
They're both mechanisms for encapsulation of internal behaviour (that may change at any time) while providing a blessed public API that you promise will stay the same (or at least only change in certain ways, under a strict discipline like semver or ‘we'll tell you on the mailing list’). The difference is that the former is runtime (dynamic) behaviour, while the latter is compile-time (static) behaviour. The former maps to functions (or, with state, closures), not types, in functional languages (see ‘objects are a poor man's closures, and vice versa’ [1]), and the latter… is types :) The same typing concept that ensures correct interaction with objects can also be used to ensure correct interaction with functions or other data types, though since functional languages are easier to type than OO languages strictly-typed functional languages tend to have stronger type systems that capture more properties, like effects.
[1]: https://people.csail.mit.edu/gregs/ll1-discuss-archive-html/...
From one perspective, there's a spectrum imperative <-> procedural <-> OOP <-> functional that is about how tightly scoped state changes are. In that view, functional languages are just the natural next step: if the whole point of OOP is to scope state, a functional language is just an OOP language with _even more_ tightly scoped state. The philosophy (uncontrolled state changes are scary and hard to reason about: add language constructs that allow the reader to see at a glance how far they have to look for the knock-on effects of a given state changes) is the same, just the implementation is different.
I suggest you look at simply typed lambda calculus, it gives a basic rationalization of types in functional programming.
Non-OOP statically typed languages are basically just saying "ok that's fine, but there's no need to attach state or behaviour to types".