$30 off During Our Annual Pro Sale. View Details »

Bridging the Language Gap

Bridging the Language Gap

Given at Craft Conference 2017 in Budapest

Samuel E. Giddins

April 28, 2017

More Decks by Samuel E. Giddins

Other Decks in Technology



  2. SAMUEL GIDDINS > Bundler > CocoaPods > RubyGems > Realm

    > Trill
  3. I work on lots of random projects across many communities.

  4. I write developer tools that occasionally work. Otherwise, I'm in

    a library at UChicago, studying something impractical.
  5. THE LANGUAGE GAP Hi, me llamo ש ָׁ ל וֹ

    ם .
  6. THE LANGUAGE GAP Gap a break in continuity Bridge something

    that is intended to reconcile or form a connection between two things
  7. THE LANGUAGE GAP > When we want to connect two

    or more languages to each other. > When we make languages talk to each other.
  8. Some languages can be translated perfectly: > Curry–Howard correspondence >

    Relationship between propositions & proofs and values & types > Turing machines > Turing completeness > !
  9. But for most, something is lost in translation


  11. WHY BOTHER? Every language has strengths & weaknesses

  12. Every language has a library of knowledge that is useful

    to refer to
  13. Is this sounding familiar?

  14. LANGUAGES > Ruby > Objective-C > Swift > C++ >

  15. WAYS TO TRANSLATE > Importer > FFI > XPC >

    Compiler Support > main()
  16. WAYS TO TRANSLATE Some are like Google Translate. They work

    on everything, but not very well. Some are like a paid translator. Amazing at going between exactly 2 languages, but very expensive.
  17. The Google Translate of Programming Language Translation

  18. $ echo I have earned those names. Bought and paid

    for them. I have earned those names. Bought and paid for them.
  19. The command line (or shell). Spawn a process, pass these

    arguments to main().
  20. > No context > No ongoing communication > Universal on

    any POSIX system
  21. HOW SHELL PROGRAMS WORK TOGETHER > 1 Program, 1 Process

    > Program Arguments > environ(7) > exit(3) > Side Effects
  22. A very general way of allowing programs in different languages

    to work together. But they don't work together very well.
  23. So, what's a step better than Google Translate?

  24. The Stack Overflow of Programming Language Translation

  25. > Run into a problem > Google it > Click

    on the first SO link > Copy-paste the solution that's already written

  27. FOREIGN FUNCTION INTERFACE Matches the ABI of the calling language

    with that of the language being called.
  28. ABI > How functions call each other > How data

    is laid out in memory > How memory is managed across function calls
  29. A "simple" example

  30. swift.swift func fib(_ x: Int) -> Int { guard x

    >= 1 else { fatalError("fib of a non-positive number is undefined, use Γ instead") } if x == 1 || x == 2 { return 1 } return fib(x - 1) + fib(x - 2) } c.c #include <stdio.h> int _TF5swift3fibFSiSi(int); int main(int argc, char *argv[]) { for (int i = 1; i < 15; ++i) { printf("fib(%d) = %d\n", i, _TF5swift3fibFSiSi(i)); } }
  31. Arcane Commands > clang c.c -c > swiftc swift.swift -c

    -parse-as-library > ld swift.o c.o ... -o main > ./main
  32. It works! fib(1) = 1 fib(2) = 1 fib(3) =

    2 fib(4) = 3 fib(5) = 5 fib(6) = 8 fib(7) = 13 fib(8) = 21 fib(9) = 34 fib(10) = 55 fib(11) = 89 fib(12) = 144 fib(13) = 233 fib(14) = 377
  33. FFI is brittle

  34. We relied on us knowing how the Swift program worked

    under the hood in order to call it from C.
  35. Now imagine writing out those function prototypes for an entire

    library. And remember, a single mistake means !.


  38. > Some context > Ongoing communication > Incredibly system dependent

  39. XPC OPTIONS > Sockets > HTTP > Mach XPC

  40. They all work by sharing ❇ state ❇ across processes.

  41. This is where the world of microservices fits in

  42. Standardized data formats like JSON, protobuf, GraphQL, etc make this

    much less painful
  43. But containerization is complicated, and introduces complexities beyond the language

  44. </hot take>

  45. As you can imagine, I'm still not a huge fan.

  46. COMPILER ✨

  47. This is the good kind of magic, I promise.

  48. This is like seeing inside the matrix. It's being able

    to call the name of the wind when your app encounters danger.
  49. Teach one compiler how to understand the structure of multiple

  50. Think C headers.

  51. Now, imagine you're not even writing C...

  52. Header: void print_the_thing(const char*); Swift: print_the_thing("the thing!")

  53. Remember the FFI ! above? We get all those benefits

    without any work
  54. No work no bugs

  55. The compiler isn't smarter. It's just as smart as the

    people who know all the intricacies of all the languages.
  56. Think memory management. Call conventions.

  57. In my free time, I work on a language called

  58. // ClangImporter.swift class ClangImporter { func run(in context: ASTContext) {

    importBuiltinAliases(into: context) importBuiltinFunctions(into: context) importDeclarations(for: URL(fileURLWithPath: ClangImporter.runtimeHeaderPath). appendingPathComponent("trill.h").path, in: context) if let path = ClangImporter.includeDir { for header in ClangImporter.headerFiles { importDeclarations(for: "\(path)/\(header)", in: context) } } } }
  59. // ClangImporter.swift class ClangImporter { func importDeclarations(for path: String, in

    context: ASTContext) { do { let file = try SourceFile(path: .file(URL(fileURLWithPath: path)), context: context) context.add(file) } catch { // do nothing } let tu: CXTranslationUnit do { tu = try translationUnit(for: path) } catch { context.error(error) return } let cursor = clang_getTranslationUnitCursor(tu) clang_visitChildrenWithBlock(cursor) { child, parent in let kind = clang_getCursorKind(child) switch kind { case CXCursor_TypedefDecl: self.importTypeDef(child, in: context) case CXCursor_EnumDecl: self.importEnum(child, in: context) case CXCursor_StructDecl: self.importStruct(child, in: context) case CXCursor_FunctionDecl: self.importFunction(child, in: context) case CXCursor_MacroDefinition: self.importMacro(child, in: tu, context: context) case CXCursor_UnionDecl: self.importUnion(child, context: context) case CXCursor_VarDecl: self.importVariableDeclation(child, in: tu, context: context) default: break } return CXChildVisit_Continue } clang_disposeTranslationUnit(tu) } }
  60. This is super ✨ meta ✨

  61. The Swift compiler knows how to import C headers The

    Trill compiler is written in Swift It uses a C compiler to read C headers
  62. But the result is a nearly seamless experience for users

  63. let foo = 10 let bar = garbage() func garbage()

    -> Int { printf("%s called!\n", #function) trill_printStackTrace() return 100 } func main() { printf("Garbage hasn't been called yet\n") printf("Foo: %d, bar: %d\n", foo, bar) printf("Bar: %d\n", bar) }
  64. That's Trill code. Calling C code.

  65. None
  66. It takes a lot of work to implement the magic

  67. But that work creates the sort of seamless experience we

    expect in today's world of many languages.
  68. If I can understand C, and Swift, and Ruby and

    Python... Why shouldn't all of them understand each other?
  69. Building bridges capable of carrying all this traffic is hard

    But you reap the benefits every day
  70. Back to the top: We work in multiple languages for

    a good reason
  71. We're most productive when we can pick & choose the

    best tool for the job at hand
  72. That happens most often and with the least friction when

    our languages can talk with each other
  73. Just like in human language, speaking happens in many different

  74. And choosing the right way to translate is just as

    important with machines as with people
  75. So, the answer with programming languages is the same as

    with upset people


  78. [insert obligatory Bridges of Siracusa County reference here]

  79. None
  80. In which Samuel answers random questions about language interop &

  81. @segiddins