on Mon Nov 28 2016, Joe Groff <[email protected]> wrote: >> On Nov 19, 2016, at 8:57 PM, John McCall via swift-evolution >> <[email protected]> wrote: >> >>> On Nov 19, 2016, at 6:03 PM, Alan Cabrera <[email protected]> wrote: >>>> On Nov 19, 2016, at 4:02 PM, John McCall <[email protected]> wrote: >>>> > >>>>> On Nov 19, 2016, at 3:31 PM, Alan Cabrera <[email protected]> wrote: >>>>>> On Nov 19, 2016, at 1:21 PM, John McCall <[email protected]> wrote: >>>>>> >>>>>>> On Nov 19, 2016, at 10:07 AM, Alan Cabrera via swift-evolution >>>>>>> <[email protected]> wrote: >>>>>>>> On Nov 19, 2016, at 9:27 AM, Jean-Daniel <[email protected]> wrote: >>>>>>>> >>>>>>>> >>>>>>>>> Le 19 nov. 2016 à 15:58, Alan Cabrera via swift-evolution >>>>>>>>> <[email protected]> a écrit : >>>>>>>>> >>>>>>>>> I’m not sure if this was proposed or not; or even if this is >>>>>>>>> a Swift-ly way of doing things. It would be pretty handy to >>>>>>>>> be able to declare init() functions in my module to register >>>>>>>>> handlers. It’s a common pattern in enterprise software. >>>>>>>>> >>>>>>>>> Currently, I have to generate a lot of boilerplate code to emulate >>>>>>>>> the behavior. I think it would be cleaner to have these global >>>>>>>>> init() functions. >>>>>>>>> >>>>>>>> >>>>>>>> I’d rather like a swift attribute equivalent to : >>>>>>>> __attribute__((constructor)) >>>>>>>> >>>>>>>> It will not force me to call my initializer init, and moreover >>>>>>>> it will let me declare multiple functions so I would be able >>>>>>>> to register multiples handlers from a single module without >>>>>>>> having to group all the register call into a single init() >>>>>>>> function. >>>>>>>> >>>>>>> >>>>>>> I’m not quite following what “__attribute__((constructor))” >>>>>>> means; it looks like an LLVM implementation bit. Do you mean >>>>>>> defining a new Swift declaration attribute named “constructor”? >>>>>>> If so, I really like that idea. I think that the specific >>>>>>> attribute name “constructor” may be a bit confusing though, >>>>>>> since it’s not really constructing anything specific. Maybe >>>>>>> “startup” would be a more descriptive attribute name? >>>>>>> >>>>>>> @startup >>>>>>> func registerHandlers() { >>>>>>> } >>>>>>> >>>>>>> The attribute would also help the compiler and IDEs prevent >>>>>>> direct calling of the startup functions, thus >>>>>>> reinforcing/focusing the startup functions’ role as global >>>>>>> startup functions. Maybe global teardown functions would be >>>>>>> helpful as well. >>>>>>> >>>>>>> I’m going to try goofing around with the idea on my fork. >>>>>> >>>>>> Some sort of reflective discovery would be better, I think. >>>>>> Eager global initialization is superficially attractive — what >>>>>> could be simpler than just running some code at program launch? >>>>>> — but as a program scales up and gains library dependencies, it >>>>>> very quickly runs into problems. What if an initializer depends >>>>>> on another already having been run? What if an initializer >>>>>> needs to be sensitive to the arguments or environment? What if >>>>>> an initializer need to spawn a thread? What if an initializer >>>>>> needs to do I/O? What if an initializer fails? Global >>>>>> initialization also has a lot of the same engineering drawbacks >>>>>> as global state, in that once you've introduced a dependency on >>>>>> it, it's extremely hard to root that out because entire APIs get >>>>>> built around the assumption that there's no need for an explicit >>>>>> initialization/configuration/whatever step. And it's also quite >>>>>> bad for launch performance — perhaps not important for a server, >>>>>> but important for pretty much every other kind of program — >>>>>> since every subsystem eagerly initializes itself whether it's >>>>>> going to be used or not, and that initialization generally has >>>>>> terrible locality. >>>>> >>>>> Very good points. I recognize the dangers. However. >>>>> >>>>> Don’t these problems already exist given that user code can still >>>>> execute at program startup? It cannot be denied that the pattern >>>>> is used and is extremely useful though, as you point out above, >>>>> it should be used carefully. Thinking on it, there are always >>>>> pros and cons to most language features and one relies on best >>>>> practices to avoid shooting oneself in the foot. For each of the >>>>> specters listed above, there are simple accepted practices that >>>>> can be adopted to avoid them; most of those practices are already >>>>> being employed for other situations. >>>>> >>>>> And the pattern is not just useful in enterprise software. >>>>> Complex applications’ app-delegate did-finish-launching methods >>>>> are chucked full of hand stitched roll calls to framework >>>>> initialization code. This needlessly places a brittle >>>>> dependency/burden on the application developer in what should be >>>>> a simple behind the scenes collaboration. >>>>> >>>>> One could argue that such a thing was never needed before. I >>>>> would point to CocoaPods, Carthage, and the other influx of >>>>> enterprise influenced tooling and frameworks. Today’s mobile >>>>> applications are no longer simply todo apps. >>>>> >>>>> Global init() functions are a clean solution to what engineers are >>>>> already boiler plating with static singleton code. >>>> >>>> No, they aren't a clean solution for the reasons I listed. They >>>> may be a solution you're used to using, but they're not a *clean* >>>> solution, and Swift's line against providing them is for the best. >>>> >>>> I'm surprised that you keep talking about enterprise / complex >>>> applications as some sort of argument for them, because those are >>>> exactly the applications where, in my experience, global >>>> initializers completely break down as a reasonable approach. It's >>>> the small applications that can get away with poor software >>>> engineering practices, because the accumulated >>>> maintenance/complexity/performance costs are, well, small. >>> >>> It’s difficult to subscribe to the slippery slope arguments that >>> contain specters that can still afflict applications without global >>> init functions. Any feature can be abused and it seems hyperbolic >>> to provide arguments that seems to ascribe the above problems as an >>> inevitability solely afflicting global init functions. My and >>> others’ experience with them has been very different from yours. >>> >>> With that said, I took some time to re-read your reply, after my >>> afternoon nap. I really like the idea of some kind of reflective >>> discovery. How would that work? Maybe having a special @tag >>> attribute that can be searched at runtime? >> >> There was another thread that mentioned this idea recently, but it >> would be reasonable to provide some way to get a P.Type for every >> type in the program that conforms to a protocol P. This would be >> opt-in at the protocol level, because we wouldn't want to be >> prevented from e.g. stripping an unused type from the program just >> because it implemented Equatable. There are some other complexities >> here, but that's the basic idea, and it's totally reasonable to >> support. > > I worry that there are registration use cases for which "get all > protocol conformers" is a bit boilerplatey. For example, collecting > test case functions is a classic use case, and requiring a separate > type declaration for every case would be a bit heavyweight compared to > just having each test be a free function.
Yeah, well you could make them methods of a conforming type, but then you still want a general introspection method so you can crawl the type's declarations and find them. -- -Dave _______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
