> 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]
>> <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. 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.
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.
John.
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution