> 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