Maybe you could show me what difference you'd expect with classes by comparing to this code that uses functions? Sorry for being slow here.
The following code prints W-002 25 W-002 25 // https://swiftlang.ng.bluemix.net/#/repl // Swift Ver. 3.0.2 (Release) // Platform: Linux (x86_64) class WidgetStore { var widget: String = "W-001" var count: Int = 1; func getWidgetProvider() -> ()->String { func provideWidget() -> String { return widget } return provideWidget } func getCountProvider() -> ()->Int { func provideCount() -> Int { return count } return provideCount } } var store = WidgetStore() var getWidget = store.getWidgetProvider() var getCount = store.getCountProvider() store.widget = "W-002" store.count = 25; print(store.widget) print(store.count) print(getWidget()) print(getCount()) On Sat, Dec 24, 2016 at 12:39 PM, Robert Widmann <[email protected]> wrote: > The point here is that the escape of the inner value necessitates the > (implicit) escape of the outer captured value. That's something closures > don't have to deal with. > > ~Robert Widmann > > 2016/12/24 13:13、Callionica (Swift) <[email protected]> > のメッセージ: > > I may be missing your point about lifetime extension problems. How would > lifetime extension be different for captures by classes than for captures > by function closures? > > On Sat, Dec 24, 2016 at 12:00 PM Robert Widmann <[email protected]> > wrote: > >> That still doesn't answer the lifetime extension problems. What is being >> described here is a complex extension to the lifetime of memory that is >> only being kept alive because of these implicit captures. It sounds like >> what you want is a member, and I'm not sure it's worth saving 5 lines to >> avoid that fact. >> >> ~Robert Widmann >> >> 2016/12/24 11:45、Callionica (Swift) via swift-evolution < >> [email protected]> のメッセージ: >> >> Missed swift-evol in my reply >> >> ---------- Forwarded message --------- >> From: Callionica (Swift) <[email protected]> >> Date: Sat, Dec 24, 2016 at 9:44 AM >> Subject: Re: [swift-evolution] Should we relax restriction on closing >> over outer scope in class declarations? >> To: Robert Widmann <[email protected]> >> >> >> These are good questions. >> >> I believe Swift closures currently do implicit self-capture. I wouldn't >> expect that behavior to be different when capturing for classes. >> >> If a class needs to refer to an outer self, I would expect the user to >> have to give the outer self a new name by assigning to a local. Same deal >> for referring to members in an outer class where there are members of the >> same name in the inner class: assign outer self to a local and refer to >> members through that local. >> >> On Fri, Dec 23, 2016 at 10:16 AM, Robert Widmann < >> [email protected]> wrote: >> >> >> On Dec 23, 2016, at 1:10 AM, Callionica (Swift) via swift-evolution < >> [email protected]> wrote: >> >> I'm certainly assuming that users have a basic understanding of scope >> (without that, what would be the intention behind defining the class within >> the function?). >> >> >> Despite its simplicity to you (given the example you’ve cited) this >> feature is quite an advanced extension to the current scoping rules. >> >> I'm not clear on what you see as the downside of letting classes capture >> locals for users that are unaware of capturing. >> >> >> I’ll be blunt: This opens a gaping hole in the semantics of variable >> lifetimes and potentially introduces an ambiguity into resolution of the >> `self` keyword. For the former, consider a light extension to your >> original example that introduces a nested class: >> >> class Outer { >> let widgetString: String = createWidgetString() >> >> // Initializer suppressed >> func foo() -> WidgetStringProvider { >> class SimpleProvider: WidgetStringProvider { >> // Initializer suppressed >> func provideWidgetString() -> String { >> return widgetString >> } >> } >> return SimpleProvider() >> } >> } >> >> Now, from SIL’s point of view, widgetString must escape the scope it’s >> in and its lifetime should be extended beyond this block. Fine. But what >> about Outer? Because we’re returning a reference to SimpleProvider which >> escapes the scope of foo(), and instance members of a SimpleProvider >> capture outer context, this means we also have to keep Outer alive and >> around for destruction (perhaps at the point where SimpleProvider is >> destroyed?) >> >> For the latter consider trying to explicitly reference widgetString >> here. In provideWidgetString() we close over self in both foo() and >> provideWidgetString(). So, if I wish to make reference to Outer’s self >> explicitly, >> how would I go about doing it? Given that today a nested aggregate can >> have members with the same identifiers as their parent, how do we know if >> we’re capturing them or not when they’re referenced in the inner aggregate? >> >> ~Robert Widmann >> >> On Thu, Dec 22, 2016 at 11:26 PM Xiaodi Wu <[email protected]> wrote: >> >> Only if you're also assuming that people defining classes within >> functions would know about capturing. This violates the principle of >> progressive disclosure, since people naturally learn about functions and >> classes before they learn about closures and capturing. >> >> >> On Fri, Dec 23, 2016 at 01:51 Callionica (Swift) < >> [email protected]> wrote: >> >> Assuming capture were allowed, people defining classes within functions >> who didn't want them to capture could position the class definition prior >> to any other code in the function so that there would be nothing to >> capture. >> >> On Thu, Dec 22, 2016 at 4:13 PM Xiaodi Wu via swift-evolution < >> [email protected]> wrote: >> >> I have to agree with Michael; it seems dangerous to allow implicit >> capture by classes. A primary purpose (telos?) of closures is to provide >> this functionality, which is actually quite an advanced concept. One knows >> to think carefully about this when encountering a closure expression. A >> primary purpose of classes is to provide for encapsulation of code. >> Accidentally extending the lifetime of a local variable in a containing >> scope would be hard to notice and highly unexpected functionality. Better >> not to mix these things. >> >> On Thu, Dec 22, 2016 at 17:54 Micah Hainline via swift-evolution < >> [email protected]> wrote: >> >> That's exactly what I'm suggesting, the class declaration could work >> similarly to a closure. >> >> >> >> >> >> > On Dec 22, 2016, at 4:15 PM, Michael Ilseman <[email protected]> >> wrote: >> >> >> > >> >> >> > Are you asking for a class declaration to implicitly capture and extend >> the lifetime of local variables? That seems like something that’s better >> done explicitly. Perhaps it’s better to think about how to reduce the >> boiler plate code, e.g. better default initializers. >> >> >> > >> >> >> > (this is of course, additive and beyond the current scope of Swift 4 >> phase 1 planning) >> >> >> > >> >> >> >> On Dec 22, 2016, at 2:39 PM, Micah Hainline via swift-evolution < >> [email protected]> wrote: >> >> >> >> >> >> >> >> Currently we allow declarations of a new class in local scope, but >> >> >> >> nothing can be referenced from the outer scope. Thus this is illegal: >> >> >> >> >> >> >> >> ``` >> >> >> >> func foo() { >> >> >> >> let widgetString: String = createWidgetString() >> >> >> >> class SimpleProvider: WidgetStringProvider { >> >> >> >> func provideWidgetString() -> String { >> >> >> >> return widgetString // Illegal, defined in outer scope >> >> >> >> } >> >> >> >> } >> >> >> >> doThingsWithWidget(provider: WidgetStringProvider()) >> >> >> >> } >> >> >> >> ``` >> >> >> >> >> >> >> >> I'm trying to feel out the edges of this decision, and figure out why >> >> >> >> exactly this isn't allowed now, and how we might want to relax this in >> >> >> >> the future if possible. While not a common construct, it is a useful >> >> >> >> one. >> >> >> >> >> >> >> >> Obviously there are ways around it, very simple to create an init and >> >> >> >> a private let and do something like this: >> >> >> >> >> >> >> >> ``` >> >> >> >> func foo() { >> >> >> >> let widgetString: String = createWidgetString() >> >> >> >> class SimpleProvider: WidgetStringProvider { >> >> >> >> private let widgetString: String >> >> >> >> >> >> >> >> init(widgetString: String) { >> >> >> >> self.widgetString = widgetString >> >> >> >> } >> >> >> >> >> >> >> >> func provideWidgetString() -> String { >> >> >> >> return widgetString // now legal, references >> >> >> >> SimpleProvider.widgetString >> >> >> >> } >> >> >> >> } >> >> >> >> doThingsWithWidget(provider: WidgetStringProvider(widgetString: >> >> >> >> widgetString)) >> >> >> >> } >> >> >> >> ``` >> >> >> >> >> >> >> >> That's boilerplate I don't want to write though, as it somewhat >> >> >> >> detracts from the readability of the structure. I'm not super >> >> >> >> interested in defending the concept of local class definitions itself, >> >> >> >> it's already allowed in the language, I'm just interested in the >> >> >> >> syntax limitation and where that line might be able to be redrawn. >> >> >> >> _______________________________________________ >> >> >> >> 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 >> >> >> >> >> >> >> >> _______________________________________________ >> 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
