They're called Blocks.  Objective C has them.  They're objects.  They're 
actually Objective C objects.

> On Nov 10, 2017, at 10:26 AM, Florent Vilmart via swift-evolution 
> <[email protected]> wrote:
> 
> Object that are functions too, Amazing! I wanted that in Javascript for a 
> while!
> 
> On Nov 10, 2017, 1:04 PM -0500, Joe Groff via swift-evolution 
> <[email protected]>, wrote:
>> I don't like the idea of some calls having wildly different semantics from 
>> others; it's difficult enough to tell what exactly a call might be doing 
>> already. Since we also lack the more obvious static "Callable" protocol idea 
>> to give even well-typed call syntax to user-defined types, this also seems 
>> like it'd be easily abused for that purpose too.
>> 
>> I think a much better general solution to the problem of "make dynamic 
>> systems interact with type systems" is something like F#'s type providers 
>> which lets you write your own importers that look at dynamic information 
>> from a database, dynamic language VM, or some other system and generate type 
>> information usable by the compiler. Integration at the importer level could 
>> let you produce more well-typed Swift declarations by looking at the runtime 
>> information you get by importing a Python module.
>> 
>> -Joe
>> 
>>> On Nov 10, 2017, at 9:37 AM, Chris Lattner via swift-evolution 
>>> <[email protected]> wrote:
>>> 
>>> Hello all,
>>> 
>>> I have a couple of proposals cooking in a quest to make Swift interoperate 
>>> with dynamically typed languages like Python better. Instead of baking in 
>>> hard coded support for one language or the other, I’m preferring to add a 
>>> few small but general purpose capabilities to Swift. This is the first, 
>>> which allows a Swift type to become “callable”.
>>> 
>>> The proposal is here:
>>> https://gist.github.com/lattner/a6257f425f55fe39fd6ac7a2354d693d
>>> 
>>> I’ve also attached a snapshot below, but it will drift out of date as the 
>>> proposal is refined. Feedback and thoughts are appreciated, thanks!
>>> 
>>> -Chris
>>> 
>>> 
>>> 
>>> 
>>> 
>>> Introduce user-defined dynamically "callable" types
>>> 
>>> • Proposal: SE-NNNN
>>> • Author: Chris Lattner
>>> • Review Manager: TBD
>>> • Status: Awaiting implementation
>>> Introduction
>>> 
>>> This proposal introduces a new DynamicCallable protocol to the standard 
>>> library. Types that conform to it are "callable" with the function call 
>>> syntax. It is simple syntactic sugar which allows the user to write:
>>> 
>>> a = someValue(keyword1: 42, "foo", keyword2: 19)
>>> and have it be interpreted by the compiler as:
>>> 
>>> a = someValue.dynamicCall(arguments
>>> : [
>>> (
>>> "keyword1", 42), ("", "foo"), ("keyword2", 19
>>> )
>>> ])
>>> 
>>> Other languages have analogous features (e.g. Python "callables"), but the 
>>> primary motivation of this proposal is to allow elegant and natural 
>>> interoperation with dynamic languages in Swift.
>>> 
>>> Swift-evolution thread: Discussion thread topic for that proposal
>>> 
>>> Motivation
>>> 
>>> Swift is well known for being exceptional at interworking with existing C 
>>> and Objective-C APIs, but its support for calling APIs written in scripting 
>>> langauges like Python, Perl, and Ruby is quite lacking. These languages 
>>> provide an extremely dynamic programming model where almost everything is 
>>> discovered at runtime.
>>> 
>>> Through the introduction of this proposal, and the related 
>>> DynamicMemberLookupProtocol proposal, we seek to fix this problem. We 
>>> believe we can make many common APIs feel very natural to use directly from 
>>> Swift without all the complexity of implementing something like the Clang 
>>> importer. For example, consider this Python code:
>>> 
>>> class Dog
>>> :
>>> 
>>> def __init__(self, name
>>> ):
>>> 
>>> self.name =
>>> name
>>> 
>>> self.tricks = [] # creates a new empty list for each dog
>>> 
>>> 
>>> 
>>> def add_trick(self, trick
>>> ):
>>> 
>>> self.tricks.append(trick)
>>> we would like to be able to use this from Swift like this (the comments 
>>> show the corresponding syntax you would use in Python):
>>> 
>>> // import DogModule
>>> // import DogModule.Dog as Dog // an alternate
>>> let Dog = Python.import(“DogModule.Dog")
>>> 
>>> // dog = Dog("Brianna")
>>> let dog = Dog("Brianna")
>>> 
>>> // dog.add_trick("Roll over")
>>> dog.add_trick("Roll over")
>>> 
>>> // dog2 = Dog("Kaylee").add_trick("snore")
>>> let dog2 = Dog("Kaylee").add_trick("snore")
>>> Of course, this would also apply to standard Python APIs as well. Here is 
>>> an example working with the Python pickleAPI and the builtin Python 
>>> function open:
>>> 
>>> // import pickle
>>> let pickle = Python.import("pickle"
>>> )
>>> 
>>> 
>>> // file = open(filename)
>>> let file = Python.open
>>> (filename)
>>> 
>>> 
>>> // blob = file.read()
>>> let blob = file.read
>>> ()
>>> 
>>> 
>>> // result = pickle.loads(blob)
>>> let result = pickle.loads(blob)
>>> This can all be expressed today as library functionality written in Swift, 
>>> but without this proposal, the code required is unnecessarily verbose and 
>>> gross. Without it (but with the related dynamic member lookup proposal) the 
>>> code would have a method name (like call) all over the code:
>>> 
>>> // import pickle
>>> let pickle = Python.import("pickle") // normal method in Swift, no change.
>>> 
>>> 
>>> // file = open(filename)
>>> let file = Python.open.call
>>> (filename)
>>> 
>>> 
>>> // blob = file.read()
>>> let blob = file.read.call
>>> ()
>>> 
>>> 
>>> // result = pickle.loads(blob)
>>> let result = pickle.loads.call
>>> (blob)
>>> 
>>> 
>>> // dog2 = Dog("Kaylee").add_trick("snore")
>>> let dog2 = Dog.call("Kaylee").add_trick.call("snore")
>>> While this is a syntactic sugar proposal, we believe that this expands 
>>> Swift to be usable in important new domains. This sort of capability is 
>>> also highly precedented in other languages, and is a generally useful 
>>> language feature that could be used for other purposes as well.
>>> 
>>> Proposed solution
>>> 
>>> We propose introducing this protocol to the standard library:
>>> 
>>> protocol DynamicCallable
>>> {
>>> 
>>> associatedtype DynamicCallableArgument
>>> 
>>> 
>>> associatedtype DynamicCallableResult
>>> 
>>> 
>>> 
>>> func dynamicCall(arguments: [(String, DynamicCallableArgument)]) throws -
>>> DynamicCallableResult
>>> }
>>> 
>>> It also extends the language such that function call syntax - when applied 
>>> to a value of DynamicCallable type - is accepted and transformed into a 
>>> call to the dynamicCall member. The dynamicCall method takes a list of 
>>> tuples: the first element is the keyword label (or an empty string if 
>>> absent) and the second value is the formal parameter specified at the call 
>>> site.
>>> 
>>> Before this proposal, the Swift language has two types that participate in 
>>> call syntax: functions and metatypes (for initialization). Neither of those 
>>> may conform to protocols at the moment, so this introduces no possible 
>>> ambiguity into the language.
>>> 
>>> It is worth noting that this does not introduce the ability to provide 
>>> dynamicly callable static/class members. We don't believe that this is 
>>> important given the goal of supporting dynamic languages like Python, but 
>>> if there is a usecase discovered in the future, it could be explored as 
>>> future work. Such future work should keep in mind that call syntax on 
>>> metatypes is already meaningful, and that ambiguity would have to be 
>>> resolved somehow.
>>> 
>>> Discussion
>>> 
>>> While the signature for dynamicCall is highly general we expect the most 
>>> common use will be clients who are programming against concrete types that 
>>> implement this proposal. One very nice aspect of this is that, as a result 
>>> of Swift's existing subtyping mechanics, implementations of this type can 
>>> choose whether they can actually throw an error or not. For example, 
>>> consider this silly implementation:
>>> 
>>> struct ParameterSummer : DynamicCallable
>>> {
>>> 
>>> func dynamicCall(arguments: [(String, Int)]) -> Int
>>> {
>>> 
>>> return arguments.reduce(0) { $0+$1
>>> .1 }
>>> }
>>> }
>>> 
>>> 
>>> let x = ParameterSummer
>>> ()
>>> 
>>> print(x(1, 7, 12)) // prints 20
>>> Because ParameterSummer's implementation of dynamicCall does not throw, the 
>>> call site is known not to throw either, so the print doesn't need to be 
>>> marked with try.
>>> 
>>> Example Usage
>>> 
>>> A more realistic (and motivating) example comes from a prototype Python 
>>> interop layer. While the concrete details of this use case are subject to 
>>> change and not important for this proposal, it is perhaps useful to have a 
>>> concrete example to see how this comes together.
>>> 
>>> That prototype currently has two types which model Python values, one of 
>>> which handles Python exceptions and one of which does not. Their 
>>> conformances would look like this, enabling the use cases described in the 
>>> Motivation section above:
>>> 
>>> extension ThrowingPyRef: DynamicCallable
>>> {
>>> 
>>> func dynamicCall(arguments: [(String, PythonConvertible)]) throws
>>> 
>>> 
>>> -
>>> PythonConvertible {
>>> 
>>> // Make sure state errors are not around.
>>> assert(PyErr_Occurred() == nil, "Python threw an error but wasn't handled"
>>> )
>>> 
>>> 
>>> // Count how many keyword arguments are in the list.
>>> let numKeywords = arguments.reduce(0
>>> ) {
>>> 
>>> $0 + ($1.0.isEmpty ? 0 : 1
>>> )
>>> }
>>> 
>>> 
>>> let kwdict = numKeywords != 0 ? PyDict_New() : nil
>>> 
>>> 
>>> 
>>> // Non-keyword arguments are passed as a tuple of values.
>>> let argTuple = PyTuple_New(arguments.count-numKeywords)!
>>> 
>>> 
>>> var nonKeywordIndex = 0
>>> 
>>> 
>>> for (keyword, argValue) in
>>> arguments {
>>> 
>>> if keyword.isEmpty
>>> {
>>> 
>>> PyTuple_SetItem(argTuple, nonKeywordIndex, argValue.toPython
>>> ())
>>> nonKeywordIndex
>>> += 1
>>> 
>>> }
>>> else
>>> {
>>> 
>>> PyDict_SetItem(kwdict!, keyword.toPython(), argValue.toPython
>>> ())
>>> }
>>> }
>>> 
>>> 
>>> // Python calls always return a non-null value when successful. If the
>>> // Python function produces the equivalent of C "void", it returns the None
>>> // value. A null result of PyObjectCall happens when there is an error,
>>> // like 'self' not being a Python callable.
>>> guard let resultPtr = PyObject_Call(state, argTuple, kwdict) else
>>> {
>>> 
>>> throw PythonError.invalidCall(self
>>> )
>>> }
>>> 
>>> 
>>> let result = PyRef(owned
>>> : resultPtr)
>>> 
>>> 
>>> // Translate a Python exception into a Swift error if one was thrown.
>>> if let exception = PyErr_Occurred
>>> () {
>>> 
>>> PyErr_Clear
>>> ()
>>> 
>>> throw PythonError.exception(PyRef(borrowed
>>> : exception))
>>> }
>>> 
>>> 
>>> return
>>> result
>>> }
>>> }
>>> 
>>> 
>>> extension PyRef: DynamicCallable
>>> {
>>> 
>>> func dynamicCall(arguments: [(String
>>> , PythonConvertible)])
>>> 
>>> -
>>> PythonConvertible {
>>> 
>>> // Same as above, but internally aborts instead of throwing Swift
>>> // errors.
>>> }
>>> }
>>> 
>>> Source compatibility
>>> 
>>> This is a strictly additive proposal with no source breaking changes.
>>> 
>>> Effect on ABI stability
>>> 
>>> This is a strictly additive proposal with no ABI breaking changes.
>>> 
>>> Effect on API resilience
>>> 
>>> This has no impact on API resilience which is not already captured by other 
>>> language features.
>>> 
>>> Alternatives considered
>>> 
>>> A few alternatives were considered:
>>> 
>>> Add ability to reject parameter labels
>>> 
>>> The implementation above does not allow an implementation to staticly 
>>> reject argument labels. If this was important to add, we could add another 
>>> protocol to model this, along the lines of:
>>> 
>>> /// A type conforming just to this protocol would not accept parameter
>>> /// labels in its calls.
>>> protocol DynamicCallable
>>> {
>>> 
>>> associatedtype DynamicCallableArgument
>>> 
>>> 
>>> associatedtype DynamicCallableResult
>>> 
>>> 
>>> 
>>> func dynamicCall(arguments: [DynamicCallableArgument]) throws -
>>> DynamicCallableResult
>>> }
>>> 
>>> 
>>> /// A type conforming to this protocol does allow optional parameter
>>> /// labels.
>>> protocol DynamicCallableWithKeywordsToo : DynamicCallable
>>> {
>>> 
>>> func dynamicCall(arguments: [(String, DynamicCallableArgument)]) throws -
>>> DynamicCallableResult
>>> }
>>> 
>>> This would allow a type to implement one or the other based on their 
>>> capabilities. This proposal is going with a very simple design, but if 
>>> there is demand for this, the author is happy to switch.
>>> 
>>> Staticly checking for exact signatures
>>> 
>>> This protocol does not allow a type to specify an exact signature for the 
>>> callable - a specific number of parameters with specific types. If we went 
>>> down that route, the best approach would be to introduce a new declaration 
>>> kind (which would end up being very similar to get-only subscripts) since, 
>>> in general, a type could want multiple concrete callable signatures, and 
>>> those signatures should participate in overload resolution.
>>> 
>>> While such a feature could be interesting for some use cases, it is almost 
>>> entirely orthogonal from this proposal: it addresses different use cases 
>>> and does not solve the needs of this proposal. It does not address our 
>>> needs because even a variadic callable declaration would not provide access 
>>> to the keyword argument labels we need.
>>> 
>>> Direct language support for Python
>>> 
>>> We considered implementing something analogous to the Clang importer for 
>>> Python, which would add a first class Python specific type(s) to Swift 
>>> language or standard library. We rejected this option because it would be 
>>> significantly more invasive in the compiler, would set the precedent for 
>>> all other dynamic languages to get first class language support, and 
>>> because that first class support doesn't substantially improve the 
>>> experience of working with Python over existing Swift with a couple small 
>>> "generally useful" extensions like this one.
>>> 
>>> Naming
>>> 
>>> The most fertile ground for bikeshedding is the naming of the protocol and 
>>> the members. We welcome other ideas and suggestions for naming, but here 
>>> are some thoughts on obvious options to consider:
>>> 
>>> We considered but rejected the name CustomCallable, because the existing 
>>> Custom* protocols in the standard library (CustomStringConvertible, 
>>> CustomReflectable, etc) provide a way to override and custom existing 
>>> builtin abilities of Swift. In contrast, this feature grants a new 
>>> capability to a type.
>>> 
>>> We considered but rejected a name like ExpressibleByCalling to fit with the 
>>> ExpressibleBy* family of protocols (like ExpressibleByFloatLiteral, 
>>> ExpressibleByStringLiteral, etc). This name family is specifically used by 
>>> literal syntax, and calls are not literals. Additionally the type itself is 
>>> not "expressible by calling" - instead, instances of the type may be called.
>>> 
>>> On member and associated type naming, we intentionally gave these long and 
>>> verbose names so they stay out of the way of user code completion. The 
>>> members of this protocol are really just compiler interoperability glue. If 
>>> there was a Swift attribute to disable the members from showing up in code 
>>> completion, we would use it (such an attribute would also be useful for the 
>>> LiteralConvertible and other compiler magic protocols).
>>> 
>>> 
>>> _______________________________________________
>>> swift-evolution mailing list
>>> [email protected]
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> [email protected]
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to