> On Nov 19, 2016, at 8:57 PM, John McCall <[email protected]> wrote: > >> On Nov 19, 2016, at 6:03 PM, Alan Cabrera <[email protected] >> <mailto:[email protected]>> wrote: >>> On Nov 19, 2016, at 4:02 PM, John McCall <[email protected] >>> <mailto:[email protected]>> wrote: >>> >>>> On Nov 19, 2016, at 3:31 PM, Alan Cabrera <[email protected] >>>> <mailto:[email protected]>> wrote: >>>>> On Nov 19, 2016, at 1:21 PM, John McCall <[email protected] >>>>> <mailto:[email protected]>> wrote: >>>>> >>>>>> On Nov 19, 2016, at 10:07 AM, Alan Cabrera via swift-evolution >>>>>> <[email protected] <mailto:[email protected]>> wrote: >>>>>>> On Nov 19, 2016, at 9:27 AM, Jean-Daniel <[email protected] >>>>>>> <mailto:[email protected]>> wrote: >>>>>>> >>>>>>> >>>>>>>> Le 19 nov. 2016 à 15:58, Alan Cabrera via swift-evolution >>>>>>>> <[email protected] <mailto:[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.
Great, are there any keywords I can use to search for this thread? > 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. Does the other thread go into detail about this? I’m not sure that I follow why it should be opt-in as opposed to simply searching for all implementations of a specific protocol. Is it because the protocol information is erased after compilation? > In general, this kind of straightforward compilation task — "compilation" in > the general sense of gathering like information from different sources — is > pretty easy to support and much less problematic than features that rely on > arbitrary code execution. Agreed, it solves the bulk of the problems I would have solved with global init functions without the temptations to indulge in dangerous proclivities. Regards, Alan
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
