[swift-evolution] Proposal: Introduce User-defined "Dynamic Member Lookup" Types
Ben Rimmington
me at benrimmington.com
Tue Nov 28 15:55:50 CST 2017
I suggest using different subscripts for function/method calls and properties:
* `value(...)` ==> `value[dynamicFunction: ""](...)`
* `value.name(...)` ==> `value[dynamicFunction: "name"](...)`
* `value.name` ==> `value[dynamicProperty: "name"]`
Dynamic callable types have an unnamed method.
Dynamic argument labels are always allowed (but can be ignored).
For example, the labels of `Date.UTC` below are not passed to JavaScript.
//===----------------------------------------------------------------------===//
// JavaScriptCore.playground
//===----------------------------------------------------------------------===//
import Foundation
import JavaScriptCore
typealias Arguments = DictionaryLiteral<String, Any>
extension JSContext {
subscript(dynamicFunction name: String) -> (_ arguments: Arguments) -> JSValue {
return globalObject[dynamicFunction: name]
}
subscript(dynamicProperty name: String) -> JSValue {
get {
return globalObject[dynamicProperty: name]
}
set {
globalObject[dynamicProperty: name] = newValue
}
}
}
extension JSValue {
subscript(dynamicFunction name: String) -> (_ arguments: Arguments) -> JSValue {
return { arguments in
let argumentValues = arguments.map({ $0.value })
if name.isEmpty {
return self.call(withArguments: argumentValues)
} else if name == "new" {
return self.construct(withArguments: argumentValues)
} else {
return self.invokeMethod(name, withArguments: argumentValues)
}
}
}
subscript(dynamicProperty name: String) -> JSValue {
get {
return forProperty(name)
}
set {
setValue(newValue, forProperty: name)
}
}
}
//===----------------------------------------------------------------------===//
// Examples
//===----------------------------------------------------------------------===//
let context = JSContext()!
//: ```
//: context.isNaN(Double.nan)
//: ```
context[dynamicFunction: "isNaN"](["": Double.nan])
//: ```
//: context.Math.PI
//: ```
context[dynamicProperty: "Math"][dynamicProperty: "PI"]
//: ```
//: context.Math.PI.toFixed(5)
//: ```
context[dynamicProperty: "Math"][dynamicProperty: "PI"][dynamicFunction: "toFixed"](["": 5])
//: ```
//: context.Math.pow(2, 53)
//: ```
context[dynamicProperty: "Math"][dynamicFunction: "pow"](["": 2, "": 53])
//: ```
//: let time = context.Date.UTC(
//: year: 9999, month: 11, day: 31,
//: hour: 23, minute: 59, second: 59, millisecond: 999)
//: ```
let time = context[dynamicProperty: "Date"][dynamicFunction: "UTC"]([
"year": 9999, "month": 11, "day": 31,
"hour": 23, "minute": 59, "second": 59, "millisecond": 999])
//: ```
//: let date = context.Date.new(time)
//: ```
let date = context[dynamicProperty: "Date"][dynamicFunction: "new"](["": time])
//: ```
//: date.toISOString()
//: ```
date[dynamicFunction: "toISOString"]([:])
> On 27 Nov 2017, at 06:04, Chris Lattner wrote:
>
> I’d like to formally propose the inclusion of user-defined dynamic member lookup types.
>
> Here is my latest draft of the proposal:
> https://gist.github.com/lattner/b016e1cf86c43732c8d82f90e5ae5438
> https://github.com/apple/swift-evolution/pull/768
>
> An implementation of this design is available here:
> https://github.com/apple/swift/pull/13076
>
> The implementation is straight-forward and (IMO) non-invasive in the compiler.
>
> -Chris
More information about the swift-evolution
mailing list