index.html (29912B)
1 <!DOCTYPE html> 2 <html lang="en"> 3 4 <head> 5 <title> 6 What is an Interface · Jack Mordaunt 7 </title> 8 <meta charset="utf-8"> 9 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 10 <meta name="color-scheme" content="light dark"> 11 12 13 14 15 <meta name="author" content="Jack Mordaunt"> 16 <meta name="description" content="Behavioral Polymorphism: The foundation of OOP."> 17 <meta name="keywords" content="blog,developer,personal,software,robust,performance,sovereign"> 18 19 20 21 <meta name="twitter:card" content="summary"> 22 <meta name="twitter:title" content="What is an Interface"> 23 <meta name="twitter:description" content="Behavioral Polymorphism: The foundation of OOP."> 24 25 <meta property="og:url" content="http://jackmordaunt.com/posts/what-is-an-interface/"> 26 <meta property="og:site_name" content="Jack Mordaunt"> 27 <meta property="og:title" content="What is an Interface"> 28 <meta property="og:description" content="Behavioral Polymorphism: The foundation of OOP."> 29 <meta property="og:locale" content="en"> 30 <meta property="og:type" content="article"> 31 <meta property="article:section" content="posts"> 32 <meta property="article:published_time" content="2025-08-01T06:26:18-03:00"> 33 <meta property="article:modified_time" content="2025-08-01T06:26:18-03:00"> 34 <meta property="article:tag" content="OOP"> 35 <meta property="article:tag" content="Go"> 36 <meta property="article:tag" content="Odin"> 37 <meta property="article:tag" content="Interface"> 38 39 40 41 42 <link rel="canonical" href="http://jackmordaunt.com/posts/what-is-an-interface/"> 43 44 45 <link rel="preload" href="/fonts/fa-brands-400.woff2" as="font" type="font/woff2" crossorigin> 46 <link rel="preload" href="/fonts/fa-regular-400.woff2" as="font" type="font/woff2" crossorigin> 47 <link rel="preload" href="/fonts/fa-solid-900.woff2" as="font" type="font/woff2" crossorigin> 48 49 50 51 52 <link rel="stylesheet" href="/css/coder.min.6445a802b9389c9660e1b07b724dcf5718b1065ed2d71b4eeaf981cc7cc5fc46.css" integrity="sha256-ZEWoArk4nJZg4bB7ck3PVxixBl7S1xtO6vmBzHzF/EY=" crossorigin="anonymous" media="screen" /> 53 54 55 56 57 58 59 60 61 62 <link rel="stylesheet" href="/css/coder-dark.min.a00e6364bacbc8266ad1cc81230774a1397198f8cfb7bcba29b7d6fcb54ce57f.css" integrity="sha256-oA5jZLrLyCZq0cyBIwd0oTlxmPjPt7y6KbfW/LVM5X8=" crossorigin="anonymous" media="screen" /> 63 64 65 66 67 68 69 70 <link rel="stylesheet" href="/css/custom.min.931a9d02d6f7655cd0cd50317fac1204e00c54ffd0232085acc957b2db5e1283.css" integrity="sha256-kxqdAtb3ZVzQzVAxf6wSBOAMVP/QIyCFrMlXstteEoM=" crossorigin="anonymous" media="screen" /> 71 72 73 74 75 76 77 <link rel="icon" type="image/svg+xml" href="/images/self-tiny-white.svg" sizes="any"> 78 <link rel="icon" type="image/png" href="/images/self-tiny-white.png" sizes="32x32"> 79 <link rel="icon" type="image/png" href="/images/self-tiny-white.png" sizes="16x16"> 80 81 <link rel="apple-touch-icon" href="/images/apple-touch-icon.png"> 82 <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon.png"> 83 84 <link rel="manifest" href="/site.webmanifest"> 85 <link rel="mask-icon" href="/images/safari-pinned-tab.svg" color="#5bbad5"> 86 87 88 89 90 91 92 93 <script defer data-domain="jackmordaunt.com" src="https://plausible.io/js/script.js"></script> 94 95 96 97 98 </head> 99 100 101 102 103 104 105 <body class="preload-transitions colorscheme-auto"> 106 107 <div class="float-container"> 108 <a id="dark-mode-toggle" class="colorscheme-toggle"> 109 <i class="fa-solid fa-adjust fa-fw" aria-hidden="true"></i> 110 </a> 111 </div> 112 113 114 <main class="wrapper"> 115 <nav class="navigation"> 116 <section class="container"> 117 118 <a class="navigation-title" href="http://jackmordaunt.com/"> 119 Jack Mordaunt 120 </a> 121 122 123 <input type="checkbox" id="menu-toggle" /> 124 <label class="menu-button float-right" for="menu-toggle"> 125 <i class="fa-solid fa-bars fa-fw" aria-hidden="true"></i> 126 </label> 127 <ul class="navigation-list"> 128 129 130 <li class="navigation-item"> 131 <a class="navigation-link " href="/posts/">Blog</a> 132 </li> 133 134 <li class="navigation-item"> 135 <a class="navigation-link " href="/about/">About</a> 136 </li> 137 138 <li class="navigation-item"> 139 <a class="navigation-link " href="/projects/">Projects</a> 140 </li> 141 142 <li class="navigation-item"> 143 <a class="navigation-link " href="/contact/">Contact</a> 144 </li> 145 146 <li class="navigation-item"> 147 <a class="navigation-link " href="/pay-with-bitcoin/">Pay</a> 148 </li> 149 150 151 152 </ul> 153 154 </section> 155 </nav> 156 157 158 <div class="content"> 159 160 <section class="container post"> 161 <article> 162 <header> 163 <div class="post-title"> 164 <h1 class="title"> 165 <a class="title-link" href="http://jackmordaunt.com/posts/what-is-an-interface/"> 166 What is an Interface 167 </a> 168 </h1> 169 </div> 170 <div class="post-meta"> 171 <div class="date"> 172 <span class="posted-on"> 173 <i class="fa-solid fa-calendar" aria-hidden="true"></i> 174 <time datetime="2025-08-01T06:26:18-03:00"> 175 August 1, 2025 176 </time> 177 </span> 178 <span class="reading-time"> 179 <i class="fa-solid fa-clock" aria-hidden="true"></i> 180 6-minute read 181 </span> 182 </div> 183 184 185 <div class="tags"> 186 <i class="fa-solid fa-tag" aria-hidden="true"></i> 187 <span class="tag"> 188 <a href="/tags/oop/">OOP</a> 189 </span> 190 <span class="separator">•</span> 191 <span class="tag"> 192 <a href="/tags/go/">Go</a> 193 </span> 194 <span class="separator">•</span> 195 <span class="tag"> 196 <a href="/tags/odin/">Odin</a> 197 </span> 198 <span class="separator">•</span> 199 <span class="tag"> 200 <a href="/tags/interface/">Interface</a> 201 </span></div> 202 203 </div> 204 </header> 205 206 <div class="post-content"> 207 208 <p><strong>Behavioral Polymorphism: The foundation of OOP.</strong></p> 209 <p>The <strong>interface</strong> is the foundation of OOP (Object Oriented Programming).</p> 210 <p>It provides <em>behavioral polymorphism</em>: constraining a type by its behaviours - 211 or more secifically, its method-set.</p> 212 <blockquote> 213 <p>A “method” (as termed in OOP langauges) is nothing more than a procedure who’s 214 first argument is a pointer to the object it is associated with. There is 215 nothing special about a method.</p></blockquote> 216 <p><strong>Definitions</strong></p> 217 <ul> 218 <li><strong>Poly</strong>: many</li> 219 <li><strong>Mono</strong>: singular</li> 220 <li><strong>Morphism</strong>: shape</li> 221 <li><strong>Polymorphism</strong>: having many shapes</li> 222 <li><strong>Monomorphism</strong>: having one shape</li> 223 </ul> 224 <p>Polymorphic refers to the ability to represent many shapes.</p> 225 <p><strong>Anology: Power Sockets</strong></p> 226 <p>You might have ten electrical appliances all completely different. 227 Toaster, microwave, blender. 228 The way they use the electricity are all different, but the power plug is the same. 229 The power socket provides a common interface that allows polymorphism with respect to the appliances. 230 As long as an appliance has a the correct plug, the power socket will accept it. 231 Thus the power socket is an interface that enables behavioral polymorphism.</p> 232 <p>Polymorphism in programing works the same way.</p> 233 <blockquote> 234 <p>In dynamically-typed programming every value is polymorphic, and only the <em>use</em> of the value will reveal whether the particular morphism is valid. 235 In statically-typed programming every value is monomorphic, and special types must be used to allow for polymorphism.</p></blockquote> 236 <p><strong>What is a shape anyway?</strong></p> 237 <p>In programming a shape is some definable characteristic about a value.</p> 238 <ul> 239 <li>At a low level: how are the fields represented in memory</li> 240 <li>At a high level: is it iterable, is it indexable, is it a reference, etc</li> 241 </ul> 242 <p>We abstract the low level up to the high level.</p> 243 <p>OOP languages often build in language-level native support for interfaces since 244 this kind of polymorphism is foundational to the OOP paradigm. In low level 245 languages like C you will typically achieve polymorphism through data layout: 246 using flexible structures and memory indirection.</p> 247 <p>Interfaces allow for polymorphism in statically-typed languages. 248 That is, they don’t require generics in the type-system to implement.</p> 249 <p>It is no coincidence that Java and Go started out statically-typed using interfaces. 250 Lacking parametric polymorphism, those languages often awkwardly relied on behavioral polymorphism.</p> 251 <h2 id="the-fat-pointer"> 252 The Fat Pointer 253 <a class="heading-link" href="#the-fat-pointer"> 254 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 255 <span class="sr-only">Link to heading</span> 256 </a> 257 </h2> 258 <p>This section applies to <em>runtime</em> interfaces, otherwise known as <em>dynamic dispatch</em>.</p> 259 <p>At the low level, an interface is nothing more than a <strong>fat pointer</strong>: a structure 260 containing a pair of pointers - one that points to the data, and the other that 261 points to a function that operates on the data.</p> 262 <p>This is all you need.</p> 263 <p><strong>Odin Example: Stream</strong></p> 264 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-odin" data-lang="odin"><span style="display:flex;"><span>Stream_Proc<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">::</span><span style="color:#6e7681"> </span><span style="color:#d2a8ff;font-weight:bold">#type</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">proc</span>(stream_data<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">rawptr</span>,<span style="color:#6e7681"> </span>mode<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span>Stream_Mode,<span style="color:#6e7681"> </span>p<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span>[]<span style="color:#ff7b72">byte</span>,<span style="color:#6e7681"> </span>offset<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">i64</span>,<span style="color:#6e7681"> </span>whence<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span>Seek_From)<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">-></span><span style="color:#6e7681"> </span>(n<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">i64</span>,<span style="color:#6e7681"> </span>err<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span>Error)<span style="color:#6e7681"> 265 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> 266 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>Stream<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">::</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">struct</span><span style="color:#6e7681"> </span>{<span style="color:#6e7681"> 267 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span>procedure<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span>Stream_Proc,<span style="color:#6e7681"> 268 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span>data<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">rawptr</span>,<span style="color:#6e7681"> 269 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>}<span style="color:#6e7681"> 270 </span></span></span></code></pre></div><p>This struct contains a pointer to a procedure and a pointer to the data. 271 It can be used to represent any kind of streaming operation: reading, writing, flushing, closing, etc, on any type.</p> 272 <p>Each specialized type (file, buffer, http body) simply needs to map itself to this shape and it can integrate with streaming logic.</p> 273 <p><strong>Converting a Buffer to a Stream</strong></p> 274 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-odin" data-lang="odin"><span style="display:flex;"><span>buffer_to_stream<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">::</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">proc</span>(b<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">^</span>Buffer)<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">-></span><span style="color:#6e7681"> </span>(s<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span>io.Stream)<span style="color:#6e7681"> </span>{<span style="color:#6e7681"> 275 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span>s.data<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#6e7681"> </span>b<span style="color:#6e7681"> 276 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span>s.procedure<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#6e7681"> </span>_buffer_proc<span style="color:#6e7681"> 277 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span><span style="color:#ff7b72">return</span><span style="color:#6e7681"> 278 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>}<span style="color:#6e7681"> 279 </span></span></span></code></pre></div><p>It simply builds the stream struct using a pointer to the buffer sets the correct procedure.</p> 280 <p>To achieve behavioral polymorphism all you need is a common 281 representation (the fat pointer) that all specialized types can conform to.</p> 282 <p><strong>Usage Example: io.Reader</strong></p> 283 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-odin" data-lang="odin"><span style="display:flex;"><span><span style="color:#ff7b72">package</span><span style="color:#6e7681"> </span>main<span style="color:#6e7681"> 284 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> 285 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span><span style="color:#ff7b72">import</span><span style="color:#6e7681"> </span><span style="color:#a5d6ff">"core:bytes"</span><span style="color:#6e7681"> 286 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span><span style="color:#ff7b72">import</span><span style="color:#6e7681"> </span><span style="color:#a5d6ff">"core:io"</span><span style="color:#6e7681"> 287 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span><span style="color:#ff7b72">import</span><span style="color:#6e7681"> </span>os<span style="color:#6e7681"> </span><span style="color:#a5d6ff">"core:os/os2"</span><span style="color:#6e7681"> 288 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> 289 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>main<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">::</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">proc</span>()<span style="color:#6e7681"> </span>{<span style="color:#6e7681"> 290 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span><span style="color:#8b949e;font-style:italic">// Assign both the file and buffer reader to this to show they are the same shape. 291 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span><span style="color:#6e7681"> </span>reader<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span>io.Reader<span style="color:#6e7681"> 292 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> 293 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span><span style="color:#8b949e;font-style:italic">// Scratch is just a buffer to read into. 294 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span><span style="color:#6e7681"> </span>scratch<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">:=</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">make</span>([<span style="color:#ff7b72">dynamic</span>]<span style="color:#ff7b72">byte</span>,<span style="color:#6e7681"> </span>1024<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">*</span><span style="color:#6e7681"> </span>1024)<span style="color:#6e7681"> 295 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> 296 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span><span style="color:#8b949e;font-style:italic">// Open a file and make a reader for it. 297 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span><span style="color:#6e7681"> </span>file,<span style="color:#6e7681"> </span>_<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">:=</span><span style="color:#6e7681"> </span>os.open(<span style="color:#a5d6ff">"file"</span>)<span style="color:#6e7681"> 298 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span>reader<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#6e7681"> </span>os.to_reader(file)<span style="color:#6e7681"> 299 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> 300 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span><span style="color:#8b949e;font-style:italic">// This call is operating on the file. 301 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span><span style="color:#6e7681"> </span>io.read_full(reader,<span style="color:#6e7681"> </span>scratch[<span style="color:#ff7b72;font-weight:bold">:</span>])<span style="color:#6e7681"> 302 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> 303 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span><span style="color:#8b949e;font-style:italic">// Allocate a byte buffer and make a reader for it. 304 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span><span style="color:#6e7681"> </span>buf<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span>bytes.Buffer<span style="color:#6e7681"> 305 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span>bytes.buffer_init(<span style="color:#ff7b72;font-weight:bold">&</span>buf,<span style="color:#6e7681"> </span><span style="color:#ff7b72">make</span>([<span style="color:#ff7b72">dynamic</span>]<span style="color:#ff7b72">byte</span>,<span style="color:#6e7681"> </span>1024<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">*</span><span style="color:#6e7681"> </span>1024)[<span style="color:#ff7b72;font-weight:bold">:</span>])<span style="color:#6e7681"> 306 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span>reader<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#6e7681"> </span>bytes.buffer_to_stream(<span style="color:#ff7b72;font-weight:bold">&</span>buf)<span style="color:#6e7681"> 307 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> 308 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span><span style="color:#8b949e;font-style:italic">// This call is operating on the buffer. 309 </span></span></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"></span><span style="color:#6e7681"> </span>io.read_full(reader,<span style="color:#6e7681"> </span>scratch[<span style="color:#ff7b72;font-weight:bold">:</span>])<span style="color:#6e7681"> 310 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>}<span style="color:#6e7681"> 311 </span></span></span></code></pre></div><p>In this example, the <code>io.Reader</code> is the interface. 312 The <code>bytes.Buffer</code> and the <code>os.File</code> are the specialized types can map to it. 313 <code>io.read_full</code> can therefore operate on any type that can map to an <code>io.Reader</code>.</p> 314 <p>Behavioral polymorphism is achieved by matching shapes. No runtime or type system 315 support needed.</p> 316 <h2 id="the-vtable"> 317 The VTable 318 <a class="heading-link" href="#the-vtable"> 319 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 320 <span class="sr-only">Link to heading</span> 321 </a> 322 </h2> 323 <p><strong>Virtual Table</strong></p> 324 <p>The Odin core prefers to (but doesn’t require) to use a VTable-of-one. A single 325 procedure that can handle any possible operation of the interface.</p> 326 <p>This keeps the shape a simple fat-pointer, making it easier to construct and 327 more compact in memory.</p> 328 <p>The traditional way (e.g., C++) assigns each method its own entry in the VTable. 329 This means the pointer to the procedure becomes a pointer to a table of procedures.</p> 330 <p>Each entry into the virtual table represents a single method.</p> 331 <p><strong>Example: Multi-Method VTable</strong></p> 332 <div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-odin" data-lang="odin"><span style="display:flex;"><span>FileInterface<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">::</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">struct</span><span style="color:#6e7681"> </span>{<span style="color:#6e7681"> 333 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span>vtable<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span>FileVTable,<span style="color:#6e7681"> 334 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span>data<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">rawptr</span>,<span style="color:#6e7681"> 335 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>}<span style="color:#6e7681"> 336 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> 337 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>FileVTable<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">::</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">struct</span><span style="color:#6e7681"> </span>{<span style="color:#6e7681"> 338 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span>read<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">proc</span>(data<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">rawptr</span>,<span style="color:#6e7681"> </span>p<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">byte</span>[])<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">-></span><span style="color:#6e7681"> </span>(n<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">int</span>,<span style="color:#6e7681"> </span>err<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span>Error),<span style="color:#6e7681"> 339 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span>write<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">proc</span>(data<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">rawptr</span>,<span style="color:#6e7681"> </span>p<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">byte</span>[])<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">-></span><span style="color:#6e7681"> </span>(n<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">int</span>,<span style="color:#6e7681"> </span>err<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span>Error),<span style="color:#6e7681"> 340 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"> </span>close<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">proc</span>(data<span style="color:#ff7b72;font-weight:bold">:</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">rawptr</span>)<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">-></span><span style="color:#6e7681"> </span>Error,<span style="color:#6e7681"> 341 </span></span></span><span style="display:flex;"><span><span style="color:#6e7681"></span>}<span style="color:#6e7681"> 342 </span></span></span></code></pre></div><p>As you can see, each additional method increases the memory required.</p> 343 <p>There is no <strong>logical</strong> difference between the two representations, only structural.</p> 344 <h2 id="windows-com"> 345 Windows COM 346 <a class="heading-link" href="#windows-com"> 347 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 348 <span class="sr-only">Link to heading</span> 349 </a> 350 </h2> 351 <p>To see how far you can take behavioral polymorphism, look no further than Windows COM.</p> 352 <p>COM is an API and ABI implemented entirely around VTables — to the exclusion of all else.</p> 353 <p>You can call and implement a COM object in <em>any</em> langauge, as long as the VTable 354 representation and behaviour of the methods are correct.</p> 355 <p>The point is not to teach COM, but to illustrate that interfaces are just VTables. 356 Behavioral polymorphism is a simple low-level idea that is abstracted into OOP 357 languages as a first class language feature.</p> 358 <p>Windows COM also shows how flexible the humble VTable can be — it allows a 359 polyglot object system. Fascinating, but probably not something to aspire to.</p> 360 <h2 id="the-cost"> 361 The Cost 362 <a class="heading-link" href="#the-cost"> 363 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 364 <span class="sr-only">Link to heading</span> 365 </a> 366 </h2> 367 <p>Interfaces are simple structures, but they are not free.</p> 368 <ul> 369 <li><strong>Size</strong>: at a minimum, two pointers.</li> 370 <li><strong>Growth</strong>: VTable size grows with number of methods.</li> 371 <li><strong>Indirection</strong>: Runtime method calls are indirect.</li> 372 </ul> 373 <p>In large dynamic arrays, interface overhead can add up:</p> 374 <ul> 375 <li><strong>Memory cost</strong></li> 376 <li><strong>Cache pressure</strong> due to pointer indirection</li> 377 <li><strong>Fragmented memory</strong> for the actual data</li> 378 </ul> 379 <p>With a more sophisticated type system, interfaces can be monomorphised at 380 compile-time (i.e., static dispatch).</p> 381 <p>This eliminates runtime cost but increases compile-time complexity.</p> 382 <h2 id="conclusion"> 383 Conclusion 384 <a class="heading-link" href="#conclusion"> 385 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 386 <span class="sr-only">Link to heading</span> 387 </a> 388 </h2> 389 <p>Interfaces allow behavioral polymorpshim.</p> 390 <p>The classic runtime interface is implemented as a simple fat-pointer shape.</p> 391 <p>Concrete types only need to satisfy the shape of the interface and they can be used anywhere 392 that interface is used.</p> 393 <p>Interfaces are not scary, and not hard to implement at the low level. They are also not a 394 substitute for parametric polymorphism as I’m sure many Go programmers are well aware.</p> 395 396 </div> 397 398 399 <footer> 400 401 402 403 404 405 406 407 408 409 410 </footer> 411 </article> 412 413 414 </section> 415 416 </div> 417 418 <footer class="footer"> 419 <section class="container"> 420 © 421 422 2025 423 Jack Mordaunt 424 · 425 426 Powered by <a href="https://gohugo.io/" target="_blank" rel="noopener">Hugo</a> & <a href="https://github.com/luizdepra/hugo-coder/" target="_blank" rel="noopener">Coder</a>. 427 428 </section> 429 </footer> 430 431 </main> 432 433 434 435 436 437 <script src="/js/coder.min.6ae284be93d2d19dad1f02b0039508d9aab3180a12a06dcc71b0b0ef7825a317.js" integrity="sha256-auKEvpPS0Z2tHwKwA5UI2aqzGAoSoG3McbCw73gloxc="></script> 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 </body> 479 </html>