> 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] 
>> <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.

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

Reply via email to