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

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

Reply via email to