[swift-evolution] Idea for enabling DSLs: bind to self in closures

David Waite david at alkaline-solutions.com
Fri Dec 4 17:32:41 CST 2015


> On Dec 4, 2015, at 3:51 PM, Kevin Ballard <kevin at sb.org> wrote:
> 
> On Fri, Dec 4, 2015, at 09:36 AM, Joe Groff wrote:
>> Another way to do this would be to support scoped imports, to make a set of top-level functions locally available without polluting the global namespace:
>>  
>> {
>>   import func QuickSpecBuilder.expect
>>  
>>   expect(sections).to(....)
>> }
>>  
>> Being able to elide self is already somewhat controversial, and a number of people find it makes code harder to read. I worry that allowing closures to change 'self' has the potential to be even more confusing. In Javascript, it's my understanding the ability to arbitrarily rebind 'this' is seen as a design flaw rather than a feature people regularly take advantage of.
>  
> I like this idea. I'm very much against rebinding `self` because it seems like an excellent source for confusion. Not only that, but the actual underlying desire here isn't to remove `self` at all, but just to introduce new functions into function resolution within a scope. And this is precisely what adding imports in arbitrary scopes does (the only downside being you need a line of code to add them, but that's not a big deal). I know Rust allows this and it's pretty handy. I'd love to have this feature even when not using a DSL.
>  
> -Kevin Ballard

A few thoughts:

1. In a lot of situations they are not pure functions - they have state associated across them determined by the context in which your closure was called. So the import would not be of a static function, but of an input parameter, aka:
	it(“…”) {
		builder in
		import builder
		expect(sections).to{…}
         }

Assuming expect is the only function, this may very well be equivalent to

	it(“…”) {
		builder in
		let expect = builder.expect
		expect(sections).to{…}
         }

2. expect, in the case of Nimble, is an overloaded function. I assume import would bring in all overloads?
3. I like the idea of providing additional scope rather than overriding self, as you would likely need to bind self to a new name per my proposal (aka [my = self] self in…)
4. I like the idea of this having lexical scope, and import being usable outside of closures
5. Imports likely should generate conflicts at compile-time if they shadow defined functions if you can do wildcard imports. No need to have syntax to alias names - one should either change the code to not conflict or use the longer-form names
6. import could be an attribute:
	it(“…”) {
		@import builder in
		expect(sections).to{…}
         }


-DW


More information about the swift-evolution mailing list