WEBVTT 00:00.000 --> 00:11.520 Okay, everybody, my name is Konovat. 00:11.520 --> 00:18.520 I work on the Swift team at Apple, I focus on primarily concurrency in server use cases. 00:18.520 --> 00:23.840 You may remember me from my Java life, in which I worked on Akka or the reactive streams 00:23.840 --> 00:24.840 spec. 00:24.840 --> 00:29.560 And yeah, it's great to be back and working a little bit with the JVM. 00:29.560 --> 00:34.520 So I will introduce Swift a little bit, a quick show of guys who is aware of Swift, 00:34.520 --> 00:36.000 who has used Swift. 00:36.000 --> 00:38.240 Okay, not so bad. 00:38.240 --> 00:43.320 So Swift is an open source language, works in many platforms, anywhere from Linux, Windows, 00:43.320 --> 00:48.120 to embedded systems, in firmware, anything between also wasm, which I don't have on 00:48.120 --> 00:51.000 this line, slide, but I just remembered. 00:51.000 --> 00:55.720 And it's a natively compiled language, it has an explicit goal to feel familiar to people 00:55.720 --> 00:59.160 coming from other ecosystems, including Java. 00:59.160 --> 01:05.200 It has a memory safe by default, and has pretty cool features like concurrency safety, verified 01:05.200 --> 01:07.600 that compile plan as well. 01:07.600 --> 01:12.960 Since day one, Swift got an amazing C-eaten objective, C interrupt story, which is how it 01:12.960 --> 01:16.920 managed to slowly replace objective C on Apple platforms. 01:16.920 --> 01:22.600 And we since then added an amazing C++ interrupt, which is really cool, and today we're 01:22.600 --> 01:25.520 adding Java to that list. 01:25.520 --> 01:28.840 So why do we even care about this? 01:28.840 --> 01:32.880 But I'm merely because of memory safety, so why do we care about memory safety? 01:32.880 --> 01:39.080 Well, memory safety vulnerabilities of a number one security vulnerability. 01:39.080 --> 01:43.360 So if we want to reduce those, it would be great to adopt memory safe language as across 01:43.360 --> 01:45.240 the whole stack. 01:45.240 --> 01:50.080 And while Java is a good solution to that, you know, Java's memory safe, it's fine, 01:50.080 --> 01:54.640 but Java programs very often end up calling into native code at some point, and when 01:54.640 --> 01:56.240 you lose the safety. 01:56.240 --> 02:00.800 So it's our opinion that whenever you're writing native code, Swift should be the tool 02:00.800 --> 02:02.720 you should be using for that. 02:02.720 --> 02:08.480 So in order to facilitate that, we need to be supporting incremental adoption of Swift, 02:08.480 --> 02:14.040 and what also means, infertility with many languages, and making it both easy and efficient 02:14.040 --> 02:15.040 to do that. 02:15.040 --> 02:19.240 I call it dark early on in the main track, how they told me just about that. 02:19.240 --> 02:24.840 So we decade of moving more and more of an ecosystem into Swift and memory safety. 02:24.840 --> 02:29.400 So, you know, that was in the past already, but you can check the video. 02:29.400 --> 02:31.640 And where do we care about this? 02:31.640 --> 02:34.080 A great example is, of course, servers. 02:34.080 --> 02:38.760 So there's a lot of Java services out there, and we're increasing number of native code 02:38.760 --> 02:43.280 in libraries written in Swift, and we would like to be able to call them both efficiently 02:43.280 --> 02:45.200 and nicely. 02:45.200 --> 02:50.480 The other situation is that it's interesting for Java and native intro up is Android. 02:50.480 --> 02:54.720 The common thing that happens is people want to have a shared library that is the core 02:54.720 --> 02:59.600 of their apps, and maybe interesting algorithms, and they want to use it in the server, 02:59.600 --> 03:01.840 on vermobile apps, and anywhere already. 03:01.840 --> 03:06.440 So we think again, Swift is a good language to do that. 03:06.440 --> 03:13.040 Golds and directions here, this is a small distinction on the primarily written in some language, 03:13.040 --> 03:18.000 where you can be primarily written in Swift, and maybe you need to call it Java library. 03:18.000 --> 03:19.000 And we do support that. 03:19.000 --> 03:23.560 We have some Swift macros and JNI wrappers, and you can kind of do that, but that's not 03:23.560 --> 03:25.560 what this talk is about. 03:25.560 --> 03:29.760 The second situation is when you have a primarily written in Java application, and you 03:29.760 --> 03:36.040 want to call it native code as the previous talk, gracefully explained with the new APIs 03:36.040 --> 03:38.520 that we just got with FFM. 03:38.520 --> 03:43.520 So this is what I will be talking about today. 03:43.560 --> 03:48.080 So Java and Swift, of course, have many differences, but you'll be surprised to find that 03:48.080 --> 03:51.880 there are actually a bit similar when you look deeper. 03:51.880 --> 03:56.000 Of course, Java is all about classes and objects, but it has primitives, and Valhalla 03:56.000 --> 03:59.040 is bringing value types to the JVM as well. 03:59.040 --> 04:04.200 Swift on the other hand has classes, but it's very much focused on rich value types. 04:04.200 --> 04:08.720 So again, something that the slogan of Valhalla that calls like a class works like an 04:08.720 --> 04:12.640 int, very much applies to Swift's value types. 04:12.640 --> 04:18.520 Of course, both are memory managed, so we have a GC here in the JVM and automatic reference 04:18.520 --> 04:19.520 counting. 04:19.520 --> 04:24.840 Yes, but it is a difference, but for the most part of a developer's day, it's a very similar 04:24.840 --> 04:26.440 user experience. 04:26.440 --> 04:30.280 And the generics, of course, have a slight difference as well, so the JVM is type of 04:30.280 --> 04:36.120 type of area at one time, and Swift has generics, but with fully reified types, that 04:36.120 --> 04:38.560 will be an interesting thing to dig into. 04:38.560 --> 04:42.520 There's smaller differences as well, so Swift has errors with your values versus exceptions 04:42.520 --> 04:48.640 with stack traces and the threading model, versus thread versus a single weight in actors, 04:48.640 --> 04:52.760 a bit different, but again, something we can work with. 04:52.760 --> 04:59.160 So a typical application, you will have some Swift sources, but either are from a library, 04:59.160 --> 05:03.280 or it's your Swift sources, and you will have some Java sources, but we'll want to use 05:03.280 --> 05:04.760 this native code. 05:04.760 --> 05:10.520 So we will build a dynamic library, depending on the platform you want to run it on, and 05:10.520 --> 05:12.200 here's the new things. 05:12.200 --> 05:16.760 We will have a tool that will generate Java sources that will make calling this native 05:16.760 --> 05:18.160 library easy. 05:18.160 --> 05:25.960 This is where we will be using the FFMAPIs for function interfaces to call down to this dynamic 05:25.960 --> 05:26.960 library. 05:26.960 --> 05:31.440 We will also have to generate a bit of Swift code, which is a bit unfortunate because 05:31.440 --> 05:36.600 with a plain C-style language, you wouldn't need to do that, and I would explain in depth 05:36.600 --> 05:40.680 why we have to do this bridging layer. 05:40.680 --> 05:45.120 At the end of the day, you put it in a jar, or in your ship for dynamic library separately, 05:45.120 --> 05:47.800 and you can just call these functions. 05:47.800 --> 05:51.720 So we do have a tool that is called JXTrack Swift. 05:51.720 --> 05:57.120 The name is very much inspired by the JXTrackStool, which is something from the JDK that 05:57.120 --> 06:02.360 takes C header files and turns it into these Java wrappers that you can use to call 06:02.360 --> 06:03.800 these C functions. 06:03.800 --> 06:09.280 So our tool is very much inspired on that, looks more or less like this, where instead 06:09.280 --> 06:14.280 of accepting C header files, we take Swift sources, and again, generate the Java code 06:14.280 --> 06:18.560 that it makes it possible and easy to call into these native functions. 06:18.560 --> 06:23.440 The tool is split up in a few phases, or some analysis phase, so Swift is a very explicit 06:23.440 --> 06:24.440 language. 06:24.440 --> 06:29.960 For example, you can have extensions on types located in other modules or sources, so we 06:29.960 --> 06:35.600 have to do a little bit of analysis to figure out what's type has, what's which method. 06:35.600 --> 06:39.840 And now later on, of course, this is the source generation step. 06:39.840 --> 06:43.840 Today we use the foreign function in memory APIs. 06:43.840 --> 06:49.120 We could have a source generation step that would use the legacy, you know, JNI APIs for 06:49.120 --> 06:52.840 platforms that just don't have the FAM yet. 06:52.840 --> 06:56.360 And we do generate these Swift function as well. 06:56.360 --> 07:00.160 And so how does it look like when we extract some source? 07:00.160 --> 07:02.960 Let's say we want to extract a Swift class. 07:02.960 --> 07:07.960 Swift class is imported as this, we're about and we implement this with KeepObject. 07:07.960 --> 07:12.160 We use this primarily to know that Aha, this object has to be referenced counted because 07:12.160 --> 07:17.280 we will try to do the right thing on the Java side as well as we import these types. 07:17.280 --> 07:22.440 When we extract a struct, we implement this with value, which again is a signal for us 07:22.440 --> 07:28.440 but okay, we will be copying this Swift value around rather than reference counting. 07:28.440 --> 07:33.920 Next we will be generating all of this for in foreign function descriptors. 07:33.920 --> 07:39.120 The previous talk very much explained, so we generate those, so we don't have to write, 07:39.120 --> 07:42.160 you know, the function signatures by your hand, by hand. 07:42.160 --> 07:47.360 And we finally generate the actual methods that Java developers will call, which kind 07:47.360 --> 07:51.640 of mirror the native shapes of the methods will be calling. 07:51.640 --> 07:57.680 An interesting thing here is, at the bottom one, you can see that these types can have 07:57.680 --> 08:03.400 other imported types, so I'm passing a my Swift struct in the Java side of things. 08:03.400 --> 08:11.080 And yes, this will be wrapping a Swift struct and we can just call a collection of Swift libraries 08:11.080 --> 08:17.000 without doing weird dances, we can just use them more and it all fits together. 08:17.000 --> 08:21.600 So I did say that we are using Swift sources, I feel that I have to explain the 08:21.600 --> 08:28.200 fact that for Swift, it is typical to use Swift sources as packet distribution mechanism. 08:28.200 --> 08:32.200 So when you publish a package, it's a get repository, you get for sources, so we always 08:32.200 --> 08:34.360 have resources available. 08:34.360 --> 08:38.040 But if you don't have the sources available, for example, you're using an operating system 08:38.040 --> 08:43.280 provided library or just close source code, the same tool will actually work the same way 08:43.280 --> 08:49.120 because Swift does have something alike header files, which is the Swift interface files, 08:49.120 --> 08:55.440 which are basically Swift source files, but except having extra bodies and implementations, 08:55.440 --> 08:57.560 it just could out without the bodies. 08:57.560 --> 09:03.560 So the same tool works the same way with those source or operating system provided library 09:03.560 --> 09:04.560 libraries. 09:04.560 --> 09:10.720 Okay, let's dive in and we will start from an interesting point which is initializers 09:10.720 --> 09:16.320 because they will lead us to some interesting discoveries I want to talk about today. 09:16.320 --> 09:21.880 So let's say I want to extract from this Swift source file, so it's an initializer, it takes 09:21.880 --> 09:27.080 a length and it takes a capacity, the capacity is another value type and I want to import 09:27.080 --> 09:30.000 that into Java. 09:30.000 --> 09:35.240 So of course we generate the function descriptor as you can see here, it will return a Swift 09:35.240 --> 09:41.760 pointer which is the initialized object and we accept the length and we accept the capacity 09:41.760 --> 09:46.720 as a pointer to that struct and oh wait what's that? 09:46.720 --> 09:53.080 We didn't see that in the Swift signature, it's another parameter here that is the Swift type. 09:53.080 --> 10:00.480 So somehow we will have to find out at runtime the Swift type metadata that we have to pass 10:00.480 --> 10:05.880 to this native function initializer to be able to call it. 10:05.880 --> 10:09.080 So how can we find that? 10:09.080 --> 10:13.560 Luckily we can just ask Swift to give us the type. 10:13.560 --> 10:18.760 So on the Java side we generate a little call that will basically down call into Swift using 10:18.760 --> 10:24.760 a well known function name and on the Swift side it's very simple because we just write 10:24.760 --> 10:27.640 the type and we just return it. 10:27.640 --> 10:32.320 I'll talk about the details of these functions a bit later, but basically I'm just returning 10:32.320 --> 10:35.760 the value out of Swift back into Java. 10:36.000 --> 10:40.920 This should feel familiar because on the JVM we have a class object and the type metadata 10:40.920 --> 10:41.920 is exactly what it's. 10:41.920 --> 10:46.880 It's very equivalent of a class object, it describes, hey this type is this and that. 10:46.880 --> 10:50.760 The type is immortal so I don't have to worry about retaining it or anything like that, 10:50.760 --> 10:53.440 I can just return it like that, let's find it. 10:53.440 --> 10:58.240 We've installed that on the Java side and we're ready to call initialize it directly, 10:58.240 --> 10:59.240 very cool. 10:59.280 --> 11:05.720 This way I can literally do a down call and I get back a Swift instance but I now have 11:05.720 --> 11:10.000 a reference to in the Java side. 11:10.000 --> 11:14.760 What about value types which is I think we've spent most of the talk because they're 11:14.760 --> 11:20.040 more interesting and value types are interesting because of course on the Swift side 11:20.040 --> 11:23.680 they will be stack allocated, that's the reason you want to have value types, they can be 11:23.680 --> 11:27.400 stack allocated and they're nice and efficient to pass around. 11:27.400 --> 11:32.080 So if we were to just return the same way as we did with the class, point to that would 11:32.080 --> 11:38.960 be pointing to a stack which could very easily be not valid anymore as I use it in Java. 11:38.960 --> 11:45.160 So instead what we do is we create a small allocation of your exact right size that the 11:45.160 --> 11:49.160 Swift initializer will fill in with the data of the struct. 11:49.160 --> 11:54.440 Now the question becomes, well I don't know the size of the struct in Java, how do I find 11:54.440 --> 11:55.440 out? 11:55.440 --> 12:01.120 And we have an analysis phase so maybe I can do that, maybe I can use the analysis to 12:01.120 --> 12:04.600 just do the math and figure out the size of the struct. 12:04.600 --> 12:11.000 We can do that, if that's an integer that's two eight bytes then okay I know that my Swift 12:11.000 --> 12:16.840 class is a class, it's a pointer again eight bytes and then it's a struct I have to look 12:16.840 --> 12:22.440 at that struct and recursively keep descending to figure out the size of that and eventually 12:22.440 --> 12:25.760 I can find that out. 12:25.760 --> 12:31.520 I could also ask the Swift content to just tell me, so the Swift runtime, the Swift API called 12:31.520 --> 12:35.320 memory layout, you can give it a type and ask these kinds of questions so you get the 12:35.320 --> 12:42.240 size, the stride, the stride is just the size plus any necessary padding to align it properly. 12:42.240 --> 12:44.760 And so we could ask Swift as well. 12:44.760 --> 12:49.480 But before we do that I want to explain why we have to do that. 12:49.480 --> 12:52.800 So what is the size of this struct? 12:52.800 --> 12:59.200 It's the same struct but now we're value and object types are generic, I know nothing 12:59.200 --> 13:04.040 about them and more interestingly when they could be reference types they could be value 13:04.040 --> 13:05.040 types. 13:05.040 --> 13:12.080 So the size of this struct at runtime really depends on how exactly it was used and I don't 13:12.080 --> 13:15.080 know by looking at this type declaration at all. 13:15.080 --> 13:18.080 So I don't know how to generate this initializer. 13:18.080 --> 13:24.280 So another cool thing about that is you may know if you've looked at a Valhalla which 13:24.280 --> 13:32.200 is we can produce tightly packed arrays and other structures using these kinds of mechanisms. 13:32.200 --> 13:37.080 But again we have to know the exact type at runtime at moments we're trying to initialize 13:37.080 --> 13:38.080 the thing. 13:38.080 --> 13:40.440 So how could we do that? 13:40.440 --> 13:44.360 We already have the type metadata and okay if the type metadata doesn't actually have 13:44.360 --> 13:48.760 this information but we can calculate a simple offset and jump to something called 13:48.760 --> 13:51.040 the value witness table. 13:51.040 --> 13:57.160 So the value witness table is something that contains a lot of interesting both functions 13:57.160 --> 14:00.520 and values that we'll be using to work with value types. 14:00.520 --> 14:06.480 Specifically how to initialize how to copy how to destroy these values and great we 14:06.480 --> 14:12.920 have the size and all the data we need to do our initial allocation for. 14:12.920 --> 14:14.600 How can I use that? 14:14.600 --> 14:20.480 So that is actually a C struct so I can just describe it using the memory layout, struct layout. 14:20.480 --> 14:24.880 I literally just layout okay this is this field, this is that field I know this is an integer 14:24.880 --> 14:30.480 this user addresses and as I'm done with that I can get a Valhalla at the appropriate 14:30.480 --> 14:39.280 offset for a given value witness table because I have that I can get the size of any swift 14:39.280 --> 14:43.360 metadata that I press. 14:43.360 --> 14:49.080 So now we're able to not only just get oh I got the size we can go a bit nicer and get 14:49.080 --> 14:52.880 the entire memory layout description based on these information. 14:52.880 --> 14:58.240 So I get the size, write or calculate the padding and I can return a struct layout that 14:58.240 --> 15:04.440 it has the proper name that describes the swift type name and today at least it's going 15:04.440 --> 15:10.560 to look a little bit like this from the previous perspective it's you know native memory 15:10.560 --> 15:12.160 layout and it's a blob. 15:12.160 --> 15:16.360 At least it's the right size of blob so we're happy because we can initialize and copy 15:16.360 --> 15:21.640 it using the value witness functions but maybe we could do that a little bit better in 15:21.640 --> 15:26.360 the future today we don't have that metadata we could do that and then we could describe 15:26.360 --> 15:31.400 exactly oh I know this is an int and this is an int and we could do the absolute correct 15:31.400 --> 15:37.080 metadata and then even do direct access to the offsets rather than going to rather than 15:37.080 --> 15:39.320 doing down course. 15:39.320 --> 15:43.720 Okay so we can check that if I got that right I can implement for initializer for 15:43.720 --> 15:50.000 a value type at all before because I just passed the value layout as we do for arena allocation 15:50.000 --> 15:52.800 and then we initialize that using the initializer. 15:52.800 --> 15:57.760 As you can see we can just print that on the JavaScript and it always has the right amount 15:57.760 --> 16:00.520 of bytes we need to be passing around. 16:00.920 --> 16:06.080 It's really cool we just taught Java to understand the layouts of native Swift objects. 16:07.080 --> 16:11.720 Now let's actually call some methods on things and this will be also interesting. 16:11.720 --> 16:17.720 Let's have a again my struct and I want to call a method called capacity on it. 16:17.720 --> 16:24.920 Capacity is another value type so first thing first I describe the function the function 16:24.920 --> 16:30.040 is a member function so we need to pass this the self as we call it in Swift. 16:30.040 --> 16:34.440 Let's say I pass it as the first parameter here and when we describe the rest of the function 16:34.440 --> 16:39.040 it's going to return again indirectly because it's a value type as we talked before 16:39.040 --> 16:44.200 in initializers I do the dance with getting the value layout, allocate that do the 16:44.200 --> 16:48.880 down core and they return I wrap it again with the appropriate wrapper type. 16:48.880 --> 16:52.280 Now how do I make this call? 16:52.280 --> 16:57.840 As as any of our non-seal language would today which is I have to generate a small 16:57.840 --> 17:02.480 function that we'll be calling using the C calling convention and we make sure using 17:02.480 --> 17:07.760 the C declarative use on the Swift side that okay this has to use the C calling convention 17:07.760 --> 17:12.320 and you know don't use features that C wouldn't understand like generic and you know other 17:12.320 --> 17:14.760 things that Swift has. 17:14.760 --> 17:19.840 This function doesn't really do much except cast the things to appropriate types and 17:19.840 --> 17:24.720 down core into the actual Swift function using the Swift convention because it Swift 17:24.720 --> 17:26.400 is calling Swift. 17:26.400 --> 17:32.160 Now in an ideal word we wouldn't do any of that and just call directly right with interaction 17:32.160 --> 17:37.680 costs as both build complexity I have to generate these things build times I have to compile 17:37.680 --> 17:42.800 them and of course performance because the yet another interaction in the way that would 17:42.800 --> 17:49.160 be cool if we could call directly and you know maybe to explain even more so why do we 17:49.160 --> 17:54.320 even need this interaction well Swift actually has its own calling convention and 17:54.320 --> 18:00.200 that's because it's you know optimized to patterns and invocation invocations that 18:00.200 --> 18:05.840 it often does and one of those optimizations in this API is that self must be passed in 18:05.840 --> 18:11.920 register so it's not like passed in a parameter it must be passed in a register but Swift 18:11.920 --> 18:17.360 has a stable API so we can easily find out where we should be passing it so the 18:17.360 --> 18:22.000 API is stable on some platforms it's well described you can check it out here so specifically 18:22.000 --> 18:31.440 on this register on x86 in this one cool so can we fix the JDK to use the Swift calling 18:31.440 --> 18:37.440 convention so I can get my magical dreamland version of directly calling yes and no I believe 18:37.440 --> 18:41.920 the code is very well structured and we have an opportunity to do that it would be here in 18:41.920 --> 18:47.200 the color range of a specific platform or maybe the calling sequence builder which would you 18:47.200 --> 18:52.720 know we would maybe tell it hey this parameter is special so that's a good news the bad news 18:52.720 --> 18:57.920 is these types are JDK internal so that's not something we did today but it's certainly 18:57.920 --> 19:03.600 possibility and other one times like dot net runtime inversion 9 have actually explored that 19:03.600 --> 19:09.840 a bit and that's a PR that implements parts of Swift's calling convention again to be able 19:09.920 --> 19:16.880 to call directly rather than from some sea shims and finally a little bit of object lifetime 19:16.880 --> 19:24.480 discussion because object lifetimes and memory safety is kind of the core of our goal here right 19:24.480 --> 19:31.920 we want to have this integration have a nice and safe so how do we do that but before I say how 19:31.920 --> 19:37.120 I need to explain what's really destroying a value means in Swiftland because it's actually a 19:37.280 --> 19:43.040 little bit different than on the JVM so again value types may have a value type code container 19:43.040 --> 19:49.680 it contains a number core primitive a person and the person is a reference type so if I create 19:49.680 --> 19:55.920 this container and then assign it to it because we're a reference content you know the ways with works 19:55.920 --> 20:02.240 this will be then this will call destroy on this value type from our good friend the value 20:02.240 --> 20:07.600 within stable this will then go through all the fields and call destroy on them or if it's a 20:07.600 --> 20:16.800 reference type eventually just release a retain come release on it if that gets zero we have to run 20:16.800 --> 20:22.080 we didn't the initializer and we're gonna run we didn't the initializer right now and noted 20:22.080 --> 20:27.840 some later point like it would be we finalize some of the JVM so developers expect this to work 20:27.920 --> 20:37.040 like this so what do we do to make it work with this we actually got inspired from the arena's API 20:37.040 --> 20:42.800 and we offer something called a Swift Arena in the you know support library that comes with all of 20:42.800 --> 20:49.680 us and yes it's a segment allocator same as arena's in the JDK but we also when we do initializers 20:49.680 --> 20:57.680 of return types we register them with the Swift Arena now we register them of course to manage 20:57.680 --> 21:04.080 for lifetimes so as I have registered for example in a Swift Arena of confined style which is 21:04.080 --> 21:10.320 again inspired by open JDK arena at the end of this scope we will call destroy on all the types 21:10.320 --> 21:16.480 that were registered with it again that is why we'll do the right thing here the same pattern 21:16.640 --> 21:20.800 applies for reference types you can just register them create them in this scope and we will just 21:20.800 --> 21:27.440 reference comes down on them today if we read if we don't read reference comes zero here we assert 21:28.080 --> 21:34.240 but I think you could totally see valid use cases for maybe you want to assert if it didn't get 21:34.240 --> 21:38.880 released and destroyed at the end of the scope or maybe you do actually want to you know just keep 21:38.880 --> 21:45.600 this style for maintaining reference counting so this is something we can do and we also try to 21:45.600 --> 21:52.880 guard against programmer errors so on the Java side you could make a mistake and unsafe he escaped 21:52.880 --> 21:58.320 a value created during this scope and you try to escape it outside of it so of course after 21:58.320 --> 22:02.480 this scope this value would have been destroyed it would be pointing its tail of the marine so on 22:02.480 --> 22:08.960 the Java side as we do with the choice we mark them so we don't try to down core into memory 22:08.960 --> 22:16.240 that was already the allocated again or then the name of safety so we don't the bad things here 22:16.880 --> 22:23.040 now we do have an auto arena as well again inspired by open gdk where we use phantom references 22:23.040 --> 22:28.800 and a cleaner thread to clean up these objects eventually I think it's great for prototyping if you 22:28.800 --> 22:34.800 want to show you know evry Java or swive developer hey please give us a go think that's a good one to 22:34.880 --> 22:40.800 start and there may be other situations where you want to rely just on the gc to these things as well of 22:40.800 --> 22:46.800 course it's less predictable than so for swive developers this would be a bit can be a bit surprising 22:48.720 --> 22:54.160 as you can see this is a very deep integration we're not just saying hey you can call 22:54.160 --> 22:59.600 simple functions now we're shooting for integration of both a programming model and 2020 you 22:59.600 --> 23:07.200 would safety as well as you know making it a pleasant thing to use and with the end goal of being 23:07.200 --> 23:13.680 able to import really most if not all swift code we have laying around so if you walk away from 23:13.680 --> 23:19.920 this talk I'd like to remember I'd like you to remember one thing but on goal is here to have memory 23:19.920 --> 23:25.360 safety all the way we don't have to lose memory safety as we cross into native land and if we 23:25.360 --> 23:31.760 collaborate from both sides with the AVM and the native language you know enforcing each 23:31.760 --> 23:38.560 other's patterns then we can pull that off swift and if a family PI's really worked well together 23:38.560 --> 23:45.440 I didn't show super crazy advanced cases but we can integrate them very deeply even with you know 23:45.440 --> 23:51.040 more in generics and use cases I didn't show today and you know value types are the core of swift 23:51.120 --> 23:56.400 and we can actually deal with them pretty well in Java which has been great so there's ongoing 23:56.400 --> 24:01.840 work on direct-track swift if you're interested in you know integration between languages like that 24:01.840 --> 24:08.960 please let us know and whatever like upcoming next steps we can look into of course performance 24:08.960 --> 24:15.200 if you're interested in performance let's say never ending story here of course we'd like to 24:15.200 --> 24:20.240 challenge a little bit of the generics because we want to support optionals and connections 24:20.320 --> 24:25.520 and then we will have to handle generics as well as swift closures and you know passing a 24:25.520 --> 24:30.800 closure to a swift function and then calling that on the swift side we can implement using up 24:30.800 --> 24:37.840 course into the AVM as well and you know express swift closures as function interfaces and you know 24:37.840 --> 24:44.880 those other calling convention differences for example for errors or async code and last but not least 24:44.880 --> 24:53.760 integration so that's all I had if you have questions please check me outside later on and thank you very much 25:14.880 --> 25:16.880 you