1# `final` 2 3The `final` attribute is the converse of the [`structural` 4attribute](structural.html). It configures how `wasm-bindgen` will generate JS 5imports to call the imported function. Notably a function imported by `final` 6never changes after it was imported, whereas a function imported by default (or 7with `structural`) is subject to runtime lookup rules such as walking the 8prototype chain of an object. Note that `final` is not suitable for accessing 9data descriptor properties of JS objects; to accomplish this, use the `structural` 10attribute. 11 12[host-bindings]: https://github.com/WebAssembly/host-bindings 13[reference-types]: https://github.com/WebAssembly/reference-types 14 15The `final` attribute is intended to be purely related to performance. It 16ideally has no user-visible effect, and `structural` imports (the default) 17should be able to transparently switch to `final` eventually. 18 19The eventual performance aspect is that with the [host bindings 20proposal][host-bindings] then `wasm-bindgen` will need to generate far fewer JS 21function shims to import than it does today. For example, consider this import 22today: 23 24```rust 25#[wasm_bindgen] 26extern "C" { 27 type Foo; 28 #[wasm_bindgen(method)] 29 fn bar(this: &Foo, argument: &str) -> JsValue; 30} 31``` 32 33**Without the `final` attribute** the generated JS looks like this: 34 35```js 36// without `final` 37export function __wbg_bar_a81456386e6b526f(arg0, arg1, arg2) { 38 let varg1 = getStringFromWasm(arg1, arg2); 39 return addHeapObject(getObject(arg0).bar(varg1)); 40} 41``` 42 43We can see here that this JS function shim is required, but it's all relatively 44self-contained. It does, however, execute the `bar` method in a duck-type-y 45fashion in the sense that it never validates `getObject(arg0)` is of type `Foo` 46to actually call the `Foo.prototype.bar` method. 47 48If we instead, however, write this: 49 50```rust 51#[wasm_bindgen] 52extern "C" { 53 type Foo; 54 #[wasm_bindgen(method, final)] // note the change here 55 fn bar(this: &Foo, argument: &str) -> JsValue; 56} 57``` 58 59it generates this JS glue (roughly): 60 61```js 62const __wbg_bar_target = Foo.prototype.bar; 63 64export function __wbg_bar_a81456386e6b526f(arg0, arg1, arg2) { 65 let varg1 = getStringFromWasm(arg1, arg2); 66 return addHeapObject(__wbg_bar_target.call(getObject(arg0), varg1)); 67} 68``` 69 70The difference here is pretty subtle, but we can see how the function being 71called is hoisted out of the generated shim and is bound to always be 72`Foo.prototype.bar`. This then uses the `Function.call` method to invoke that 73function with `getObject(arg0)` as the receiver. 74 75But wait, there's still a JS function shim here even with `final`! That's true, 76and this is simply a fact of future WebAssembly proposals not being implemented 77yet. The semantics, though, match the future [host bindings 78proposal][host-bindings] because the method being called is determined exactly 79once, and it's located on the prototype chain rather than being resolved at 80runtime when the function is called. 81 82## Interaction with future proposals 83 84If you're curious to see how our JS function shim will be eliminated entirely, 85let's take a look at the generated bindings. We're starting off with this: 86 87```js 88const __wbg_bar_target = Foo.prototype.bar; 89 90export function __wbg_bar_a81456386e6b526f(arg0, arg1, arg2) { 91 let varg1 = getStringFromWasm(arg1, arg2); 92 return addHeapObject(__wbg_bar_target.call(getObject(arg0), varg1)); 93} 94``` 95 96... and once the [reference types proposal][reference-types] is implemented then 97we won't need some of these pesky functions. That'll transform our generated JS 98shim to look like: 99 100```js 101const __wbg_bar_target = Foo.prototype.bar; 102 103export function __wbg_bar_a81456386e6b526f(arg0, arg1, arg2) { 104 let varg1 = getStringFromWasm(arg1, arg2); 105 return __wbg_bar_target.call(arg0, varg1); 106} 107``` 108 109Getting better! Next up we need the host bindings proposal. Note that the 110proposal is undergoing some changes right now so it's tough to link to reference 111documentation, but it suffices to say that it'll empower us with at least two 112different features. 113 114First, host bindings promises to provide the concept of "argument conversions". 115The `arg1` and `arg2` values here are actually a pointer and a length to a utf-8 116encoded string, and with host bindings we'll be able to annotate that this 117import should take those two arguments and convert them to a JS string (that is, 118the *host* should do this, the WebAssembly engine). Using that feature we can 119futher trim this down to: 120 121```js 122const __wbg_bar_target = Foo.prototype.bar; 123 124export function __wbg_bar_a81456386e6b526f(arg0, varg1) { 125 return __wbg_bar_target.call(arg0, varg1); 126} 127``` 128 129And finally, the second promise of the host bindings proposal is that we can 130flag a function call to indicate the first argument is the `this` binding of the 131function call. Today the `this` value of all called imported functions is 132`undefined`, and this flag (configured with host bindings) will indicate the 133first argument here is actually the `this`. 134 135With that in mind we can further transform this to: 136 137```js 138export const __wbg_bar_a81456386e6b526f = Foo.prototype.bar; 139``` 140 141and voila! We, with [reference types][reference-types] and [host 142bindings][host-bindings], now have no JS function shim at all necessary to call 143the imported function. Additionally future wasm proposals to the ES module 144system may also mean that don't even need the `export const ...` here too. 145 146It's also worth pointing out that with all these wasm proposals implemented the 147default way to import the `bar` function (aka `structural`) would generate a JS 148function shim that looks like: 149 150```js 151export function __wbg_bar_a81456386e6b526f(varg1) { 152 return this.bar(varg1); 153} 154``` 155 156where this import is still subject to runtime prototype chain lookups and such. 157