1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 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 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556
|
# Interoperability between Swift and C++
# ⚠️ Warning: document is out of date. ⚠️
**This document has not had significant updates in the last three years. The goals and design outlined here do not necessarily reflect those established by the C++ Interop Work Group. For an up-to-date document, please see [the Forward Vision document](https://github.com/apple/swift-evolution/blob/main/visions/using-swift-from-c%2B%2B.md).**
[** ‼️ Additionally, the official C++ interoperability documentation is live at Swift.org and provides an up-to-date guide for mixing Swift and C++ ‼️ **](https://www.swift.org/documentation/cxx-interop/)
This document discusses the design and tradeoffs for bidirectional API-level
interoperability between Swift and C++.
Assumptions:
* We can make changes to the Swift language and the standard library.
* The proposed changes must fit Swift's goals and philosophy. In other words,
the proposed changes must have a reasonable chance to be accepted by the
Swift community. For example, a change that requires an ABI break on Apple
platforms is a non-starter.
* Forking the Swift language or standard library, or creating a dialect
without a fork (and therefore, being able to make radical changes to Swift's
goals, philosophy, safety, or ergonomics) are not interesting options, and
therefore, are not considered or discussed.
* We can make limited changes to the C++ code, toolchain, standard library
implementation, and runtime environment.
* The cost of such changes must be taken into account. Changes that require an
ABI break for C++ might be interesting for users who control the complete
toolchain, but are non-starters for the community at large; therefore, such
changes can only be considered an optimization. Changes that require
significant manual work on existing C++ code by end users can also be
considered only as optimizations or improvements for ergonomics.
- [Goals](#goals)
- [Current state of art: importing C code into Swift](#current-state-of-art-importing-c-code-into-swift)
- [Importing C++ APIs into Swift](#importing-c-apis-into-swift)
* [Names, identifiers and keywords](#names-identifiers-and-keywords)
* [Functions](#functions)
+ [Non-const pointer and reference parameters](#non-const-pointer-and-reference-parameters)
+ [Const reference parameters](#const-reference-parameters)
+ [Mapping overload sets](#mapping-overload-sets)
+ [Inline functions](#inline-functions)
* [Namespaces and modules](#namespaces-and-modules)
+ [The "std" namespace](#the-std-namespace)
* [Structs and classes](#structs-and-classes)
+ [Mapping the type itself and its special member functions](#mapping-the-type-itself-and-its-special-member-functions)
+ [Special member functions with incorrect semantics](#special-member-functions-with-incorrect-semantics)
+ [Special member functions that throw exceptions](#special-member-functions-that-throw-exceptions)
+ [Precise destruction semantics](#precise-destruction-semantics)
+ [Member functions that return inner pointers](#member-functions-that-return-inner-pointers)
+ [Differences in move semantics between C++ and Swift](#differences-in-move-semantics-between-c-and-swift)
+ [Move-only C++ classes](#move-only-c-classes)
+ [Move-only C++ classes: mapping in Swift 5](#move-only-c-classes-mapping-in-swift-5)
+ [Move-only C++ classes: mapping to move-only Swift types (in future Swift versions)](#move-only-c-classes-mapping-to-move-only-swift-types-in-future-swift-versions)
+ [Non-destructive moves](#non-destructive-moves)
+ [Non-movable C++ classes](#non-movable-c-classes)
+ [Member functions](#member-functions)
+ [Const-qualified member functions in C++ classes](#const-qualified-member-functions-in-c-classes)
+ [Volatile-qualified member functions](#volatile-qualified-member-functions)
+ [Ref-qualified member functions](#ref-qualified-member-functions)
+ [Final functions](#final-functions)
+ [Getters and setters](#getters-and-setters)
+ [Pointers to members](#pointers-to-members)
+ [Virtual member functions](#virtual-member-functions)
+ [Inherited APIs](#inherited-apis)
+ [Conversions between derived and base classes](#conversions-between-derived-and-base-classes)
+ [Subclassing C++ classes in Swift](#subclassing-c-classes-in-swift)
+ [Making C++ classes conform to Swift protocols](#making-c-classes-conform-to-swift-protocols)
* [Enums](#enums)
* [Templates](#templates)
+ [Function templates](#function-templates)
+ [Function templates: import as Swift generic functions](#function-templates-import-as-swift-generic-functions)
+ [Function templates: allow to specify template arguments](#function-templates-allow-to-specify-template-arguments)
+ [Function templates: calls to specific specializations](#function-templates-calls-to-specific-specializations)
+ [Function templates: calls with generic type parameters](#function-templates-calls-with-generic-type-parameters)
+ [Function templates: importing as real generic functions](#function-templates-importing-as-real-generic-functions)
+ [Class templates](#class-templates)
+ [Class templates: importing full class template instantiations](#class-templates-importing-full-class-template-instantiations)
+ [Class templates: importing specific specializations](#class-templates-importing-specific-specializations)
+ [Class templates: using with generic type parameters](#class-templates-using-with-generic-type-parameters)
+ [Class templates: using in generic code through a synthesized protocol](#class-templates-using-in-generic-code-through-a-synthesized-protocol)
+ [Class templates: importing as real generic structs](#class-templates-importing-as-real-generic-structs)
+ [Mapping SFINAE](#mapping-sfinae)
+ [Variadic templates](#variadic-templates)
+ [Non-type template parameters](#non-type-template-parameters)
+ [Template template parameters](#template-template-parameters)
* [Overloaded operators](#overloaded-operators)
* [`operator*`, `operator->`](#operator-star-operator-arrow)
* [`operator[]`](#operator-square-brackets)
* [`operator()`](#operator-parentheses)
* [Literal operators](#literal-operators)
* [Exceptions](#exceptions)
* [Atomics](#atomics)
* [Importing non-const pointer as extra return values](#importing-non-const-pointer-as-extra-return-values)
- [Enhancing C++ API mapping into Swift with bridging](#enhancing-c-api-mapping-into-swift-with-bridging)
* [Bridging data types with different memory layout](#bridging-data-types-with-different-memory-layout)
* [Bridging: behind the scenes](#bridging-behind-the-scenes)
* [Bridging does not work in every context](#bridging-does-not-work-in-every-context)
* [Bridging `std::function`](#bridging-std-function)
* [Bridging `std::string`](#bridging-std-string)
* [Bridging `std::vector`](#bridging-std-vector)
* [Bridging `std::set`, `std::map`](#bridging-std-set-std-map)
* [Bridging `std::unordered_set`, `std::unordered_map`](#bridging-std-unordered-set-std-unordered-map)
* [Bridging `std::tuple`, `std::pair`](#bridging-std-tuple-std-pair)
* [Bridging `std::span`](#bridging-std-span)
* [Standard C++ containers in general](#standard-c-containers-in-general)
* [Custom C++ containers](#custom-c-containers)
* [Bridging `absl::flat_hash_{set,map}`, `absl::node_hash_{set,map}`](#bridging-absl-hash-set-map)
- [Enhancing C++ API mapping into Swift with annotations](#enhancing-c-api-mapping-into-swift-with-annotations)
* [Annotation workflow](#annotation-workflow)
* [Tooling to infer nullability annotations](#tooling-to-infer-nullability-annotations)
* [APIs that take a pointer and count](#apis-that-take-a-pointer-and-count)
- [Current state of art: importing Swift code into C](#current-state-of-art-importing-swift-code-into-c)
- [Importing Swift APIs into C++](#importing-swift-apis-into-c)
* [Resilient types](#resilient-types)
- [Forum discussions](#forum-discussions)
# Goals
What are the properties of a good interoperability layer? Exercising
interoperability is not in itself a goal of any Swift or C++ user. Therefore,
for API users interoperability should be maximally transparent in all aspects:
API design and ergonomics, editor integration and tooling, and performance. For
API vendors, interoperability should not be a significant extra burden, while
allowing API vendors to own and curate the imported API surface. Let's discuss
what these points mean.
**API design and ergonomics.** Ideally, users working in Swift should not feel
any difference between native Swift APIs and imported C++ APIs.
For example, while it is possible to write a custom hashtable in Swift, it is
done extremely rarely, and most code uses the vocabulary types `Set` and
`Dictionary`. Therefore, if C++ APIs that used `std::unordered_map` or
`flat_hash_map` types, when imported in Swift, would continue using those C++
map types, they would look weird and foreign in Swift. Idiomatic Swift code that
uses `Set` and `Dictionary` will have to convert the data into these foreign
hashtable types before calling imported C++ APIs.
As another example, C++ functions often receive values by const reference or by
const pointer. Semantically, the closest equivalent in Swift is `UnsafePointer`.
However, `UnsafePointer` is not as common in Swift as const references are in
C++; it is not idiomatic for Swift APIs to accept `UnsafePointer` outside of a
couple exceptional situations (for example, implementations of low-level
facilities, performance-sensitive code, etc.) Therefore, if C++ APIs, when
imported in Swift, would use `UnsafePointer` a lot, they would look weird and
foreign in Swift. Imported C APIs, when they are not operating on Objective-C
types, already use `UnsafePointer` a lot, and look non-idiomatic because of
that. Swift provides some affordances that make calling them easier.
**Editor integration and tooling** should transparently support code in both
languages. To the extent possible, all editor operations should "see through"
the interop. For example, if the user invokes the "rename function" refactoring,
it should rename all definitions, declarations, and usages across Swift and C++
code. This goal has been largely achieved for Swift/Objective-C interop, and we
are planning to rely on the same mechanisms for Swift/C++ interop.
**Performance.** C++ APIs, when used from Swift, ideally, should have
performance characteristics identical to when they are used from C++.
**Interop must not be a burden for API vendors.** Enabling Swift code to call a
certain C++ library should create minimal burden for the owners of that C++
library. Ideally, it should be possible without any involvement of the owners.
For example, requiring the API owners to create an API description file (like in
CLIF for Python), or a glue layer (like in JNI for Java) is a significant
burden. Most API owners are not going to do it without specific requests from
users, and even when such request is received, many API owners will carefully
consider if they want to take on maintenance of this extra file.
It may be possible to allow users to do the work necessary to expose a C++
library to Swift, however, that is not a great option either. A C++ library
might end up with multiple (incompatible) bindings of varying quality, covering
different parts of the API. In addition, the owner of the API loses control of
the API surface.
**Allow API vendors to own and curate the imported API surface.** While the
minimal amount of work to expose a C++ library to Swift should be ideally "none"
(it should just work), API vendors should own the Swift API surface of their C++
libraries, and should be able to adjust it where the automated interop is not
satisfactory.
**Tension and conflicts between goals.** These goals are conflicting. For
example, API ergonomics are in conflict with performance: we can provide a more
ergonomic API if we automatically bridge C++ types to corresponding Swift
vocabulary types at the API boundary, however, these type conversions will cost
CPU cycles. The solutions will be designed on a case by case basis: sometimes,
we will pick one side of the tradeoff, sometimes we will pick one side but allow
the user to override the default, and sometimes we will add multiple facilities
that pick different sides, forcing the user to choose.
# Current state of art: importing C code into Swift
Swift/C++ interoperability builds on top of the Swift/C interoperability, so it
helps to be familiar with [Swift's strategy for importing C
modules](../HowSwiftImportsCAPIs.md).
# Importing C++ APIs into Swift
Now let's talk about extending existing rules to handle C++.
## Names, identifiers and keywords
C++ allows defining names that are not identifiers:
* Destructors
* Overloaded operators
* Literal operators
Member functions with non-identifier names are discussed in the section about
classes. Other constructs are discussed in their respective sections.
## Functions
### Non-const pointer and reference parameters
In C++, there are no language requirements for pointers passed as function
arguments. For example, given a function signature like this:
```c++
void increment(int *value);
```
C++ as a language poses no requirements for `value` to live long enough during
the function call, or even that `value` points to valid memory when the
function is called; `value` can be null or it can be an invalid (for example,
freed) pointer. There are also no requirements about the memory pointed to by
`value` being initialized, or valid to dereference without data races. Pointers
are also allowed to alias other memory, as long as the types are compatible.
Pointers also don't imply anything about ownership or non-ownership.
Rules in C++ about references are a bit tighter, but not much. The only
differences are that a reference can't be null, and that it must be bound to a
valid object when it is initially created.
In practice, engineers working in C++ often make the following assumptions about
third-party APIs, even though these properties are not guaranteed by the
language, and are often not explicitly documented by the API:
- All pointers passed to a function are valid to dereference.
- Almost all pointers passed to a function remain valid to dereference while the
function is running.
- Almost all pointers passed to a function are valid to dereference without data
races.
- Almost all pointers passed to a function point to initialized data. Passing a
pointer to uninitialized memory and expecting the function to initialize it
happens occasionally, but it is not common.
- Often enough, pointers passed to a function are not null.
- Often enough, pointers of different types don't alias each other's subobjects.
- Almost all `const &T` parameters are semantically equivalent to passing `T` by
value.
In Swift, passing unsafe pointers as function arguments is not idiomatic.
Idiomatic code passes structs by value, and classes by reference. `inout`
parameters in Swift allow functions to read and modify storage specified by the
caller. The argument for the `inout` parameter must be a storage reference
expression.
```swift
func increment(_ value: inout Int) {
value += 1
}
struct TwoInts {
var x: Int = 0
var y: Int = 0
}
func caller() {
var ints = TwoInts()
increment(&ints.x)
// ints.x is 1
// ints.y is 0
}
```
To understand the constraints that Swift puts on `inout` parameters, let's take
a look at the mental model for introduced in the [Ownership
manifesto](OwnershipManifesto.md) and in [SE-0176 Enforce Exclusive Access to
Memory](https://github.com/apple/swift-evolution/blob/main/proposals/0176-enforce-exclusive-access-to-memory.md).
When the caller binds a storage reference to an `inout` parameter, it starts a
non-instantaneous access to the whole value that occupies the storage. This
access ends when the callee returns. Overlapping accesses are not allowed, and
therefore, while an `inout` parameter is live, original value may not be
accessed.
(Note that before the ownership manifesto, `inout` parameters were explained in
terms of a different model that might be easier to understand. Nevertheless,
both models are equivalent. The old model stated that on function entry, the
value is moved from the caller-specified storage reference into the `inout`
parameter, and moved from the `inout` parameter back into the original storage
on function exit. During the execution of the function, the original storage
remains uninitialized, and therefore, the whole value that occupied that storage
remains inaccessible until the function returns.)
In practice, `inout` parameters are implemented as passing a pointer to the
storage that should be mutated, while maintaining behavior identical to the
models explained above. As a consequence of these models, `inout` parameters
provide the following guarantees:
- the memory backing an `inout` parameter is valid to access throughout the
execution of a function.
- since `inout` parameters are not pointers, there is no such thing as "null
`inout` parameter".
- `inout` parameters are valid to read and modify throughout the execution of
a function without data races, unless the function itself has shared the
parameter with multiple threads.
- `inout` are backed by initialized memory on function entry and function exit
(an implication of the copy-in/copy-out semantics). Destroying the object in
`inout` requires using unsafe constructs. Therefore, in safe Swift `inout`
parameters are backed by initialized memory throughout function execution.
- `inout` parameters don't alias each other or any other values that program is
allowed to access at that point. Remember that the original value that is
bound to an `inout` parameter is inaccessible for the duration of the `inout`
binding.
In practice, non-const pointers and references in function parameters are most
often used for the same purpose as Swift's `inout`, so it is desirable to map
them to each other.
```c++
// C++ header.
void incrementBoth(int *value1, int *value2);
```
```swift
// C++ header imported in Swift (possible mapping).
func incrementBoth(_ value1: inout Int, _ value2: inout Int)
```
The `incrementBoth` function imported like this has more restrictions in Swift
than in C++ (for example, arguments may not alias). Calling this C++ function
from Swift does not create a new kind of safety issues in Swift, because a
language with more restrictions calls a language with fewer restrictions. From
the API point of view, it should not be a problem either, unless the caller
needs to pass arguments that alias (Swift's enforcement of exclusivity will
prevent that).
Based on the comparison above, it looks like Swift's `inout` provides strictly
more guarantees than C++'s non-const pointers and references. Therefore, it is
not safe to map them to each other in all cases. For example, we can't apply
this mapping when Swift is implementing a function exposed to C++, for example:
```c++
// C++ header.
class Incrementer {
public:
virtual void incrementBoth(int *value1, int *value2) = 0;
};
```
```swift
// C++ header imported in Swift (possible mapping).
protocol Incrementer {
func incrementBoth(_ value1: inout Int, _ value2: inout Int)
}
struct MyIncrementer: Incrementer {
func incrementBoth(_ value1: inout Int, _ value2: inout Int) {
// The language requires that `value1` and `value2` don't alias.
}
}
```
It would be unsafe to expose an Swift implementation of
`Incrementer.incrementBoth` through the C++ signature, unless the C++ function
already has Swift-like preconditions for pointer arguments. For true inout
parameters in C++, those preconditions should in fact hold, even if the C++
function does not formally document them.
### Const reference parameters
In C++, const references in function arguments are most often used to avoid
copying objects passed to functions. Swift solves this problem in two ways:
- by providing language features that allow the engineer to introduce
indirections (for example, reference types, existential types, indirect enum
cases, tools for defining copy-on-write types),
- by automatically passing large arguments indirectly without copying them,
where possible.
It is not feasible to automatically map C++ const references to Swift-specific
indirections like class types, because that would require changing the memory
layout through non-trivial bridging.
**Option 1: Import `const T&` as `UnsafePointer<T>`.**
We can easily map C++ const references in function parameters to
`UnsafePointer<T>` in Swift, however, the resulting APIs will not look
idiomatic. They will be usable from Swift, because Swift code can make an unsafe
pointer with the `&` operator, however, it can only be applied to mutable
storage locations. Therefore, more variables will be mutable in Swift than
necessary. Furthermore, to make some values mutable, the code will need to
make a copy that will be stored in a mutable variable -- defeating the point of
the C++ API taking a const reference.
```c++
void printInt(const int &value);
```
```swift
// C++ header imported in Swift.
func printInt(_ value: UnsafePointer<Int>)
```
```swift
// Usage example.
func caller() {
var x = 42
printInt(&x) // OK
let y = 42
printInt(y) // error: type mismatch: `Int` is not an `UnsafePointer<Int>`
printInt(&y) // error: can't apply `&` to an immutable value
}
```
**Improvement for option 1: Allow using `&` on immutable values.**
To eliminate the extra copies that the code would have to perform to make some
values mutable, we could extend the Swift language to allow applying `&` to
immutable values, producing an `UnsafePointer<T>`.
```swift
// Usage example.
void caller() {
let x = 42
printInt(&x) // OK
}
```
**Option 2: Import `const T&` as `T`.**
A more ergonomic approach would be to import C++ const references to value types
as values, but still use a by-reference calling convention behind the scenes.
```c++
void printInt(const int &value);
```
```swift
// C++ header imported in Swift.
func printInt(_ value: Int)
```
```swift
// Usage example.
func caller() {
let x = 42
printInt(y) // OK
}
```
The imported `printInt` function that takes an `Int` by value would be a thunk
that calls the actual C++ entry point that takes an `Int` by a const reference.
A mandatory optimization pass would inline that thunk into its callers, and
eliminate the copies that now became unnecessary.
It is important to understand that this approach only works in cases where the
compiler can insert a thunk. Here's an example where the compiler can't
transparently wrap a function pointer into a thunk, and therefore can't import
`const int&` as `Int32`:
```c++
struct Example {
void (*printInt)(const int &);
};
```
This approach is much more ergonomic. However, it has a few disadvantages.
One disadvantage is that this approach provides less control: the caller can't
specify or predict the exact address that is passed to the C++ function (because
Swift can make copies of values or move them around in memory). Most functions
receiving `const T&` parameters should not care about the exact address, but
some might.
Another disadvantage of this approach is that it is safe in many cases in
practice, but users can construct unsafe cases. Specifically, if the C++ code
being called persists the reference that was passed by Swift beyond the duration
of the function call, that reference can become invalid (because Swift code
could pass an address of a temporary, implicitly materialized by the compiler).
The nature of unsafety is identical between option 1, option 2, and existing
Swift/C interop, however, in option 2, where we import C++ references as Swift
values, it is not visible to the Swift programmer that the function being called
accepts an address.
### Mapping overload sets
C++ has complex overload resolution rules, in part to support certain API design
patterns. Some API design patterns appeared as a consequence of overload
resolution rules. Therefore, in C++ an "API atom" is an overload set, not an
individual function ([CppCon 2018: Titus Winters "Modern C++ Design (part 1 of
2)"](https://www.youtube.com/watch?v=xTdeZ4MxbKo)). The same is also the case in
Swift, so, fundamentally, there is no impedance mismatch here.
However, C and Objective-C interoperability imports each function and method
separately. For C++ interoperability, we should recognize design patterns that
use overload sets, and map them appropriately to Swift.
One such C++ pattern is providing two overloads: one that takes a `const T&` and
another that takes a `T&&`. If we attempt to naively map them to Swift, they
would map to the same signature. If we import just one of them and ignore the
other, we would be leaving performance on the table.
The easiest way to map such overload sets is to import the `T&&` overload as a
function that takes the argument by value, and ignore the `const T&` overload.
This approach does create a small amount of performance overhead (an extra
move), but does not require changing the Swift language or type checker to
recognize the concept of temporaries. The SIL optimizer seems like the
appropriate place to opportunistically reclaim that performance, by removing
unnecessary moves of temporaries where possible, and replacing calls to the
thunk with calls to the most appropriate C++ entry point.
```c++
// C++ header.
struct Tensor { ... };
void processTensor(const Tensor&);
void processTensor(Tensor&&);
```
```swift
// C++ header imported in Swift.
struct Tensor { ... }
func processTensor(_: Tensor) {
// call `void processTensor(Tensor&&)`
}
```
```swift
// Usage example.
func useTensor() {
var x = Tensor()
processTensor(x)
processTensor(x)
}
```
```swift
// Equivalent of SIL code after optimizations.
// void processTensor(const Tensor&);
func processTensorByConstRef(_: UnsafePointer<Tensor>)
// void processTensor(Tensor&&);
func processTensorByRvalueRef(_: UnsafeMutablePointer<Tensor>)
func useTensor() {
var x = Tensor()
processTensorByConstRef(x)
processTensorByRvalueRef(x) // Automatically move the value because it is obviously not used anymore.
}
```
Once move-only types are added to Swift, the same mapping technique becomes
applicable to C++ move-only value types as well, with the only difference that
argument of the imported function would be marked as being consumed.
### Inline functions
Inline functions (both free and member functions) are used in C++ a lot more
than inline functions in C. For inline functions in C++, Swift should use the
same strategy as it uses currently for C: use Clang's CodeGen libraries to
emit definitions of inline functions into one LLVM module together with Swift
code.
## Namespaces and modules
Namespaces and modules in C++ are orthogonal concepts. Namespaces in C++ can
span multiple modules; C++ namespaces can also be nested. In Swift, modules are
namespaces.
**Option 1: Map C++ namespaces to empty enums in Swift.**
There are precedents for using empty enums as namespaces in Swift (for example,
`CommandLine`, `Unicode`, `Unicode.UTF8` in the standard library).
However, empty enums are not a perfect substitute for C++ namespaces:
- Swift has no `using`-like construct that allows code to avoid qualifying names
nested in an enum (in other words, names nested within an enum must be always
qualified with the name of that enum when used).
- C++ namespaces can span multiple modules. We don't want every imported C++
module to define its own empty enum, as that will lead to name collisions,
which will require even more qualification from users.
```c++
// C++ header in module `CppButton`.
namespace widgets {
class Button {};
}
```
```c++
// C++ header in module `CppTextbox`.
namespace widgets {
class Textbox {};
}
```
```swift
// C++ module `CppButton` imported to Swift.
enum widgets {
struct Button {}
}
```
```swift
// C++ module `CppTextbox` imported to Swift.
enum widgets {
struct Textbox {}
}
```
```swift
// Usage example: everything works well when we import only `CppButton`.
import CppButton
func makeButton() {
var b1 = Button() // error: no such type
var b2 = widgets.Button() // OK
}
```
```swift
// Usage example: ambiguities when we import both `CppButton` and `CppTextbox`.
import CppButton
import CppTextbox
func makeButton() {
var b1 = Button() // error: no such type
var b2 = widgets.Button() // error: name `widgets` is ambiguous, did you mean `CppButton.widgets` or `CppTextbox.widgets`?
var b3 = CppButton.widgets.Button()
}
```
**Improvement for option 1: Move all empty enums to one synthetic module.**
We could fix the ambiguity between same-named namespace enums defined by
multiple C++ modules by synthesizing an extra Swift module that will contain
only the enums that make up the namespace structure, and then making all other
C++ modules define extensions for those enums.
```swift
// Swift module `CppNamespaces` synthesized by the C++ importer.
enum widgets {}
```
```swift
// C++ module `CppButton` imported to Swift.
import CppNamespaces
extension widgets {
struct Button {}
}
```
```swift
// C++ module `CppTextbox` imported to Swift.
import CppNamespaces
extension widgets {
struct Textbox {}
}
```
```swift
// Usage example.
import CppButton
import CppTextbox
// Implicitly injected: import CppNamespaces
func makeButton() {
var b1 = Button() // error: no such type
var b2 = widgets.Button() // OK
}
```
An incidental readability advantage of using enum extensions is that the
pretty-printed module interface for C++ modules will use the keyword `extension`
for namespaces instead of `enum`, reducing the confusion potential.
**Improvement for option 1: Add a `using`-like construct to Swift.**
Some C++ libraries define namespaces with long names, or deeply nested
namespaces. C++ users of such libraries often prefer to avoid typing and seeing
such namespace qualifiers in their code. To help use these libraries in Swift,
we could add a construct similar to C++ `using`, that would expand the name
lookup into the given empty enum.
```swift
// Usage example.
import CppButton
import CppTextbox
// Implicitly injected: import CppNamespaces
import CppNamespaces.widgets
func makeButton() {
var b1 = Button() // OK
}
```
We could limit this construct to only work with enums in the `CppNamespaces`
module, if such feature is not deemed to be appropriate for APIs defined in
Swift.
**Option 2: Introduce namespaces into Swift as a C++ interoperability feature.**
From the implementation point of view, option 1 feels like a pile of hacks and
tricks. We could add C++-style namespaces to Swift, and only allow the C++
importer to define them, clearly designating namespaces as a C++
interoperability feature. From the point of view of users, there will be very
few, if any, differences between option 1 and option 2.
**Option 3: Introduce namespaces into Swift.**
We could add C++-like namespaces to Swift as a generally available language
feature, and then use it to import C++ into Swift.
### The "std" namespace
An interesting question is how to import the `std` namespace in Swift.
Continuing to call it `std` might invoke incorrect associations, because APIs in
`std` are not a part of the Swift standard library. We could rename `std` to
something that suggests that it is the C++ standard library, like `cxx_std`.
## Structs and classes
### Mapping the type itself and its special member functions
For the purposes of this discussion, we will consider C++ classes only. There
are no important technical differences between C++ structs and classes, both
have exactly the same capabilities. In C++, structs and classes differ in how
they are typically used, however, it is not enforced by the compiler. Different
style guides have different rules about when to define a struct or a class, and
these rules are often not toolable in principle. Therefore, struct/class
distinction in C++ can be used at best as a hint to guide the API importer.
Swift's structs and classes are two completely different concepts. Structs are
the building block for value types, and classes are the building block for
reference types. References to Swift class instances are similar to
`std::shared_ptr<T>` in C++ (but are more efficient, because they use an
intrusive refcount), and therefore are not suitable for mapping an arbitrary C++
class type.
As far as value/reference semantics go, C++ classes are similar to structs in
Swift: both inherit value/reference semantics from constituent parts (if you
compose value types in a C++ class or a Swift struct, you get a value type; if
you embed a reference type in a C++ class or in a Swift struct, the composite
type behaves like a reference type). They are also similar in their memory
allocation strategy: both are allocated inline (local variables are allocated on
the stack, member variables are allocated in the containing object without an
indirection).
C++ classes allow the API owner to separately control whether the value is
copyable, movable, copy-assignable, move-assignable, and destructible. Moreover,
behavior for those operations can be customized. User-defined structs in Swift
can't customize such operations. User-defined Swift classes can only customize
the `deinit`, which corresponds to the destructor in C++. Nevertheless, this
limitation only applies to user-defined Swift structs and classes. There are
more mechanisms in the Swift object model, compiler, and runtime, that are not
exposed as language features, but exist as hooks for future extension (e.g.,
some were added specifically for potential C++ interop), or exist to support
Swift language features like resilience.
Let's take a look at what types look like in the compiler and runtime, and what
sorts of customization hooks are available.
The compiler classifies types as loadable or address-only (either one or the
other). Address-only types are always manipulated through a pointer. Loadable
types can be loaded from memory into SIL and LLVM IR values, and then
reconstructed back in memory.
The compiler uses different strategies to access and manage values depending on
the classification of the type. For example, trivial loadable types can be
freely copied, destroyed, and moved around in memory without running any
user-defined code. Structs imported from C are considered loadable in Swift. C
structs are only composed of C primitives, and therefore are considered trivial
-- can be initialized, assigned, and moved around with `memcpy`.
Resilient Swift types are on the complete opposite end of the spectrum.
Resilient types are types provided by a third-party library that does not want
to commit to a particular ABI for that type. Resilient types are opaque values
that must be manipulated through a value witness table -- a table of function
pointers that defines the following operations:
| Swift Value Witness Operation | C++ equivalent |
| ----------------------------- | ------------------------------------------------------------------------ |
| `initializeWithCopy` | copy constructor |
| `assignWithCopy` | copy assignment operator |
| `initializeWithTake` | move constructor, followed by a call to destructor on the source |
| `assignWithTake` | move assignment operator, followed by a call to destructor on the source |
| `destroy` | destructor |
| `size` | `sizeof(T)` minus trailing padding |
| `stride` | `sizeof(T)` |
| `flags` | among other information, contains alignment, i.e., `alignof(T)` |
Value witness tables also contain composite operations that can be derived from
the operations above.
We can map an arbitrary copyable C++ class type to a Swift struct type whose
value witnesses call the corresponding special member function of the C++ class.
We can map certain C++ classes to a more optimizable representation in Swift.
For example, C++ classes that contain only primitives and have trivial special
member functions (i.e., POD types) can be mapped to trivial loadable Swift
structs, just like C structs are today.
Can we map more complex C++ classes to loadable Swift structs? Someone with a
more thorough knowledge of runtime and SIL should answer, but here's what the
author of the document could find.
From `swift/docs/SIL.rst`:
> Loadable types are types with a fully exposed concrete representation:
>
> * Reference types
> * Builtin value types
> * Fragile struct types in which all element types are loadable
> * Tuple types in which all element types are loadable
> * Class protocol types
> * Archetypes constrained by a class protocol
"Fully exposed concrete representation" looks like a definition of a loadable
type, however, other comments say slightly different things, and it is not clear
what "fully exposed" actually means.
From `swift/include/swift/SIL/TypeLowering.h`:
```c++
/// Is a lowered SIL type address-only? That is, is the current context
/// required to keep the value in memory for some reason?
///
/// A type might be address-only because:
///
/// - it is not fixed-size (e.g. because it is a resilient type) and
/// therefore cannot be loaded into a statically-boundable set of
/// registers; or
///
/// - it is semantically bound to memory, either because its storage
/// address is used by the language runtime to implement its semantics
/// (as with a weak reference) or because its representation is somehow
/// address-dependent (as with something like a relative pointer).
///
/// An address-only type can be fixed-layout and/or trivial.
/// A non-fixed-layout type is always address-only.
enum IsAddressOnly_t : bool {
IsNotAddressOnly = false,
IsAddressOnly = true
};
```
C++ classes are fixed-size, so we don't care about the first bullet point. The
second bullet point is more interesting -- a type must be address-only if an
instance of that type cares about which address it is stored at.
From [Slava Pestov's blog post "How to talk to your kids about SIL type
use"](https://medium.com/@slavapestov/how-to-talk-to-your-kids-about-sil-type-use-6b45f7595f43):
> If you define a C++ class describing a smart pointer to a reference-counted
> object, the presence of a custom copy constructor and destructor force the
> value to be materialized in memory all of the time, because the compiler
> doesn't know what the hell you're doing inside the custom constructor; maybe
> you're taking the address of ‘this' and storing it somewhere.
>
> If C++ had loadable types, they would involve some kind of special annotation
> that told the compiler that the move constructor can just trivially do a
> memcpy() of the value, even if there is a custom copy constructor or
> destructor. At this point, your smart pointer could be loaded into a register
> and passed around without issues.
This example says that a C++ smart pointer, with a custom copy constructor, copy
assignment operator, and destructor, can be loadable, as long as all move
special member functions are trivial. This explanation aligns well with the
previous one.
A C++ class is loadable in Swift as long as moving it is trivial. If we ignore
C++ classes with inconsistent copy and move semantics, a trivial move implies
that copy constructor and copy assignment don't care about the specific address,
which matches Swift's requirements.
### Special member functions with incorrect semantics
C++ classes can define special member functions with incorrect or inconsistent
semantics. It can be done intentionally; for example, the copy constructor of
`auto_ptr` actually moves the value. It can also be done unintentionally: it is
common to define only the special member functions that the C++ code happens to
use right now -- for example, only define the copy constructor but not the copy
assignment.
Therefore, we need to decide whether the Swift/C++ interoperability layer should
trust special member functions of C++ classes to have expected semantics, or
whether some verification is necessary.
Non-user-provided special member functions have correct semantics by
construction if the C++ class is composed of well-behaved types. Given the
current state of the art in static analysis, it does not seem like the
interoperability layer even remotely has a chance of proving that user-provided
special member functions have correct semantics. There are two practical
options: either trust the user in this regard and allow them to adjust the
inference done by the interop layer with annotations, or don't make any
assumptions about the semantics and demand that the user annotates types as
value types, move-only, or non-movable.
### Special member functions that throw exceptions
If C++ classes are imported in Swift as structs, there seems to be no reasonable
way to map exceptions thrown from special member functions to an error that can
be handled in Swift.
While it is possible to [propagate C++ exceptions](#exceptions) thrown by normal
member functions to Swift code, special member functions are different as they
used to implement value witnesses, which are called by the compiler
implicitly. Therefore, either such exceptions have to be mapped to fatal errors
(as we do for other unhandled C++ exceptions), or calls to such special member
functions must be prevented statically.
Preventing such calls statically seems difficult. Also, in practice, special
member functions throw mostly due to out-of-memory conditions, which is
considered unrecoverable in Swift. Therefore, the practical solution is to
map exceptions from special member functions to fatal errors.
If the user must use a C++ class with throwing special member functions from
Swift, a reasonable workaround would be to write a wrapper that exposes these
operations as regular APIs. Wrappers can even be synthesized by the importer, if
such classes are found to be common.
```c++
// Can't be imported in Swift.
class MyThrowingType {
public:
MyThrowingType() { if(...) throw ...; }
~MyThrowingType() { if(...) throw ...; }
void method();
};
// Can be imported in Swift.
class MyThrowingTypeWrapper {
private:
std::unique_ptr<MyThrowingType> value_;
public:
MyThrowingTypeWrapper(): value_(nullptr) {}
void init() /* can throw */ { value_ = std::make_unique<MyThrowingType>(); }
void deinit() /* can throw */ { value_ = nullptr; }
void method() { value_.method(); }
};
```
### Precise destruction semantics
C++ language specifies the exact point in program execution at which destructors
should run, while Swift does not. Some C++ APIs rely on these guarantees to work
properly (for example, RAII types like mutex locks).
```c++
// A pure C++ program.
class PickyCxxClass {
public:
~PickyCxxClass() { ... }
};
void test1() {
PickyClass c;
printf("Hello");
// `c`'s destructor is guaranteed to be called exactly here.
}
```
```swift
// A pure Swift program, similar to the C++ program above.
struct SwiftStruct { ... }
func test1() {
var s = SwiftStruct()
// `s` can be deallocated here.
print("Hello")
// `s` can also be deallocated here.
}
```
But how commonly do C++ APIs rely on precise destruction? A gut feeling is that
it happens pretty often, but it is not always intentional and acknowledged by
the API vendor. *All* C++ types get a precise destruction point, and therefore,
it is very easy to start inadvertently relying on it in API design.
There are multiple ways to deal with this impedance mismatch.
**Ignore the differences, and apply Swift destruction semantics to C++
classes.** This approach will work for most C++ classes. However, C++ classes
that rely on C++ destruction semantics won't work well in Swift.
**Force the user to always pick a destruction point for values of C++ types.**
Too much burden on the user, and the code won't look like normal Swift.
**Allow the user to pick a destruction point, otherwise let the compiler pick.**
This approach will work, but it trusts the user to do the right thing every
time a certain C++ class is used. Often, whether precise destruction point is
required or not depends on the type.
**Define a destruction point for C++ classes.** This can't be done universally
in all Swift code, but it is feasible for local variables of concrete types.
An example where it is not possible to maintain precise destruction semantics
for C++ classes is in a generic Swift function that is called with a C++ class
as a type parameter. In this case, we must be able to compile one definition of
a Swift function, which must work regardless of the nature of the type (be it a
Swift type or a C++ class). This limitation does not seem too bad, because RAII
types are not often passed as type parameters to templates in C++, which creates
a reason to believe it will not be common in Swift either.
**Allow the API owner to annotate the C++ class as requiring a precise
destruction point.** An improvement upon the previous approach where unusual
semantics are only applied to C++ classes that need them, for example, RAII
types like mutex locks.
The pragmatic choice is to implement one of the last two options.
If a precise destruction point is defined for annotated C++ classes, here's an
example of behavior that we get:
```c++
// C++ header.
[[swift::requires_precise_destruction]]
class PickyCxxClass {
public:
~PickyClass() { ... }
};
```
```swift
// C++ header imported in Swift.
struct PickyCxxClass {
// The destructor is not imported as a declaration into Swift, however,
// it is mapped to a value witness function, and it is called when the
// lifetime of the object ends, like in C++.
}
```
```swift
func testConcreteType() {
var c = PickyCxxClass()
print("Hello")
// `c` will be deallocated here.
}
func testTypeParameter<T>(_ t: T.self) {
var c = T()
// `c` can be deallocated here, even if `c` is a `PickyCxxClass`.
print("Hello")
// `c` can also be deallocated here.
}
testTypeParameter(PickyCxxClass.self)
```
### Member functions that return inner pointers
When a member function in a C++ class returns a pointer (or a reference), most
commonly the lifetime of that pointer is limited to the lifetime of the object
itself. C++ code often relies on precise destruction semantics to ensure that
the object that owns the memory lives long enough. Another problem is that the
Swift compiler can move the object around in memory whenever it wants,
invalidating those outstanding inner pointers.
```c++
// C++ header.
class Employee {
private:
std::string company_;
public:
std::string *mutable_company() { return &company_; }
};
```
```swift
// C++ header imported in Swift.
struct Employee {
func mutable_company() -> UnsafeMutablePointer<std.string>
}
```
```swift
func test() {
var employee: Employee = ...
var company = employee.mutable_company()
// HAZARD: `employee` could have been moved to a different location in memory
// by now, invalidating the `company` pointer.
company.pointee = "A"
print(employee)
// HAZARD: `employee` can be deallocated here, however, `company` is still
// accessible.
company.pointee = "B"
}
```
To fix the problem of values being moved around in memory, we need to tell the
Swift compiler about the connection between pointers and objects that own the
memory.
```c++
// C++ header.
class Employee {
private:
std::string company_;
public:
[[swift::returns_inner_pointer]]
std::string *mutable_company() const { return &_company; }
};
```
The `returns_inner_pointer` attribute can be added manually to the C++ headers,
or it can be safely inferred on all member functions that return a pointer or
reference, to reduce annotation burden. Inferring this annotation on functions
that don't actually need it is harmless (does not change semantics, and does not
create unsafety), but may prevent some optimizations.
To fix the lifetime problem, the lifetime of a local variable can be extended
until the end of the scope if the current scope called a method that returns an
inner pointer.
```swift
func test() {
var employee: Employee = ...
var company = employee.mutable_company()
// ... any amount of code...
// `employee` is destroyed at the end of the scope because of the `mutable_company` call.
}
```
This technique will not work for temporaries (instead, they need to be extended
to the end of the full expression). It is also not very useful to call methods
that return inner pointers on temporaries.
### Differences in move semantics between C++ and Swift
Swift's "move" operation will leave the source value uninitialized (see
[ownership manifesto](OwnershipManifesto.md)); this operation is called a
"destructive move". C++ has "non-destructive moves" that leave the source value
initialized, but in an indeterminate state.
The following sections address various aspects of this impedance mismatch
between the two languages.
### Move-only C++ classes
For the purposes of this document, we will call C++ classes that can be moved
but don't have a public copy constructor and a public copy assignment operator
"move-only C++ classes".
Swift does not have move-only types at the time this document was written
(January 2020). There is a desire to add them, and a lot of design work has been
done (see the [Ownership Manifesto](OwnershipManifesto.md)), however, this
design has not been proposed yet.
Therefore, we will first discuss mapping move-only C++ classes to Swift before
move-only types are implemented. In this situation there's clearly no good
direct mapping. There are some non-ergonomic options though.
Second, we will discuss mapping move-only C++ classes to move-only types in
future Swift versions.
### Move-only C++ classes: mapping in Swift 5
**Import move-only C++ classes as Swift structs, and statically ensure that
copies are never needed.**
This seems doable, although the usability and predictability of the language
feature will depend on the compiler stage where the checks are done. It is easy
to perform such checks at the SIL level, however, the language might not behave
predictably. It is a more difficult to do such checks on the AST, but the
language will be more predictable from the user's point of view. Also, AST-based
checks might reject more programs than people expect.
Since value witness tables require a valid copy witness, it will be also
necessary to prohibit passing such pseudo-move-only types into generic code as
type parameters, or force full specialization of generic functions, and perform
the checks on fully-specialized SIL.
Here's a sketch of rules for move-only types that are reasonably simple to check
at compile-time and provide good diagnostics, at the expense of the resulting
code being non-ergonomic. Move-only C++ classes can be imported in Swift as
structs as usual, however, such structs can't be used as values. The compiler
would only allow `UnsafePointers` to them, and would allow calling methods on
`UnsafePointer.pointee`. When move-only types are used as C++ class members,
Swift can import them as opaque blobs, and expose a `withUnsafePointer`-style
API to get an `UnsafePointer` to the data member.
```c++
// C++ header.
// `File` is a move-only C++ class.
class File {
private:
int file_descriptor_;
public:
File(std::string_view filename);
File(const File &) = delete;
File(File &&) = default;
~File();
File& operator=(const File &) = delete;
File& operator=(File &&) = default;
std::string ReadAll();
};
// `TwoFiles` is move-only because it is composed of move-only parts.
struct TwoFiles {
File firstFile;
File secondFile;
};
```
```swift
// C++ header imported in Swift.
struct File {
public init(_ filename: std.string_view)
public func ReadAll() -> std.string
}
struct TwoFiles {
private var _firstFile: <unspecified-opaque-storage>
private var _secondFile: <unspecified-opaque-storage>
func withUnsafePointerToFirstFile<Result>(
_ body: (UnsafePointer<File>)->Result
) -> Result {
body(&_firstFile)
_fixLifetime(self)
}
func withUnsafePointerToSecondFile<Result>(
_ body: (UnsafePointer<File>)->Result
) -> Result {
body(&_secondFile)
_fixLifetime(self)
}
}
```
```swift
// Usage example.
func useOneFile(_ f: UnsafeMutablePointer<File>) {
// var f2 = f.pointee // compile-time error: can only call a method on 'pointee'.
print(f.pointee.ReadAll()) // OK
// Move `f` to a different memory location.
var f2 = UnsafeMutablePointer<File>.allocate(capacity: 1)
f2.moveInitialize(from: f, count: 1)
// `f` is left uninitialized now.
print(f2.pointee.ReadAll()) // OK
f2.deallocate() // OK
// The file is closed now.
}
func useTwoFiles(_ files: UnsafeMutablePointer<TwoFiles>) {
// Like `print(files.first.ReadAll())`, if it was possible to compile it:
files.pointee.withUnsafePointerToFirst { print($0.ReadAll()) }
}
```
If we add support for [marking APIs as returning inner
pointers](#member-functions-that-return-inner-pointers), we could make the
imported API nicer:
```swift
// C++ header imported in Swift.
struct TwoFiles {
private var _firstFile: <unspecified-opaque-storage>
private var _secondFile: <unspecified-opaque-storage>
@_returnsInnerPointer
var firstFile: UnsafePointer<File> { get }
@_returnsInnerPointer
var secondFile: UnsafePointer<File> { get }
}
```
### Move-only C++ classes: mapping to move-only Swift types (in future Swift versions)
This section is based on the design for move-only Swift types that has not been
officially proposed yet. See [ownership manifesto](OwnershipManifesto.md) for
the design for ownership and move only types that we assume in this section.
Move-only C++ classes correspond to `moveonly` structs in Swift. Semantic
analysis ensures that they are never copied.
Moves that destroy the source are spelled `move(x)` in Swift. Swift does not
have a concept of non-destructive move; a section below discusses possible
design options.
```c++
// C++ header.
class File {
private:
int file_descriptor_;
public:
File(std::string_view filename);
File(const File &) = delete;
File(File &&) = default;
~File();
File& operator=(const File &) = delete;
File& operator=(File &&) = default;
std::string ReadAll();
};
```
```swift
// C++ header imported in Swift.
moveonly struct File {
public init(_ filename: std.string_view)
public deinit
public func ReadAll() -> std.string
}
moveonly struct TwoFiles {
var first: File
var second: File
}
```
```swift
// Usage example.
func useOneFile(_ f: File) {
print(f.ReadAll()) // OK
// Move `f` to a different memory location.
var f2 = move(f)
// print(f.ReadAll()) // compile-time error: can't access `f`, its value was moved
print(f2.ReadAll()) // OK
endScope(f2) // OK
// The file is closed now.
}
func useTwoFiles(_ files: TwoFiles) {
print(files.first.ReadAll()) // OK
}
```
### Non-destructive moves
Generally, Swift code that uses values of C++ class types should use Swift's
destructive moves in most cases where C++ code would have used a non-destructive
move. However, certain C++ APIs are designed to be used with non-destructive
moves, therefore, non-destructive moves should be made available in Swift.
Adding non-destructive moves to Swift as a native language feature is a
non-starter.
Consider the following C++ code:
```c++
// Example of C++ API design that requires users to perform non-destructive
// moves.
class Example { /* move-only */ };
std::optional<Example> getExample();
void processExample(Example e);
void test() {
std::optional<Example> e = getExample();
processExample(std::move(e.value()));
}
```
Equivalent Swift code would look like this:
```swift
// Equivalent Swift code.
func test() {
var e: cxx_std.optional<Example> = getExample();
processExample(move(e.value()));
// If we assume that the previous line compiled, we have a problem:
// `cxx_std.optional` does not know that the value was destructively moved
// and will try to delete it again.
}
```
Of course, one could argue that the interoperability layer could provide special
support for `std::optional`, and make it work with destructive moves better.
While that is true, the point still stands: there will be C++ APIs that expect
users to perform non-destructive moves, and should ensure that they are usable
from Swift without overlays or special compiler support.
**Option 1: Non-destructive moves in Swift are swaps with an arbitrary valid
value.**
It is easy to model a non-destructive move in Swift as a swap with a
default-initialized value.
```swift
// Swift standard library, C++ support module.
public protocol DefaultInitializable {
init()
}
public moveonly func cxxMove<T: DefaultInitializable>(_ value: inout T) -> T {
var result = T()
swap(&value, &result)
return result
}
public moveonly func cxxMove(_ value: inout T, replacingWith newValue: T) -> T {
var result = newValue
swap(&value, &result)
return result
}
```
```swift
// Usage example.
// This function takes a `File` by value, consuming it.
func consumeFile(_ f: File) { ... }
func useArrayOfFiles() {
var files: [File] = ...
// consumeFile(files[0]) // compile-time error: can't copy a `File`
// Swift's move does not help.
// consumeFile(move(file[0]))
// compile-time error: moving one element of an array will cause a
// double-destruction of `File` when the array is destroyed.
consumeFile(cxxMove(&file[0])) // OK, replaced `file[0]` with a `File()`.
consumeFile(cxxMove(&file[1], replacingWith: File("/tmp/example.txt")))
// OK, replaced `file[1]` with a newly-opened file.
}
```
The advantage of this approach is that we avoid creating "valid but
indeterminate" values, which can be hazardous. However, such values can be
passed from C++ to Swift at any time, even if Swift code can't create them
directly. It is also awkward to require the user to come up with a dummy valid
value when the type is not default-constructible.
**Option 2: Non-destructive moves in Swift invoke the C++ move constructor.**
So, we want to perform a real C++ move and leave a "valid but indeterminate"
value in the source. For that, we must enable the Swift to call the C++ move
constructor.
If `class File` has a move constructor in C++, the imported Swift struct defines
a corresponding initializer:
```c++
// C++ header imported in Swift.
public moveonly struct File {
// File(File &&);
public init(cxxMovingFrom: inout File)
}
```
```swift
// Usage example.
func useArrayOfFiles() {
var files: [File] = ...
consumeFile(File(cxxMovingFrom: &files[0]))
}
```
The move syntax, `File(cxxMovingFrom: &files[0])`, is quite verbose and requires
repeating the name of the type, whereas the corresponding C++ construct,
`std::move(x)`, does not. When type context is available, the expression can be
abbreviated to `.init(cxxMovingFrom: &files[0])`. We can make it more concise by
synthesizing a helper method in movable types:
```swift
// C++ header imported in Swift.
public moveonly struct File {
// File(File &&);
public init(cxxMovingFrom: inout File)
public mutating func cxxMove() -> File {
return File(cxxMovingFrom: &self)
}
}
```
```swift
// Usage example.
func useArrayOfFiles() {
var files: [File] = ...
consumeFile(files[0].cxxMove())
}
```
Although methods are more in line with Swift API design than free functions,
injecting names into C++ types can backfire due to naming collisions.
Alternatively, we could model non-destructive moves with a free function,
imitating the C++ syntax. To do this we need a protocol for non-destructively
movable types, and a free function that calls the move constructor:
```swift
// Swift standard library, C++ support module.
public protocol NonDestructivelyMovable {
public init(cxxMovingFrom: inout Self)
}
public moveonly func cxxMove<T: NonDestructivelyMovable>(_ value: inout T) -> T {
return T(cxxMovingFrom: &value)
}
```
```swift
// C++ header imported in Swift.
public moveonly struct File: NonDestructivelyMovable {
public init(cxxMovingFrom: inout File)
}
```
```swift
// Usage example.
func useArrayOfFiles() {
var files: [File] = ...
consumeFile(cxxMove(&files[0]))
}
```
It is also useful to expose the move assignment operation in Swift. Even though
move assignment is not necessary to implement `cxxMove()`, it can be used for
optimization.
```swift
// C++ header imported in Swift.
public moveonly struct File {
// File(File &&);
public init(cxxMovingFrom: inout File)
// File& operator=(File &&);
public func moveAssignFrom(_ value: inout File)
}
```
The compiler could perform a high-level optimization replacing `x = cxxMove(&y)`
(which creates a temporary, and calls the move constructor twice) with
`x.moveAssignFrom(&y)` (which does not create a temporary and calls move
assignment only once).
### Non-movable C++ classes
By non-movable C++ classes we mean C++ classes that don't have a copy
constructor or a move constructor.
Swift does not have any struct-like equivalent to non-movable C++ classes, and
there's nothing planned in that area. Therefore, we have to either creatively
reuse one of existing Swift's features, or add some new features to Swift.
**Option 1: Map non-movable C++ classes to Swift structs.**
If we want to map all C++ classes to structs in Swift, one approach to make
non-movable C++ classes work is only importing pointers to non-movable types;
this approach is described in detail in the section about [importing move-only
types in Swift 5](#move-only-c-classes-mapping-in-swift-5). Non-movable classes
in C++ are often used as polymorphic base classes. Allowing to only use pointers
to such types is not a bad limitation. The primary disadvantage of this approach
is ergonomics.
**Option 2: Map non-movable C++ classes to Swift classes.**
While Swift structs are a bad match for non-movable C++ classes, Swift classes
match semantics better. For example, instances of Swift classes, once allocated,
stay at the same address until `deinit`. Instances of Swift classes are always
worked with indirectly, eliminating the need to move them around in memory.
Although user-defined Swift classes have a certain memory layout determined by
the Swift compiler (for example, the memory block should start with an object
header that contains a metadata pointer and a refcount), that exact memory
layout is not necessary for a type to successfully masquerade as a Swift class.
For example, Swift already imports CoreFoundation types as "foreign classes";
from the user's point of view they look like ordinary classes.
The biggest semantic impedance mismatch between C++ classes and Swift classes is
that Swift classes are reference-counted. It is certainly possible to import a
C++ class as a Swift class if it is intrusively reference counted, or wrapped in
a `shared_ptr`.
But what about non-movable C++ classes that are not reference counted? This
issue could be worked around by making retain and release operations on C++
classes be a no-op, and introducing an explicit "delete" operation, effectively
making C++ class references in Swift equivalent to `UnsafeMutablePointer`.
```c++
// C++ header.
class NonMovable {
public:
NonMovable(const NonMovable &) = delete;
NonMovable(NonMovable &&) = delete;
~NonMovable();
NonMovable &operator=(const NonMovable &) = delete;
NonMovable &operator=(NonMovable &&) = delete;
void debugPrint() const;
};
```
```swift
// C++ header imported in Swift.
class NonMovable {
// Runs `delete this`.
func delete()
func debugPrint()
}
```
```swift
func useNonMovable(nm: NonMovable) {
var nm2 = nm
// `nm2` now points to the same object as `nm`. No reference-counting.
nm.debugPrint() // OK
nm2.debugPrint() // OK
nm2.delete() // OK
// The object is deallocated now. From this point, using `nm` or `nm2`
// is undefined behavior.
}
```
Everything seems to work really well, except that we broke Swift's safety
guarantees about classes. Swift manages lifetime of regular user-defined classes
automatically; in safe Swift code it is not possible to get a dangling class
reference; it is also weird that users would have to manually deallocate class
instances. Therefore, classes imported from C++ would behave very differently
from user-defined Swift classes; most importantly, they are unsafe. This issue
seems incompatible with Swift's design and philosophy. Otherwise, importing C++
classes as Swift classes looks like a viable implementation strategy.
The unsafety issue could be mitigated by adding the word "unsafe" somewhere in
the source code. For example, importing a non-movable C++ class `Example` as a
Swift class `UnsafeExample`, or requiring the user to write the keyword "unsafe"
before the type name:
```swift
func useNonMovable(nm: unsafe NonMovable) { ... }
```
### Member functions
Member functions of C++ classes are most naturally mapped to methods in Swift
structs. C++ allows to add various qualifiers to member functions, which we
discuss in the following sections.
### Const-qualified member functions in C++ classes
Member functions of C++ classes can be marked with a `const` qualifier; however,
this qualifier does not provide any semantic guarantees. Const-qualified methods
can change the state of the object through a variety of mechanisms.
`const_cast` is the first language feature that comes to mind when one thinks
about modifying a const object. As long as an object was originally allocated as
non-const, its const-qualified methods can cast const away and mutate the
object. Detecting potential `const_cast`s is quite difficult, since it requires
examining everything that a const member function can call, transitively.
However, in practice, `const_cast`s are rare, and given the more pervasive
issues described below, `const_cast`s can be ignored.
```c++
class SneakyMutation {
private:
int value = 0;
public:
void mutateSneakily() const { opaqueMutator(this); }
void setValue(int newValue) { value = newValue; }
};
// in a different file:
void opaqueMutator(const SneakyMutation* sm) {
const_cast<SneakyMutation*>(sm)->setValue(42);
}
```
Another C++ feature that allows const-qualified member functions to mutate the
object is "mutable" data members. Mutable data members are a lot more common
than `const_cast`s, but fortunately they are trivial to detect statically.
```c++
class SneakyMutation {
private:
mutable int value = 0;
public:
void mutateSneakily() const { value = 42; }
};
```
Yet another C++ feature that allows const-qualified methods to mutate the object
is aliasing. A const member function can obtain a pointer to the same object
through some other means, and change the pointed-to data.
```c++
class SneakyMutation {
private:
int value = 0;
public:
void mutateSneakily(SneakyMutation *other) const {
other->value = this->value + 1;
// What if `other` happens to be equal to `this`? In that case, a const
// member function has mutated `this`!
}
};
void test() {
SneakyMutation sm;
// A const method mutates the object that it is invoked on:
sm.mutateSneakily(&sm);
}
```
Note that `mutateSneakily()` can obtain the alternative `this` pointer through a
variety of ways, not necessarily as a function argument. The method can find
another non-const pointer equal to `this` in a global variable or in a data
structure accessible from `this` itself. It also need not mutate `other` so
obviously: it can pass `other` to another function which will mutate it. It is
difficult to estimate how common such mutation is, however, it is not an element
of a common design pattern.
Swift's replacement for C++ const member functions are non-`mutating` functions:
```swift
struct Example {
private var value: Int = 0
mutating func mutatingFunction() { value = 42 }
func nonMutatingFunction() {
// value = 42 // would not compile
print(value) // OK
}
}
```
The biggest difference from C++ is that non-`mutating` functions in Swift are
really not allowed to mutate `self`; there are no backdoors. Some equivalents of
C++'s mutation backdoors are disallowed statically, some are disallowed
dynamically, some are undefined behavior.
The backdoors are disallowed by the exclusivity rule (from [SE-0176 Enforce
Exclusive Access to
Memory](https://github.com/apple/swift-evolution/blob/main/proposals/0176-enforce-exclusive-access-to-memory.md)):
> two accesses to the same variable are not allowed to overlap unless both
> accesses are reads
If we map C++ classes to Swift structs, how do we map C++'s `const` qualifier on
member functions? There are a couple of options.
* Ignore `const`, and mark all Swift struct functions as `mutating`. Allow API
owners to manually annotate functions as non-`mutating`. This is a
conservative and correct-by-default approach, but it is not ergonomic.
* Map `const` to non-`mutating` in Swift. This approach is very desirable from
the point of view of ergonomics, however it is not safe in the general case.
Nevertheless, in many cases such inference will be correct.
How can we make the second, ergonomic, approach safer? First of all, we should
allow C++ API owners to override the inferred `mutating`/non-`mutating` with an
annotation. API owners must have control over what their APIs look like in
Swift.
In addition, the compiler could do a lightweight static analysis to recognize
common problematic patterns, like `mutable` members and obvious `const_cast`s.
If the compiler finds anything alarming, it should refuse to perform inference
and require the user to manually annotate methods in C++ as `mutating` or
non-`mutating`.
### Volatile-qualified member functions
Volatile-qualified member functions are so rare that there's not enough value in
spending non-trivial engineering effort for them in the interop layer ensuring
that they map nicely. There are two easy ways to handle them:
* don't import volatile-qualified member functions,
* map member functions as if the `volatile` qualifier was not present.
### Ref-qualified member functions
TODO
### Final functions
TODO
### Getters and setters
Getters and setters in C++ classes most directly correspond to properties in
Swift. While it is certainly possible to map getters and setters to regular
methods, properties would be more ergonomic.
First of all, we need to find getter/setter pairs in a C++ class. We would need
to use name-based heuristics for that, while allowing the API owner to override
the inference with annotations (specifically, with the `swift_name` attribute).
There are a variety of naming styles for getters and setters in C++, but we only
need to cover the most common ones.
Getters take no arguments, return a `T` or a `const T`. Typical naming patterns
are: `AaaBbb()`, `GetAaaBbb()`, `aaaBbb()`, `getAaaBbb()`, `aaa_bbb()`,
`get_aaa_bbb()`
Setters take a `T`, a `const T&`, or a `T&&`, and return `void`. Typical naming
patterns are: `SetAaaBbb()`, `setAaaBbb()`, `set_aaa_bbb()`
Mutable accessors take no arguments and return a `T&` or a `T*`. Typical naming
patterns are: `MutableAaaBbb()`, `mutableAaaBbb()`, `mutable_aaa_bbb()`.
The C++ importer can synthesize a Swift property from a getter, from a
getter/setter pair, or from a getter and a mutable accessor. Swift does not have
set-only properties, so unpaired setters and mutable accessors will be imported
as regular methods.
```c++
// C++ header.
class Employee {
public:
const std::string &getName() const;
void setName(std::string newName);
};
```
```swift
// C++ header imported in Swift.
struct Employee {
public var name: std.string { get set }
}
```
```swift
// Implementation details of the imported API.
struct Employee {
// const std::string &getName();
private func _getName() -> UnsafePointer<std.string>
// void setName(std::string newName);
private mutating func _setName(_ newName: std.string)
// Swifty API.
public var name: std.string {
_read {
yield _getName().pointee
}
set {
_setName(newValue)
}
}
}
```
Sometimes the type returned by the getter will not match the type taken by the
setter. For example, the getter can return a `std::string_view`, while a setter
takes a `std::string`. `std::string_view` is like a `const std::string&`, so it
makes sense from the API perspective in C++. Swift, however, requires the getter
and setter to use the same type exactly.
We could teach the C++ importer about the most widely used type pairs, and
insert the appropriate type conversions in the synthesized property accessors.
However, these type conversions will carry a performance penalty, and the
resulting Swift API will be less performant than the original C++ API. For
example, consider a C++ class where a getter returns a `std::string_view`, and
the setter takes a `std::string`. If we synthesize a `std::string_view` property
in Swift, its setter would always copy the character data, even though in C++
the setter would move the `std::string`. If we synthesize a `std::string`
property in Swift, its getter would have to materialize a `std::string` from a
`std::string_view`.
Therefore, it seems like the best approach is to teach the C++ importer about
handling such mismatched types, but only perform property synthesis on demand,
triggered by an annotation in C++ code.
```c++
// C++ header.
// New attribute.
#define SWIFT_PROPERTY(type, name) __attribute__((swift_property(#type, #name)))
class Manager {
public:
std::string_view getName() const SWIFT_PROPERTY(std::string, name);
void setName(std::string newName) SWIFT_PROPERTY(std::string, name);
std::span<const Employee> getReports() const;
void setReports(std::vector<Employee> newReports);
};
```
```swift
// C++ header imported in Swift.
struct Manager {
// Property is synthesized as requested by the annotation.
public var name: std.string { get set }
// Property is not synthesized because getter and setter operate on
// different types.
public func getReports() -> std.span<const<Employee>>
public func setReports(_ newReports: std.vector<Employee>)
};
```
### Pointers to members
Pointers to members are quite rare in C++, so not importing them at all, at
least initially, would not be a big loss. Nevertheless, importing them is
possible.
Pointers to data members best correspond to keypaths in Swift. (TODO: need an
example.)
Pointers to member functions could be ergonomically mapped to curried functions,
just like struct and class methods in Swift can be converted to curried
functions.
```swift
// Inspiration from Swift: methods can be converted to curried functions.
// A normal user-defined struct.
struct Point {
var x: Double
var y: Double
func distanceTo(_ line: Line) -> Double { ... }
}
var distanceToFunc: (Point) -> (Line) -> Double = Point.distanceTo
```
The only difference is that C++ member function pointers use a different memory
layout than Swift closures. Therefore, they would need to be imported with a
special calling convention, let's call it `@convention(cxx_method)`. Here's an
example:
```c++
// C++ header.
class Point {
public:
double distanceTo(Line line) const;
};
void CallMemberFunctionPointer(Point p, double (Point::*ptr)(Line));
```
```swift
// C++ header imported in Swift.
public struct Point {
public func distanceTo(_ line: Line) -> Double { ... }
}
func CallMemberFunctionPointer(
_ p: Point,
_ ptr: @convention(cxx_method) (Point) -> (Line) -> Double
)
```
### Virtual member functions
If we map C++ classes to Swift structs, it makes the most sense to map virtual
member functions to struct methods in Swift. However, Swift structs don't
support inheritance. So, while we can map virtual functions to methods and
execute C++ dynamic dispatch correctly, we can't express the fact that the
struct is subclassable, and that the method is overridable in Swift.
TODO: design how to map inheritance.
### Inherited APIs
Swift structs don't allow inheritance. If we map C++ classes as Swift structs,
we could replicate APIs from all base classes in every derived class.
```c++
// C++ header.
class Base {
public:
void doBaseStuff();
};
class Derived : public Base {
public:
void doDerivedStuff();
};
```
```swift
// C++ header imported in Swift.
public struct Base {
public func doBaseStuff()
}
public struct Derived {
public func doBaseStuff()
public func doDerivedStuff()
}
```
### Conversions between derived and base classes
Swift structs don't allow inheritance, so it is not possible to directly express
the is-a relationship between derived classes and base classes. The is-a
relationship is not very important for non-polymorphic C++ classes, where
inheritance is typically used as an implementation technique, rather than an
intentional part of the API. In polymorphic classes the is-a relationship is
quite important and is an intentional part of the API.
So how to represent conversions between derived and base classes? There are two
cases to consider: converting values and converting pointers.
Converting values of derived type to values of base type is known as "object
slicing" in C++. It is well-known to be error-prone, but since some C++ APIs
might rely on it, we should try to expose it in Swift.
Object slicing is possible without any language extensions:
```swift
var derived: Derived = ...
var base: Base = UnsafeRawPointer(&derived).load(as: Base.self)
```
It is not very ergonomic, but not too bad for an operation that is known to be
error-prone. APIs that intentionally rely on object slicing could add helper
methods to types that intentionally participate in slicing:
```swift
// Manually written overlay for a C++ API.
extension Base {
public init(_ other: Derived) {
self = UnsafeRawPointer(&other).load(as: Base.self)
}
public init(_ other: UnsafePointer<Derived>) {
self = UnsafeRawPointer(other).load(as: Base.self)
}
}
```
Now let's talk about conversions between pointers to derived type and pointers
to base type. These operations need to be ergonomic only for polymorphic
classes.
First of all, let's reject extending Swift's type casting operators `as` and
`as?` to handle casts between pointers to C++ objects. We need to convert
between `UnsafePointer<Base>` and `UnsafePointer<Derived>`, which are not
connected with a subtyping relationship in Swift. Implementing a conversion in
type casting operators (`as` and `as?`) that does not reflect a subtyping
relationship is not a good idea. Swift already has a couple of such conversions,
and they cause a lot of complexity in the compiler and the runtime. Moreover,
sometimes such casting behavior can be unexpected by users. Therefore, we are
going to explore API-based approaches to express upcasts and downcasts for C++
objects.
It is important to realize that interleaved accesses to an `UnsafePointer<Base>`
that aliases an `UnsafePointer<Derived>` violate Swift's type-based aliasing
rules. These rules could be relaxed for types imported from C++.
To prevent the user from accidentally violating type-based aliasing rules, Swift
intentionally does not provide an easy way to freely convert between pointers of
unrelated types. Swift allows to temporarily create an aliasing pointer;
however, that pointer has a scoped lifetime, and during that scope accessing the
original pointer is not allowed.
```swift
// Pointer conversion example in existing Swift language.
var basePtr: UnsafePointer<Base> = ...
basePtr.withMemoryRebound(to: Derived.self) {
// In this closure, `$0` has type `UnsafePointer<Derived>` and
// aliases `basePtr`.
$0.doBaseStuff()
$0.doDerivedStuff()
}
```
Type conversions are usually expressed as initializers in Swift. However, adding
an initializer to `UnsafePointer` for base/derived C++ class pair is going to
create a big overload set, which will negatively impact compilation performance.
Therefore, we should try to distribute the conversion APIs among the imported
types themselves. The importer could synthesize conversion APIs on base and
derived classes:
```swift
// C++ header imported in Swift.
public struct Derived {
@returnsInnerPointer
public var asBase: UnsafePointer<Base> { get }
public static func downcast(from basePointer: UnsafePointer<Base>) -> UnsafePointer<Derived>?
}
public struct Base {
public static func upcast(from basePointer: UnsafePointer<Derived>) -> UnsafePointer<Base>
}
```
```swift
// Usage example.
func useBasePtr(_ basePtr: UnsafePointer<Base>) { ... }
func useDerivedPtr(_ derivedPtr: UnsafePointer<Derived>) { ... }
func testDowncast() {
var d = Derived()
useBasePtr(d.asBase)
// or:
useBasePtr(Base.upcast(from: &d))
}
func testUpcast(_ basePtr: UnsafePointer<Base>) {
if let derivedPtr: UnsafePointer<Derived> = Derived.downcast(from: basePtr) {
useDerivedPtr(derivedPtr)
}
}
```
The `asBase` property operates on a value, so it will need a way to pin the
original value in memory while the aliasing pointer is live. If we ignore that
API, the "type-upcast-from-value" and "type-downcast-from-value" syntax in other
APIs doesn't read well, because the order looks reversed.
Let's see what an API based on free functions would look like. We have to
separate the upcast and downcast APIs because they must return different types:
upcasts can't fail, while downcasts can.
```swift
// C++ support module in the Swift standard library.
public func cxxUpcast<Source, Destination>(
_ source: UnsafePointer<Source>,
to type: Destination.Type
) -> UnsafePointer<Destination>
public func cxxDowncast<Source, Destination>(
_ source: UnsafePointer<Source>,
to type: Destination.Type
) -> UnsafePointer<Destination>
public func cxxDynamicDowncast<Source, Destination>(
_ source: UnsafePointer<Source>,
to type: Destination.Type
) -> UnsafePointer<Destination>?
```
The Swift type checker would have special knowledge about these functions, and
only allow calling them when `Source` and `Destination` are fully concrete types
that belong to the same class hierarchy in C++.
These functions will know the concrete source and destination types, so they
will be able to perform any necessary pointer adjustments, therefore multiple
inheritance and virtual base classes wouldn't be a problem.
### Subclassing C++ classes in Swift
TODO
### Making C++ classes conform to Swift protocols
TODO
## Enums
In Swift 5, C enums that are not annotated (with either of `enum_extensibility`,
`NS_ENUM`, or `NS_OPTIONS`) are imported into Swift as structs, and enumerators
are imported as computed global variables. This might have been the right call
for importing Objective-C code, where enums not declared with `NS_ENUM` are
highly likely to have a "non-enum nature": they are either a bitfield, or just
a bag of constants. C++ has more ways, and more flexible ways to declare
constants, so using enums in C++ to declare constants is not very idiomatic.
Bitfield enums are used in C++ though, however, compared to overall enum usage,
bitfield enums are still rare. Therefore, current strategy of importing
non-annotated enums as Swift structs is the wrong default for C++.
There are multiple strategies we could take to import C++ enums into Swift.
**(1) Adopt the strategy used for C enums in C++**: unannotated C++ enums are
imported as Swift structs, C++ enums annotated as open/closed are imported as
Swift enums.
Pros:
* Conservatively correct. This strategy does not trust enums to have the "enum
nature" unless they are annotated otherwise.
* Simpler design: identical rules across C, Objective-C, and C++.
Cons:
* Non-ergonomic. In idiomatic C++ codebases most enums have enum nature, so
users would need to add lots of annotations.
**(2) Assume non-annotated C++ enums have "enum nature" and import them
as non-frozen Swift enums**; (optionally) implement an annotation for C++ enums
with "non-enum nature" and import such enums as Swift structs.
Pros:
* Correct default. In an idiomatic C++ codebase, the vast majority of enums do
have enum nature.
* Maintaining source compatibility by not changing how C enums are imported.
Cons:
* Non-annotated enums of non-enum nature would be imported incorrectly from the
API point of view (however, there is no undefined behavior hazard).
* No clear strategy to tell apart C and C++ enums. In an ideal world, `extern
"C"` should allow to detect C declarations in C++, but not all C code is
wrapped in `extern "C"`. For example, most Objective-C headers are not wrapped
in `extern "C"` because most Objective-C constructs have a compatible ABI
between Objective-C and Objective-C++.
**(3) Apply strategy #2 in C, Objective-C, and C++.** Doing so will change the
mapping strategy for non-annotated enums coming from Objective-C code, breaking
source stability to some extent.
Pros:
* Correct default in C++.
* Likely correct default in C.
* Simpler design: same rules in C and C++.
* Obvious how to implement, because there is no need to distinguish between
different header kinds.
Cons:
* Likely not correct default in Objective-C. In idiomatic Objective-C code enums
with "enum nature" are declared with `NS_ENUM`, and bitfields are declared
with `NS_OPTIONS`, which leaves plain enums to cover the unusual cases.
* Breaking source compatibility by changing how C enums are imported. There are
ways to mitigate this issue, for example, continue importing enumerators as
computed global variables, marking them deprecated.
Strategy #3 is best for C++ code, but it is unclear if consequences for
Objective-C would be acceptable. We should gather data about usage of plain
enums in idiomatic C++ code and in Apple's SDKs and evaluate the absolute amount
of source breakage.
## Templates
From 10,000 feet, C++ templates are similar to Swift generics. However, there
are multiple semantic gaps between them.
C++ templates perform a syntactic substitution. Any type that supports the
syntax invoked in the template is a valid template argument. However, we don't
know exactly what syntax a type is required to support until we try to
substitute that type into a template. Generics in Swift are constraint-based and
require modular type checking.
C++ templates require instantiation at compile time. It is not possible to
compile a template without substituting concrete types in. It is not specified
whether Swift generics are instantiated or not, the compiler can make either
choice and the user can't tell the difference.
C++ templates support specialization. Swift generics don't allow specialization;
they provide a different mechanism (protocol requirements) to make one generic
function behave differently for different types.
C++ class templates support specialization, which allows defining completely
different APIs across specializations of the same class. All instantiations of a
generic type in Swift have the API described in the generic declaration (with
type parameters substituted), plus applicable conditional extensions.
C++ templates support non-type template parameters, template
parameters, and parameter packs (variadic generics), all of which are not
supported in Swift.
### Function templates
Since C++ uses an instantiation-based model for templates, the most obvious way
to import C++ function templates in Swift is to only import full specializations
as regular functions. However, it would be most ergonomic to import function
templates as Swift generic functions. Let's explore both options and see how far
we can go.
### Function templates: import as Swift generic functions
Let's take explicit specializations out of the picture for the purposes of
presenting the API in Swift. Since overload resolution in C++ ignores
specializations of function templates, we can ignore them, too, when importing a
function template into Swift.
```c++
// C++ header.
template<typename T>
void functionTemplate(T t) { ... }
// Any number of explicit specializations may follow.
template<>
void functionTemplate(int x) { ... }
```
```swift
// C++ header imported in Swift.
func functionTemplate<T>(_ t: T)
// No need to import explicit specializations as separate APIs.
```
Of course, when Swift code calls `functionTemplate` with an `Int32`, it should
call the correct explicit specialization, `functionTemplate<int>`, even though
it is not shown in the imported Swift API.
### Function templates: allow to specify template arguments
Calls to Swift generic functions always deduce generic arguments from the call.
C++ allows the caller to either deduce the arguments, or specify them
explicitly. Sometimes it is important to invoke C++ function templates with
specific template arguments, so it would make sense to expose this capability in
Swift.
We suggest to allow Swift code to use the angle bracket syntax to explicitly
specify function template arguments at the callsite. If template arguments are
not specified, we should run template argument deduction. (TODO: explain in more
detail how template argument deduction will work starting from Swift types.)
```swift
// Usage example in Swift.
functionTemplate<Int>(42)
```
How to specify C++ types that map ambiguously into Swift, for example, `int &`
or `int *`, both of which map to `UnsafePointer<Int>`? The C++ support module in
the Swift standard library could provide Swift typealiases that would map
unambiguously to C++.
```swift
// C++ support module in the Swift standard library.
typealias CxxPointer<T> = UnsafeMutablePointer<T> // T*
typealias CxxConstPointer<T> = UnsafePointer<T> // const T*
typealias CxxRef<T> = UnsafeMutablePointer<T> // T&
typealias CxxConstRef<T> = UnsafePointer<T> // const T&
typealias CxxRvalueRef<T> = UnsafeMutablePointer<T> // T&&
typealias CxxConstRvalueRef<T> = UnsafePointer<T> // const T&&
```
```swift
// Usage example in Swift.
var x = 42
// Calls `functionTemplate<int>`.
functionTemplate<Int>(x)
// Calls `functionTemplate<const int *>`.
functionTemplate<CxxConstPointer<Int>>(&x)
// Calls `functionTemplate<int &>`.
functionTemplate<CxxRef<Int>>(&x)
```
Although it is desirable to map rvalue references to Swift's `inout`, it is not
possible to do so when importing a C++ function template as a C++ generic
function; "inout"-ness of an argument can't change across instantiations of a
generic function in Swift.
### Function templates: calls to specific specializations
From an implementation point of view, it is easy to compile Swift code that
calls C++ function templates if template arguments are concrete types that are
obvious at the callsite (either deduced or specified explicitly). In other
words, it is easy to compile the call if Swift compiler can easily deduce which
specialization of the C++ function template to call. The imported API could
still look like a Swift generic function:
```swift
// C++ header imported in Swift.
func functionTemplate<T>(_ t: T)
// No need to import explicit specializations as separate APIs.
```
```swift
// Usage example in Swift, works.
func callFunctionTemplate() {
functionTemplate(0) // OK: calls the `functionTemplate<int>` specialization.
}
```
If we stop here, `functionTemplate` would look like a generic function in Swift,
but it would not be callable from generic code. This option might be good enough
for the most basic mapping of function templates in Swift. But can we allow
calling C++ function templates from Swift generics?
### Function templates: calls with generic type parameters
The primary implementation difficulty in allowing generic Swift code to call C++
function templates is that the C++ compiler can only compile full
specializations, but Swift generics can run unspecialized.
```swift
// Usage example in Swift.
func myGenericFunction<T>(_ t: T) {
functionTemplate(0) // OK: calls the `functionTemplate<int>` specialization.
functionTemplate(t) // compilation error: can't call a C++ function template, because we don't know what `T` is, and therefore, can't select which specialization to call.
}
```
We could force Swift generics to be instantiated if they use a C++ template.
Fully generic entry points will be still emitted to fulfill ABI expectations,
but they would trap.
```swift
// C++ header imported in Swift.
@_must_specialize
func functionTemplate<T>(_ t: T)
```
```swift
// Usage example in Swift.
@_must_specialize
func genericFunction<T>(_ t: T) {
functionTemplate<T>(t) // OK!
}
struct GenericStruct<T> {
init GenericStruct(_ t: T) { self.t = t }
var t: T
@_must_specialize
func callGenericFunction() {
genericFunction(t) // OK!
}
}
func example() {
GenericStruct(42).callGenericFunction()
}
```
We introduce a `@_must_specialize` attribute for generic functions that must be
instantiated in order to be called. The importer marks all Swift generic
functions that are backed by a C++ template as `@_must_specialize`, and from
there the Swift compiler infers the attribute for all users.
This analysis relies on over-approximating the dynamic callgraph with the static
callgraph. The static callgraph is feasible to compute in most cases, since
Swift has very limited ways to abstract over an unspecialized generic function.
Specifically, Swift does not have generic closures. Swift does allow protocols
to have requirements for generic functions though.
### Function templates: importing as real generic functions
If we know the complete set of allowed type arguments to a C++ function
template, we could import it as an actual Swift generic function that performs
dynamic dispatch.
```c++
// C++ header.
template<typename T>
void functionTemplate(T t) { ... }
// Any number of explicit specializations may follow.
template<>
void functionTemplate(int x) { ... }
```
Let's say it is known that `functionTemplate` can only take `Int` and `UInt`.
```swift
// C++ header imported in Swift.
func _cxx_functionTemplate<T>(_ t: T) // Imported as explained before.
func functionTemplate<T>(_ t: T) {
if T == Int.self {
return _cxx_functionTemplate(t as! Int)
}
if T == UInt.self {
return _cxx_functionTemplate(t as! UInt)
}
fatalError()
}
```
The user can write this code themselves (in an overlay, for example), or if we
can communicate the allowed list of types to the importer, it can synthesize the
function for us. Either way, the result is that we get a true generic Swift
function.
### Class templates
Class templates pose the same challenges as function templates regarding
separate compilation. In addition to that, we can't ignore explicit
specializations of class templates when importing the API to Swift.
We could ignore explicit specializations of function templates, because they
don't affect the API. Explicit specializations of class templates can
dramatically change the API of the type.
### Class templates: Importing full class template instantiations
A class template instantiation could be imported as a struct named
`__CxxTemplateInst` plus Itanium mangled type of the instantiation (see the
`type` production in the Itanium specification). Note that Itanium mangling is
used on all platforms, regardless of the ABI of the C++ toolchain, to ensure
that the mangled name is a valid Swift type name (this is not the case for MSVC
mangled names). A prefix with a double underscore (to ensure we have a reserved
C++ identifier) is added to limit the possibility for conflicts with names of
user-defined structs. The struct is notionally defined in the `__C` module,
similarly to regular C and C++ structs and classes. Consider the following C++
module:
```c++
// C++ header.
template<class T>
struct MagicWrapper {
T t;
};
struct MagicNumber {};
typedef MagicWrapper<MagicNumber> WrappedMagicNumber;
```
`WrappedMagicNumber` will be imported as a typealias for a struct
`__CxxTemplateInst12MagicWrapperI11MagicNumberE`. Interface of the imported
module will look as follows:
```swift
// C++ header imported to Swift.
struct __CxxTemplateInst12MagicWrapperI11MagicNumberE {
var t: MagicNumber
}
struct MagicNumber {}
typealias WrappedMagicNumber = __CxxTemplateInst12MagicWrapperI11MagicNumberE
```
### Class templates: importing specific specializations
Just like with calls to C++ function templates, it is easy to compile a use of a
C++ class templates if the usage in Swift code unambiguously specifies which
specialization should be used.
```c++
// C++ header.
template<typename T>
class ClassTemplate {};
```
```swift
// C++ header imported to Swift.
struct ClassTemplate<T> {}
```
```swift
// Usage example.
func useClassTemplate() {
var x = ClassTemplate<Int32>() // OK, uses `ClassTemplate<int>`.
}
```
If the class template provides specializations with completely different APIs,
we don't have an issue, because we only need to import specific
specializations into Swift.
```c++
// C++ header.
template<typename T>
class ClassTemplate {
void func1();
};
template<>
class ClassTemplate<int> {
void func2();
};
template<typename T>
class ClassTemplate<std::vector<T>> {
void func3();
};
```
```swift
// C++ header imported to Swift.
// A shell of a generic struct only used for name lookup.
struct ClassTemplate<T> {}
```
```swift
// Usage example.
func useClassTemplate() {
var x1 = ClassTemplate<Int8>() // OK
var x2 = ClassTemplate<Int32>() // OK
var x3 = ClassTemplate<cxx_std.vector<Int32>> // OK
}
```
When the Swift compiler sees `ClassTemplate<Int8>`, it translates the type to
C++, that is, `ClassTemplate<char>`. Then Swift compiler asks the Clang importer
to import that specialization. Clang importer instantiates the primary template
with `T=char` and imports the resulting `ClassTemplate<char>`. Same for all
other rereferences to `ClassTemplate`. At the end, we get:
```c++
// C++ header imported to Swift, as needed for the program above.
// A shell of a generic struct only used for name lookup.
struct ClassTemplate<T> {}
struct ClassTemplate<Int8> {
func func1()
}
struct ClassTemplate<Int32> {
func func2()
}
struct ClassTemplate<cxx_std.vector<Int32>> {
func func3()
}
```
Effectively, `ClassTemplate<Int8>`, `ClassTemplate<Int32>`, and
`ClassTemplate<cxx_std.vector<Int32>>` are completely unrelated types; they just
have angle brackets in their name. (By the way, the same is the case in C++.)
Advantages of this approach:
* Relatively straightforward to implement.
* Simple model, few or no corner cases.
Disadvantages of this approach:
* Users can only use complete specializations. In other words, users can't use a
C++ template from Swift generic and pass a generic type parameter to the C++
template.
### Class templates: using with generic type parameters
Many class templates don't define specializations that dramatically change the
API, or use features like non-type template parameters that don't exist in Swift
generics. It is desirable to import such templates as Swift generics directly.
With a lightweight static analysis, or with annotations in the C++ header, the
compiler would recognize such a type and import the API shared by all
instantiations into Swift.
Similarly to our treatment of function templates described above, we can
annotate the transitive closure of generic Swift code that uses C++ class
templates with `@_must_specialize`.
### Class templates: using in generic code through a synthesized protocol
Class templates that have a uniform API across all specializations could be made
to conform to a Swift protocol, which would facilitate passing them to generic
code.
```c++
// C++ header.
template<typename T>
class MyClassTemplate {
void func1(T t);
};
```
```swift
// C++ header imported in Swift.
protocol MyClassTemplateProtocol {
associatedtype T
func func1(_ t: T)
}
struct MyClassTemplate<T> : MyClassTemplateProtocol {}
```
In this model, the Swift compiler can still import only specific specializations
of `MyClassTemplate`. The new part is that the Swift compiler will synthesize a
protocol, `MyClassTemplateProtocol`, that contains APIs shared by all
specializations. The Swift compiler will also make every imported specialization
of `MyClassTemplate` conform to `MyClassTemplateProtocol`.
This way, we solved the issue of specializations being unrelated types: now they
all conform to a common protocol, and therefore, generic code can operate
transparently on any specialization.
```swift
// Usage example.
// Use a C++ class template from a Swift generic function without naming a
// specific specialization.
func useGeneric<SomeSpecialization>(_ classTemplate: SomeSpecialization, _ t: SomeSpecialization.T)
where SomeSpecialization: MyClassTemplateProtocol
{
classTemplate.func1(t)
}
func useConcrete() {
var classTemplate = MyClassTemplate<Int32>()
classTemplate.func1(0)
useGeneric(classTemplate, 0)
}
```
### Class templates: importing as real generic structs
If we know the complete set of allowed type arguments to a C++ struct
template, we could import it as an actual Swift generic struct. Every method of
that struct will perform dynamic dispatch based on type parameters. See
the section about function templates for more details.
### Mapping SFINAE
We can map SFINAE to generic constraints and to conditional extensions.
TODO
### Variadic templates
TODO
### Non-type template parameters
TODO
### Template template parameters
TODO
## Overloaded operators
TODO: Mapping C++'s operators to Equatable, Comparable, Hashable.
## <a name="operator-star-operator-arrow"></a> `operator*`, `operator->`
TODO
## <a name="operator-square-brackets"></a> `operator[]`
`operator[]` semantically maps well to Swift's `subscript`.
```c++
// C++ header.
class MyCxxContainer {
public:
const double& operator[](int i) const;
double& operator[](int i);
};
```
```swift
// C++ header imported in Swift.
struct MyCxxContainer {
public subscript(_ i: Int) -> Double { get set }
}
```
The synthesized `subscript` uses the `_read` and `_modify` generalized accessors
to forward the memory address to the caller.
```swift
// Implementation details of the imported API.
struct MyCxxCollection {
// const double& operator[](int i) const;
private func _operatorBracketsConst(_ i: Int) -> UnsafePointer<Double>
// double& operator[](int i);
private func _operatorBrackets(_: Int) -> UnsafeMutablePointer<Double>
// Swifty API.
public subscript(_ i: Int) -> Double {
_read {
yield _operatorBracketsConst(i).pointee
}
_modify {
yield &_operatorBrackets(i).pointee
}
}
}
```
## <a name="operator-parentheses"></a> `operator()`
Swift has an equivalent for C++'s `operator()`: `callAsFunction` (introduced in
[SE-0253: Callable values of user-defined nominal
types](https://github.com/apple/swift-evolution/blob/main/proposals/0253-callable.md)).
```c++
// C++ header.
class MultiplyIntDouble {
public:
double operator()(int x, double y);
};
```
```c++
// C++ header imported in Swift.
struct MultiplyIntDouble {
public func callAsFunction(_ x: Int, _ y: Double) -> Double { ... }
}
```
This mapping rule would handle the call operator of `std::function`,
`function_ref` and similar types.
## Literal operators
TODO
## Exceptions
### Background
C++ unfortunately has the opposite default to Swift where exception throwing is
concerned. Any C++ function that is not explicitly marked `noexcept` must be
assumed to be potentially throwing, even though many such functions don't throw
in practice.
If we imported all of these functions into Swift as `throws` functions, the code
calling them would be littered with `try!`s. Requiring all imported functions (and
everything they call transitively) to be marked `noexcept` also seems excessively
burdensome and is not idiomatic C++.
### Baseline functionality: Import functions as non-throwing, terminate on uncaught C++ exceptions
In the first iteration of C++ interop, we will import all C++ functions as
non-throwing Swift functions. If a C++ function called from Swift throws an
exception that is not caught within the C++ code, the program will terminate.
This approach is similar to that taken by the [Python interop
library](https://github.com/pvieito/PythonKit/blob/master/PythonKit/Python.swift),
which also terminates the program by default if a Python exception is raised and
not caught within the Python code.
If exceptions thrown in C++ need to be handled in Swift, this can be done by
writing a C++ wrapper that catches the exception and returns a corresponding
error object.
### Extended functionality: Optionally propagate exceptions to Swift
If we find that developers routinely need to handle C++ exceptions in Swift,
writing C++ wrappers as described above will obviously not be a satisfactory
solution. In this case, we will add an option to propagate C++ exceptions as
Swift exceptions; this will be backward compatible with the baseline approach
described above.
We again take inspiration from Python interop. There, appending `.throwing` to
the function name calls a variant of the function that propagates the Python
exception to Swift.
It isn't really practical to do something exactly analogous in C++ interop. We
could import each function twice and identify the throwing version by a name
suffix or a dummy parameter. However, this solution would bloat the interface of
imported classes, and it would not be universal: Name suffixes can't be used
with constructors or operators; a dummy parameter could be used with most
constructors, but still doesn't work for default constructors or operators.
Instead, we propose extending Swift with a `throws!` marker. A function marked
with `throws!` can potentially throw exceptions, but the function does not need
to be called with `try`. If the function _is_ called with `try`, exceptions are
handled as they would be for a normal throwing function. If the function is not
called with `try` and the function raises an exception, the program is
terminated. These semantics are close to C++ exception handling semantics.
All C++ functions that are not marked `noexcept` would be imported as `throws!`
functions; `noexcept` functions would be imported as non-throwing functions.
This brief sketch obviously leaves many questions unanswered on the detailed
semantics that a `throws!` feature would have, for example whether user-written
Swift code should be allowed to use `throws!` -- see also [this forum
discussion](https://forums.swift.org/t/handling-c-exceptions/34823). Before we
take any steps towards implementing C++ exception propagation, we will submit a
formal Swift Evolution proposal for the `throws!` feature.
The other question to answer is how we would map the C++ exception to a
corresponding Swift object implementing `Error`. In theory, C++ allows
objects of any copy-initializable type to be thrown. In practice, most
user-defined C++ exceptions derive from `std::exception`, so it would be natural
to propagate C++ exceptions as the Swift-imported equivalent of
`std::exception` and make that type implement `Error`. We could add a separate
fallback error type (e.g. `CxxUnknownException`) for the case where the
exception does not derive from `std::exception`.
As `std::exception` is a polymorphic type, the details of how `std::exception`
will be represented in Swift will need to wait until we have finalized how
polymorphism is handled (see also the section on [virtual member
functions](#virtual-member-functions)).
### Implementation
Many common C++ ABIs allow the default behavior (terminate the program if a
C++ exception is thrown) to be implemented at zero cost. In particular, it is not
necessary to wrap every C++ function in a synthesized try-catch block.
For example, the Itanium C++ ABI defines a so-called personality routine that is
called for each stack frame as the stack is being unwound. The idea is that
different languages can have different personality routines, so that different
languages can co-exist on the stack and can each define their own stack frame
cleanup logic.
The stack unwinding infrastructure finds the correct personality routine by
consulting a so-called unwind table, which maps program counter ranges to
personality routines.
We would define unwind table entries covering all Swift code that does not
attempt to handle C++ exceptions and have these entries map to a personality
routine that simply terminates the program.
If exception support is turned off in the C++ compiler by passing `-Xcc
-fno-exceptions` to `swiftc`, we assume that the C++ code never throws
exceptions and will not emit any unwind table entries for Swift code.
## Atomics
TODO
## Importing non-const pointer as extra return values
TODO
# Enhancing C++ API mapping into Swift with bridging
## Bridging data types with different memory layout
When we import a C++ `T` into Swift as a type `U`, in the general case we must
ensure that `T` and `U` have identical memory layout. For example, Swift's `Int8`
and C++'s `int8_t` have identical memory layout, and therefore, we can import
`int8_t` as `Int8` everywhere.
If `T` and `U` have even slightly different memory layouts, we must invoke a
bridging function at the interop boundary. Further sections in this document
provide many examples of such type pairs, but to give an example, consider
`std::vector<T>` in C++, which is semantically similar to `Array<T>` in Swift,
but has a completely different memory layout. If we want to map them to one
another, but must keep the memory layout of both types unchanged, we must
convert the `std::vector<T>` value into an `Array<T>` value when the program
execution crosses the language boundary.
For example:
```c++
// C++ header.
std::vector<int> IncrementVectorValues(std::vector<int> v);
```
```swift
// C++ header imported in Swift.
// Note: no C++ vectors!
func IncrementVectorValues(_ v: [CInt]) -> [CInt]
```
```swift
// Using the imported C++ API in Swift.
func callIncrementVectorValues() -> CInt {
var xs: [CInt] = IncrementVectorValues([10, 20, 30])
return xs[0] // = 11.
}
```
## Bridging: behind the scenes
Here's a simplified description of how Swift implements bridging. Behind the
scenes, the function `IncrementVectorValues` is imported as is, with C++ data
types:
```c++
// C header imported in Swift, behind the scenes:
func _cxx_IncrementVectorValues(std.vector<CInt> v) -> std.vector<CInt>
```
C++ bridging support code provides a function that converts a `std::vector` to a
Swift `Array` and vice versa:
```swift
// Swift standard library, C++ support module.
func StdVectorToArray<T>(_ vector: std.vector<T>) -> [T]
func ArrayToStdVector<T>(_ array: [T]) -> std.vector<T>
```
Each caller is transformed to call the bridging function:
```
// Using the imported C++ API in Swift: code written by the user.
func callIncrementVectorValues() -> CInt {
var xs: [CInt] = IncrementVectorValues([10, 20, 30])
return xs[0] // = 11.
}
```
```swift
// Using the imported C++ API in Swift: code rewritten by the type checker.
func callGetVector() -> CInt {
var xs: [CInt] =
StdVectorToArray(_cxx_IncrementVectorValues(ArrayToStdVector([10, 20, 30])))
return xs[0] // = 11.
}
```
A naive implementation of `StdVectorToArray` and `ArrayToStdVector` would have
to copy the container's elements. However, with enough cooperation between the
C++ standard library and the Swift standard library, Swift `Array` could take
ownership of `std::vector`'s storage and vice versa in O(1), avoiding making a
copy. Such cooperation would likely require changing the ABI of at least one of
the types, so it would not be feasible to implement in all environments.
## Bridging does not work in every context
Bridging between types with different memory layouts does not work universally.
For example, just because a C++ type `T` can be bridged to a Swift type `U`, it
does not follow that we can bridge a `T*` to an `UnsafeMutablePointer<U>`.
```c++
// C++ header.
const std::vector<int> *GetPtrToVector();
```
```swift
// C++ header imported in Swift.
// We can't bridge types like in the example below, it is not implementable.
// The underlying C++ function returns a vector with unclear ownership semantics,
// but we need to return a pointer to a Swift Array.
// If the bridging code allocates the Swift Array on the heap, what would own it?
// If the bridging code does not allocate a new Array, where does it get the
// storage from?
func GetPtrToVector() -> UnsafePointer<[CInt]>
// OK.
func GetPtrToVector() -> UnsafePointer<std.vector<CInt>>
```
Therefore, we can perform non-trivial bridging only in a limited number of
contexts. In all remaining places C++ types must be imported according to the
general rules.
As a consequence, every non-trivial bridging solution needs a fallback that does
not require adjusting the memory layout.
## <a name="bridging-std-function"></a> Bridging `std::function`
`std::function` in C++ is similar to closures in Swift. The primary difference
is that `std::function` has an empty state, similarly to function pointers,
while Swift closures don't.
Due to allowing an empty state, `std::function` must be mapped to an optional
Swift closure, unless annotated as non-nullable.
To convert a non-empty `std::function` value to a Swift closure, we need to
define a thunk and allocate a closure context on the heap. The new closure
context will point to a copy of the `std::function` value. The thunk will use a
Swift calling convention, and it will forward the arguments to
`std::function::operator()()` using the C++ calling convention.
A thunk like this will not cost much in terms of code size. The primary cost of
the thunk will come from dynamic dispatch. We will have double dynamic dispatch:
first one at the callsite that calls the Swift closure and ends up calling the
thunk, and second one from the thunk to the C++ code wrapped in `std::function`.
Another issue is branch predictor pollution: there will be a single thunk
backing all closures with the same signature. Indirect branches from thunk will
be difficult to predict for the branch predictor.
There is additional cost contributed by reference counting: closures in Swift
are reference counted, while `std::function` isn't.
Finally, allocating a new closure context on the heap is a cost to be paid on
every conversion from a C++ `std::function` to a Swift closure.
## <a name="bridging-std-string"></a> Bridging `std::string`
Ergonomically, the best mapping of C++'s `std::string` is Swift's `String`. Both
types support nul bytes (the conversion has to take them into account and cannot
assume nul-terminated strings). However, there's a semantic gap: Swift strings
require text to be valid UTF-8.
We have a couple of options to address the UTF-8 issue:
* Trust C++ code to only store UTF-8 text in strings, and map them to Swift's
`String` where possible. Perform a runtime check for UTF-8 validity during the
conversion. Allow to annotate `std::string`s that store binary data, and map
those as either Swift's `Array` or `std::string`.
* Assume `std::string`s store binary data, and map them to according to the
regular interop rules to `cxx_std.string`. Allow users to annotate UTF-8
strings as such, and map them to Swift's `String`.
The annotations could be inferred with a dynamic analysis tool that would track
which `std::string`s contain binary data.
Here's an example of API mapping if we decide to trust `std::string`s to store
UTF-8 data.
```c++
// C++ header.
class Employee {
public:
std::string DebugDescription() const;
[[swift::import_as_std_string]] std::string SerializedAsProtobuf() const;
};
```
```swift
// C++ header imported in Swift.
struct Employee {
func DebugDescription() -> String
func SerializedAsProtobuf() -> std.string
}
```
To avoid copying data unnecessarily, we need the C++ and Swift standard
libraries to cooperate, so that Swift's `String` can take ownership of
`std::string`'s heap allocation, and vice versa.
Character data in `Swift.String` is stored in a reference-counted object.
`Swift.String` can take ownership of `std::string` by transferring ownership of
`std::string` to a newly-allocated reference-counted object. Swift/Objective-C
bridging of `NSString` already works exactly this way.
On non-Objective-C platforms, `Swift.String` assumes that the character data is
tail-allocated in the reference-counted object; this assumption will have to be
replaced with a branch. Therefore, adding this sort of bridging on
non-Objective-C platforms will create a certain (small) performance penalty. It
is important to note that this performance penalty has been always affecting
Objective-C platforms and it is considered acceptable.
We could eliminate the branch on non-Objective-C platforms by changing
`Swift.String` there to always use a reference-counted object with an
`std::string` in it as the backing storage. The disadvantage of such memory
layout is that `Swift.String` would need to dereference two levels of
indirection to access to character data, instead of one like we have today.
`std::string` can't take ownership of `Swift.String`'s reference-counted object,
because `std::string` has no branches in its code that retrieves the pointer to
the character data and in its deallocation code. Adding branches there is
certainly possible, but will likely lead to regressions for many C++
applications, including ones that don't use Swift. Therefore, this approach
looks like a non-starter.
Therefore, the only viable approach for O(1) bidirectional bridging is having
`Swift.String` use `std::string` as its backing storage, and taking the penalty
of a double-indirection to access character data.
If one-way C++-to-Swift bridging is sufficient, it can be implemented with a
branch in the `Swift.String` code that retrieves a pointer to character data.
We can implement one-way O(1) Swift-to-C++ bridging by embedding a fake
`std::string` in the `Swift.String` buffer. Such a `std::string` instance would
not be full-fledged, and would be only good for reading from it; its destructor
can never be called.
## <a name="bridging-std-vector"></a> Bridging `std::vector`
Ergonomically, the best mapping of C++'s `std::vector` is Swift's `Array`.
Except for the case of `std::vector<bool>`, the constraints for `Swift.Array`
taking ownership of `std::vector`'s element buffer and vice versa are identical
to string bridging.
## <a name="bridging-std-set-std-map"></a> Bridging `std::set`, `std::map`
Swift standard library does not provide collections with semantics similar to
`std::set` and `std::map`, so they can't be meaningfully bridged to any Swift
vocabulary type. Therefore, they will be imported as `std.set` and `std.map`.
It would be useful to provide ergonomic ways to convert `std.set` and `std.map`
to `Swift.Set` and `Swift.Dictionary`, since `std::set` and `std::map` are
sometimes used in C++ APIs (especially older ones) when the element order
doesn't matter.
## <a name="bridging-std-unordered-set-std-unordered-map"></a> Bridging `std::unordered_set`, `std::unordered_map`
The most ergonomic mapping of `std::unordered_set` and `std::unordered_map` are
`Swift.Set` and `Swift.Dictionary`.
The constraints for these Swift types taking ownership of C++'s storage buffers
and vice versa are quite similar to string bridging. An interesting new point to
highlight is that the `Swift.Set` and `Swift.Dictionary` types would need to use
the hash function defined in C++ for C++ types. It should be possible to expose
the C++ hash function in Swift as a conformance to the `Hashable` protocol, or
as a conformance to a new C++-specific protocol for hashing.
## <a name="bridging-std-tuple-std-pair"></a> Bridging `std::tuple`, `std::pair`
Ergonomically, the best mapping of C++'s `std::tuple` and `std::pair` are
Swift's tuples.
Tuple and pair elements have to be copied to implement non-trivial bridging. It
is unreasonable to introduce a dual representation and require a branch to
access tuple elements either in C++ or Swift.
However, there are only so many different ways to lay out a `std::pair` in
memory. In fact, it is almost certainly a struct with exactly two data members,
`first` and `second`, in that order. When `std::pair<T, U>` and Swift's tuple
`(T, U)` happen to use the same layout, we could bridge them trivially, without
copying the data.
```c++
// C++ header.
std::pair<int, int> *GetPairPtr();
```
```swift
// C++ header imported in Swift.
UnsafeMutablePointer<(Int, Int)> GetPairPtr()
```
`std::tuple` is more complex and has more viable implementation options compared
to `std::pair`. For example, `std::tuple` is laid out in forward order by
libc++, and in backward order by libstdc++. Therefore, if libc++ is used,
there's a good chance that the memory layout of `std::tuple` matches the memory
layout of the corresponding Swift tuple, and we could bridge them trivially.
The disadvantage of the techniques described above is that they depend on
implementation details of the standard library, and as those change (or if the
user switches to a different standard library altogether), the API in Swift
might change as well.
## <a name="bridging-std-span"></a> Bridging `std::span`
The difficulty with `std::span<T>` is that it has a different API in Swift
depending on whether `T` is `const` or not.
```c++
// C++ standard library.
template<typename T>
class span {
public:
constexpr T& front() const noexcept;
};
```
```c++
// C++ standard library imported in Swift.
// When T is non-const.
struct span<T> {
public func front() -> UnsafeMutablePointer<T>
}
// When T is const.
struct span<T> {
public func front() -> UnsafePointer<T>
}
// Need to choose one way to import, can't have both!
```
The easiest way to deal with this is to only import `std::span<T>` as full
specialization (the fallback way to import templates). However, that would not
be very ergonomic, and would prevent other templates that use `std::span` from
being imported as generics in Swift.
A more ergonomic way would be to import `std::span` as two generic structs in
Swift, selecting the appropriate one depending on constness.
```swift
// C++ standard library imported in Swift.
struct mutable_span<T> {
public func front() -> UnsafeMutablePointer<T>
}
struct const_span<T> {
public func front() -> UnsafePointer<T>
}
```
```c++
// C++ header.
std::span<int> GetMutableIntSpan();
std::span<const int> GetConstIntSpan();
```
```swift
// C++ header imported in Swift.
func GetMutableIntSpan() -> std.mutable_span<Int>
func GetConstIntSpan() -> std.const_span<Int>
```
## Standard C++ containers in general
It seems appropriate to provide an overlay that adds `Swift.Collection`
conformances to C++ container types.
## Custom C++ containers
The importer could try to recognize custom C++ containers and synthesize
`Swift.Collection` conformances, however, that seems fragile: custom containers
often don't implement the complete container API as required by the standard, or
deviate from it in subtle ways.
It seems best to add `Swift.Collection` conformances in overlays.
## <a name="bridging-absl-hash-set-map"></a> Bridging `absl::flat_hash_{set,map}`, `absl::node_hash_{set,map}`
Projects that use Abseil often use Abseil hash tables a lot more than standard
containers. However the same is also true about other libraries, like Boost or
Qt. Therefore, privileging a third-party library in C++/Swift interop seems
inappropriate. Abseil, Boost, and Qt should be treated just like user-written
code. Library vendors can provide annotations and Swift overlays to improve the
API in Swift.
# Enhancing C++ API mapping into Swift with annotations
## Annotation workflow
Annotations in C headers are employed by the Swift / C interop today (for
example, nullability annotations). However, these annotations must be added to
headers manually. How could tools infer annotations?
**Online inference at compile-time.** The Swift compiler could infer annotations
from information available in the headers. For example:
```c++
// example.h
class Example {
public:
int *get_mutable_value() { return &value; }
// The Swift compiler infers that the return type is `int * _Nonnull` because
// the function never returns nullptr.
};
```
The problem with this approach is that it is making API decisions based on API
implementation details, without letting the API owner to intervene. It is going
to be fragile in the long run: no-op changes to implementation details of C++
APIs can tip annotation inference one way or the other, and unintentionally
change the Swift API. Imagine that the example above is refactored to:
```c++
// example.h
class Example {
public:
int *get_mutable_value() { return get_mutable_value_impl(); }
private:
int *get_mutable_value_impl(); // defined in example.cc
};
// The Swift compiler does not know whether `get_mutable_value_impl()`
// can return nullptr or not, therefore its return type is
// `int * _Null_unspecified`. Therefore, the return type of
// `get_mutable_value()` is now changed to `int * _Null_unspecified` as well.
```
API declarations should be the source of truth for API information; this also
aligns with expectations of C++ API owners.
**Offline inference.** The concerns about inspecting implementation details for
inference would be alleviated if inference tooling produced a source code patch
that would be reviewed by a human and adjusted if necessary before being
committed.
The ideal option is to add annotations directly to the header, to make the API
contract obvious to all readers and API owners. However, sometimes API owners
don't want to change the header, or can't be reached. In those cases,
annotations can be added to a sidecar file, removing the need to change the
header.
A sidecar annotation file allows to add arbitrary attributes to declarations
parsed from a header file. You can find examples of such files in the [apinotes
directory](../apinotes). APINotes files
are handled by the [APINotes library in
Clang](https://github.com/apple/llvm-project/tree/apple/main/clang/lib/APINotes).
Clang reads an APINotes file alongside the header file; Clang injects attributes
specified by APINotes into the AST parsed from the header.
## Tooling to infer nullability annotations
Nullability annotations in C++ headers are useful not only for Swift / C++
interop; they also document the intended API contract to C++ API users.
Nullability annotations can be validated by static and dynamic analysis tooling
in C++ (e.g., UBSan can be extended to detect assignments of `nullptr` to
`_Nonnull` pointers).
To infer nullability annotations we can use a combination of static and dynamic
analysis. Static analysis could infer nullability in more obvious cases -- along
with some confidence score, while dynamic analysis could provide insight into
arbitrarily complex APIs and data structures, with the usual caveat that the
inference results are only as good as the test cases.
There is a lot of existing research about detecting nullability issues in C and
C++ with static analysis, so we are not discussing the design of potential
static analysis tooling here. However, we are not aware of existing dynamic
analysis tooling that infers nullability.
Nullability inference based on dynamic analysis will use compile-time
instrumentation that is similar to UBSan for references, but instead of
producing a fatal error upon a nullptr store, we will record this fact and
continue. For each source-level pointer variable and class member declaration,
the compiler will allocate a global boolean flag that tracks nullability, and a
usage counter, which will be used to gauge confidence. The nullability flags are
initialized to "false" at program startup, usage counters are initialized to
zero. Each store into the pointer variables is instrumented, and when a nullptr
is stored, the corresponding flag is set to "true". Either way, the usage
counter is incremented. At program shutdown (or when signalled somehow), the
inferred nullability flags and usage counters are saved to disk.
## APIs that take a pointer and count
Many C and C++ APIs take a pointer and count. It would be nice if we could
import them as a buffer pointer in Swift, given appropriate annotations:
```c++
// C++ header.
void example(int *xs, int count);
// TODO: figure out what annotations might look like.
```
```swift
// C++ header imported in Swift.
func example(_ xs: UnsafeMutableBufferPointer<CInt>)
```
# Current state of art: importing Swift code into C
The Swift compiler generates a header that C code can use.
TODO: add details.
# Importing Swift APIs into C++
TODO
## Resilient types
The semantic gap here is related to resilient types -- their size is unknown at
compile time. `std::vector<T>` needs to know `sizeof(T)` at compile time. This
is a common problem in Swift-to-C++ bridging in general, and it would be solved
with boxing. Boxes for resilient Swift types would have a fixed size.
# Forum discussions
The topic of Swift/C++ interoperability has been discussed on Swift forums
before:
* [C++ Interop](https://forums.swift.org/t/c-interop/25567)
* [C++ / Objective-C++ Interop](https://forums.swift.org/t/c-objective-c-interop/9989)
* [C++ support in Swift](https://forums.swift.org/t/c-support-in-swift/13313)
|