1 The `__get__` metamethod is consulted when a property lookup yields nothing 2 in the instance itself nor in its prototype chain. It is invoked as a method 3 on the instance, with the key as single argument. 4 5 -- Testcase -- 6 {% 7 let o = proto({}, { 8 __get__(key) { 9 return key == "bar" ? "virtual:bar" : null; 10 } 11 }); 12 13 print(o.bar, "\n"); 14 print(o.foo === null, "\n"); 15 %} 16 -- End -- 17 18 -- Expect stdout -- 19 virtual:bar 20 true 21 -- End -- 22 23 Properties found by the normal lookup shadow the metamethod, both own ones 24 and ones inherited from the prototype chain. 25 26 -- Testcase -- 27 {% 28 let hits = []; 29 30 let o = proto({ own: 1 }, { 31 inherited: 2, 32 __get__(key) { 33 push(hits, key); 34 return "virtual"; 35 } 36 }); 37 38 print(o.own, " ", o.inherited, " ", o.missing, "\n"); 39 printf("%.J\n", hits); 40 %} 41 -- End -- 42 43 -- Expect stdout -- 44 1 2 virtual 45 [ 46 "missing" 47 ] 48 -- End -- 49 50 Metamethods are resolved by walking the whole prototype chain, so a 51 grandparent prototype provides them as well. An own property with a dunder 52 name is plain data, not a metamethod: it does not shadow the prototype's 53 metamethod and is readable like any other property. 54 55 -- Testcase -- 56 {% 57 let grand = { __get__(key) { return "grand:" + key; } }; 58 let parent = proto({}, grand); 59 let child = proto({}, parent); 60 61 print(child.x, "\n"); 62 63 let o = proto({}, { __get__(key) { return "parent"; } }); 64 o.__get__ = function(key) { return "own"; }; 65 66 print(o.x, "\n"); 67 print(type(o.__get__), "\n"); 68 %} 69 -- End -- 70 71 -- Expect stdout -- 72 grand:x 73 parent 74 function 75 -- End -- 76 77 A `__get__` which is itself an object (rather than a function) delegates the 78 lookup to that object. This is how a common set of virtual properties can be 79 shared without copying. 80 81 -- Testcase -- 82 {% 83 let base = { greeting: "hi", shared: "base", n: 1 }; 84 let o = proto({ shared: "own" }, { __get__: base }); 85 86 print(o.greeting, " ", o.shared, " ", o.n + 1, " ", o.nope === null, "\n"); 87 %} 88 -- End -- 89 90 -- Expect stdout -- 91 hi own 2 true 92 -- End -- 93 94 A `__get__` function may return any value; that value becomes the result of 95 the property read, including objects and arrays. 96 97 -- Testcase -- 98 {% 99 let base = { greeting: "hi", shared: "base", n: 1 }; 100 let o = proto({}, { __get__(key) { return base; } }); 101 102 print(o.anything.greeting, " ", o.anything.shared, "\n"); 103 %} 104 -- End -- 105 106 -- Expect stdout -- 107 hi base 108 -- End -- 109 110 A metamethod is only honored when it is an actual function. Optional 111 chaining goes through the same lookup, so `?.` yields virtual properties 112 too. 113 114 -- Testcase -- 115 {% 116 let o = proto({}, { __get__: "not callable" }); 117 let p = proto({}, { __get__(key) { return "virtual:" + key; } }); 118 119 print(o.x === null, "\n"); 120 print(p?.y, "\n"); 121 %} 122 -- End -- 123 124 -- Expect stdout -- 125 true 126 virtual:y 127 -- End -- 128 129 Arrays with their own prototype participate in `__get__` delegation for 130 non-index keys. 131 132 -- Testcase -- 133 {% 134 let base = { label: "lan", mode: "up" }; 135 let a = proto([1, 2, 3], { __get__: base }); 136 137 print(a[0], " ", a.label, " ", a.mode, " ", a.nope === null, "\n"); 138 %} 139 -- End -- 140 141 -- Expect stdout -- 142 1 lan up true 143 -- End --
This page was automatically generated by LXR 0.3.1. • OpenWrt