> On Nov 29, 2016, at 1:54 PM, John McCall <[email protected]> wrote:
> 
> 
>> On Nov 28, 2016, at 11:53 AM, 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.
> 
> I agree with you, but I'm not sure that global initializers fit this use-case 
> well either.

That wasn't what I was going for, sorry for not being clear. I more meant that 
having another mechanism for discovering a set of declarations with a common 
attribute across a program might be called for besides just types with protocol 
conformances. Someone earlier in the thread suggested a @tag attribute; 
something like that could be allowed to apply not only to types but to 
functions as well.

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

Reply via email to