Structural Typing ================= ```Example from 1 languages: Python # Python's optional static type system features 2 kinds of structural types: from typing import Protocol class Clearable(Protocol): def clear(self): ... def print_and_clear(x: Clearable): print(x) x.clear() print_and_clear([1, 2, 3]) # OK because lists have a clear() method print_and_clear({1, 2, 3}) # OK because sets have a clear() method print_and_clear(1) # not OK because ints don't have a clear() method from typing import TypedDict class NameDict(TypedDict): first_name: str last_name: str class EmployeeDict(TypedDict): employee_id: int first_name: str last_name: str def greet(name: NameDict): print(f"Hello {name['first_name']} {name['last_name']}!") john: EmployeeDict = { "first_name": "John", "last_name": "Smith", "employee_id": 123 } # EmployeeDict is a (structural) subtype of NameDict even though there is no # explicit relation between them, so this passes type checking: greet(john) ``` ```Example from 1 languages: C++ // concepts use structural typing: #include <iostream> #include <string> using namespace std; // NOTE that concept implementations MUST be defined BEFORE the concept itself string toTypedJson(int x) { return "{\"type\": \"int\", \"value\": " + to_string(x) + "}"; } template <typename T> concept ToTypedJson = requires (T a) { {toTypedJson(a)} -> convertible_to<string>; }; template <ToTypedJson T> void printAsTypedJson(T x) { cout << toTypedJson(x) << endl; } int main() { printAsTypedJson(123); } ``` ```Example from 1 languages: TypeScript // https://www.typescriptlang.org/docs/handbook/type-compatibility.html // Subtype relations are structural for both interfaces and classes. // Interface example: interface CanCheckIncludes<T> { includes(x: T): boolean; } function logIfIncludes<T>(includer: CanCheckIncludes<T>, includee: T) { if (includer.includes(includee)) { console.log(includer); } } logIfIncludes("abc", "b"); logIfIncludes([1, 2, 3], 4); logIfIncludes(1, 1); // Fails typechecking, as numbers don't have includes() ``` ```Example from 1 languages: Scala // https://docs.scala-lang.org/scala3/reference/changed-features/structural-types.html#using-java-reflection-1 import scala.reflect.Selectable.reflectiveSelectable type Reversable[T] = { def reverse: T } def printReversed[T](x: Reversable[T]): Unit = { println(x.reverse) } printReversed("abc") printReversed(Array(1, 2, 3)) printReversed(1) // Doesn't compile because integers don't have a reverse method ``` * Languages *with* Structural Typing include Python, C++, TypeScript, Scala, OCaml * Languages *without* Structural Typing include JavaScript, C, Java, Bash, Rust, Kotlin * View all concepts with or missing a *hasStructuralTyping* measurement http://pldb.info/../lists/explorer.html#columns=rank~id~appeared~tags~creators~hasStructuralTyping&searchBuilder=%7B%22criteria%22%3A%5B%7B%22condition%22%3A%22null%22%2C%22data%22%3A%22hasStructuralTyping%22%2C%22origData%22%3A%22hasStructuralTyping%22%2C%22type%22%3A%22num%22%2C%22value%22%3A%5B%5D%7D%5D%2C%22logic%22%3A%22AND%22%7D missing http://pldb.info/../lists/explorer.html#columns=rank~id~appeared~tags~creators~hasStructuralTyping&searchBuilder=%7B%22criteria%22%3A%5B%7B%22condition%22%3A%22!null%22%2C%22data%22%3A%22hasStructuralTyping%22%2C%22origData%22%3A%22hasStructuralTyping%22%2C%22type%22%3A%22num%22%2C%22value%22%3A%5B%5D%7D%5D%2C%22logic%22%3A%22AND%22%7D with * Read more about Structural Typing on the web: 1. https://en.wikipedia.org/wiki/Structural_type_system 1. Built with Scroll v178.2.3