Save 37% off PRO during our Black Friday Sale! »

Answering the Existential Question

Answering the Existential Question

Given at FrenchKit 2018

4d6be90af74894fd132fb06dacec04d7?s=128

Samuel E. Giddins

September 21, 2018
Tweet

Transcript

  1. Answering the Existential Question Samuel Giddins 1

  2. @segiddins Mobile Developer Experience @ Square Trill Core Team 2

    — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  3. ⚠ Programming Language Nerdery Ahead 3 — Answering the Existential

    Question – Samuel Giddins @ FrenchKit 2018
  4. back to the beginning of time 4 — Answering the

    Existential Question – Samuel Giddins @ FrenchKit 2018
  5. Objective-C 5 — Answering the Existential Question – Samuel Giddins

    @ FrenchKit 2018
  6. NSArray<NSString *> *strings = @[ @"1", @2.string, ]; 6 —

    Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  7. id strings = [NSArray arrayWithObjects: [NSString stringWithUTF8String:"1"], [[NSNumber numberWithInteger:2] stringValue],

    nil ]; 7 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  8. Objective-C ⇢Based on SmallTalk ⇢All message-passaging 8 — Answering the

    Existential Question – Samuel Giddins @ FrenchKit 2018
  9. Message Passing receiver (self) determines what to do with each

    message 9 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  10. sound familiar? we still have that in today's Objective-C --

    id 10 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  11. id is really cool every objc object is an id,

    and you can send any message to id 11 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  12. even better you can recover class/type info from an id,

    get info like respondsToSelector: 12 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  13. You can ask an id what it is, and it

    will tell you. 13 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  14. I think, therefore I am. — Descartes 14 — Answering

    the Existential Question – Samuel Giddins @ FrenchKit 2018
  15. And there you have an existential! 15 — Answering the

    Existential Question – Samuel Giddins @ FrenchKit 2018
  16. Existential: something that knows what it is 16 — Answering

    the Existential Question – Samuel Giddins @ FrenchKit 2018
  17. Simple Sounding, Powerful Construct 17 — Answering the Existential Question

    – Samuel Giddins @ FrenchKit 2018
  18. existentials' power: ⇢Dynamic Casting ⇢print() ⇢Protocol Types 18 — Answering

    the Existential Question – Samuel Giddins @ FrenchKit 2018
  19. When Swift was first announced... 19 — Answering the Existential

    Question – Samuel Giddins @ FrenchKit 2018
  20. When Swift was first announced I worried that Ints and

    Bools having type information would make the language slow 20 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  21. ... would make the language slow like Ruby 21 —

    Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  22. In Ruby (like Objective-C), every object has an isa pointer

    22 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  23. struct objc_object { Class isa, uint_64t flags, // ivars... }

    23 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  24. That'd be a lot of overhead for every Int! 24

    — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  25. So how does this work? let i: Int = 5

    let a: Any = i as Any if let really_i = a as? Int { print("this works! i is \(really_i)") } 25 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  26. It doesn't work in a language like C, since an

    Int is just 32 bits 26 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  27. ! 27 — Answering the Existential Question – Samuel Giddins

    @ FrenchKit 2018
  28. ! Swift is smarter than C 28 — Answering the

    Existential Question – Samuel Giddins @ FrenchKit 2018
  29. Let's step through how these 5 lines of code work

    let i: Int = 5 let a: Any = i as Any if let really_i = a as? Int { print("this works! i is \(really_i)") } 29 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  30. This is equivalent to C: we just store the raw

    integer let i: Int = 5 let a: Any = i as Any if let really_i = a as? Int { print("this works! i is \(really_i)") } 30 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  31. This is just like doing an isKindOfClass: check in ObjC

    -- at runtime, we check the type metadata for a let i: Int = 5 let a: Any = i as Any if let really_i = a as? Int { print("this works! i is \(really_i)") } 31 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  32. And now really_i is back to being a normal Int

    -- and can be used with zero overhead let i: Int = 5 let a: Any = i as Any if let really_i = a as? Int { print("this works! i is \(really_i)") } 32 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  33. and that's it! ! 33 — Answering the Existential Question

    – Samuel Giddins @ FrenchKit 2018
  34. Oh, I missed this line? let i: Int = 5

    let a: Any = i as Any if let really_i = a as? Int { print("this works! i is \(really_i)") } 34 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  35. It turns out, this is the key to understanding how

    existentials work let a: Any = 5 as Any 35 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  36. let a: Any = 5 as Any ⇢Compiler sees a

    cast from Int Any ⇢ Int is a non-existential type, Any is existential ⇢ Compiler generates a "promotion" for 5, and stores it as a separate instance 36 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  37. let a: Any = 5 as Any ⇢A new ExistentialBox

    is allocated ⇢ Points to type metadata ⇢ Which also points to "thunks" for protocol witnesses ⇢ Points to (or copies) the underlying value 37 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  38. All code referring to an Any knows it needs to

    indirect through the Box 38 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  39. And any code that needs type metadata for a non-existential

    type Goes through the promotion process 39 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  40. Trill Wannabe Swift, written in Swift 40 — Answering the

    Existential Question – Samuel Giddins @ FrenchKit 2018
  41. type Foo { let bar: Int let baz: Bool }

    41 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  42. func foo(_ t: Any) -> Int { printf("[%s] entered\n", #function)

    if t is Int { printf("t is an Int!!\n") } return t as Int } func duplicate(_ t: Any) -> Any { return t as Int * 2 } 42 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  43. func main() { printf("[%s] entered\n", #function) let f = foo(1)

    var v: Any = 1 if !(v is Bool) { printf("v: %d\n", v as Int) } v = true if v is Bool { printf("v: %s\n", v as Bool ? "true" : "false") } v = Foo(bar: 20, baz: true) if v is Foo { let foo = v as Foo printf("v: Foo(bar: %d, baz: %s)\n", foo.bar, foo.baz ? "true" : "false") } printf("[%s] foo returned\n", #function) printf("%d\n", f) printf("%d\n", duplicate(2) as Int) } 43 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  44. /// TRILL_ANY is a special type understood by the Trill

    compiler as the /// representation of an Any value. typedef struct TRILL_ANY { void * _Nonnull _any; #ifdef __cplusplus inline AnyBox *_Nonnull any() { trill_assert(_any != nullptr && "passed a null value for Any"); return reinterpret_cast<AnyBox *>(_any); } inline AnyBox *_Nonnull operator->() noexcept { return any(); } inline operator AnyBox*_Nonnull() { return any(); } #endif } TRILL_ANY; 44 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  45. /// An AnyBox is a heap-allocated box that contains: ///

    - A pointer to the type metadata for an underlying value /// - A variably-sized payload struct AnyBox { const TypeMetadata *typeMetadata; static AnyBox *create(const TypeMetadata *metadata); AnyBox *copy(); void updateField(uint64_t fieldNum, AnyBox *newValue); void *value() { return reinterpret_cast<void *>( reinterpret_cast<uintptr_t>(this) + sizeof(AnyBox)); } void *fieldValuePtr(uint64_t fieldNum); AnyBox *extractField(uint64_t fieldNum); const FieldMetadata *fieldMetadata(uint64_t fieldNum); bool isNil(); }; 45 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  46. func codegenPromoteToAny(value: IRValue, type: DataType) -> IRValue { if case

    .any = type { if storage(for: type) == .reference { // If we're promoting an existing Any value of a reference type, just // thread it through. return value } else { // If we're promoting an existing Any value of a value type, // then this should just be a copy of the existing value. return codegenCopyAny(value: value) } } let allocateAny = codegenIntrinsic(named: "trill_allocateAny") let meta = codegenTypeMetadata(type) let castMeta = builder.buildBitCast(meta, type: PointerType.toVoid, name: "mc") let res = builder.buildCall(allocateAny, args: [castMeta], name: "aa") let valPtr = codegenAnyValuePtr(res, type: type) builder.buildStore(value, to: valPtr) return res } 46 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  47. What's next? 47 — Answering the Existential Question – Samuel

    Giddins @ FrenchKit 2018
  48. What's next for Swift? 48 — Answering the Existential Question

    – Samuel Giddins @ FrenchKit 2018
  49. Opaque Return Types func importantDates() -> opaque Collection where _.Element

    == Date 49 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  50. Type Erasure let ints = AnyCollection<Int> = [1, 2, 3]

    50 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  51. Generalized Existentials let strings: Any<Sequence where .Iterator.Element == String> =

    ["a", "b", "c"] 51 — Answering the Existential Question – Samuel Giddins @ FrenchKit 2018
  52. Samuel Giddins @segiddins 52 — Answering the Existential Question –

    Samuel Giddins @ FrenchKit 2018