[swift-evolution] Proposal: 'selfless' keyword for refactoring duplicate code from initialisers

Marc Knaup marc at knaup.koeln
Tue Dec 15 19:06:26 CST 2015


In its current state with the initial example -1 from me for the proposal.

The example could easily be written like this:

class FooView: UIView {

    var property = 4

    init() {
        super.init()
    }

    init(frame: CGRect) {
        super.init(frame)
    }
}


In cases where the initially value is computed in a complex way a closure
can be used:

class FooView: UIView {

    var property: Int = {
        // some complicated computation
        return value
    }()

    init() {
        super.init()
    }

    init(frame: CGRect) {
        super.init(frame)
    }
}

And that value could even delegate computation to static methods of the
class.

In cases where the computation is even more complex and refers to other
properties a lazy var can be used, which even allows the value to refer to
self:

class FooView: UIView {

    private(set) lazy var property: Int = {
        // some complicated computation which can use self
        return value
    }()

    init() {
        super.init()
    }

    init(frame: CGRect) {
        super.init(frame)
    }
}



On Wed, Dec 16, 2015 at 1:30 AM, Charles Srstka via swift-evolution <
swift-evolution at swift.org> wrote:

> On Dec 15, 2015, at 5:59 PM, Ross O'Brien via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>
> Hi all,
>
> I'm a new member of the list, so apologies if this is a duplicate of an
> existing idea or if there's already a way to do this in Swift 2.1 that I've
> missed.
>
> In Objective C, and C-like languages, an initialiser function represents a
> stage after allocation of memory where properties are given values. In
> Swift, init appears to precede (or overlap with) allocation. The benefit of
> this is that for type-safety reasons, all properties of a type (or new
> properties of a derived type) can be verified as having values. The
> disadvantage, and one of the stumbling blocks for those who learned
> Objective-C, is that until all the properties have values, the instance
> does not exist and instance functions cannot be called.
>
> There's an invisible threshold in Swift init() functions marking this
> transition. In derived classes it's the point where super.init() is called
> - after the derived type has provided initial values, but before any type
> functions can be called.
>
> Some types have multiple initialisers, and may be duplicating a lot of
> code in those distinct inits before they cross the threshold. This code
> can't be refactored into an instance function because the instance doesn't
> exist yet. The instance function may not even require the use of any
> properties of the type.
>
> If the compiler can read an init function and its varied control flow and
> determine a threshold where all properties have values, presumably it can
> read the code of any function called before that threshold, determine which
> properties they read and which they assign to, and provide a warning if a
> path assigns to a constant a second time, etc.. But this isn't currently
> happening.
>
> I'm guessing there are multiple contributing factors for this: the
> combinatorial explosion of possible control flow paths with functions
> (particularly if they're recursive); the possibility that the function
> calls are used by the compiler to mark the end of a control flow path, by
> which point it can determine whether everything has a value; the function
> genuinely can't exist without allocation. I don't know the reasons but I'd
> be interested to learn them.
>
> I'm proposing the keyword 'selfless' for a function which could be called
> before the threshold. It either only uses local properties or properties
> belonging to the type - never to the 'super' type (in the case of a derived
> class). It can't call any instance functions which aren't themselves
> selfless.
>
> Example of use:
> class FooView : UIView
> {
>     var property : Int
>
>     init()
>     {
>         initialiseProperty()
>         super.init()
>     }
>
>     init(frame:CGRect)
>     {
>         initialiseProperty()
>         super.init(frame)
>     }
>
>     selfless func initialiseProperty()
>     {
>         property = 4
>     }
> }
>
> Is this something of interest?
>
> Regards,
> Ross O'Brien
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
> +1. This is something that I was planning to propose. It comes up
> particularly often in Cocoa objects that implement NSCoding, where you have
> to implement both init(coder:) and the designated initializer. Currently,
> if you have a bunch of complicated code involved in setting defaults for
> your properties, in a manner that’s too complex to solve with simple
> default values, you end up with a lot of copy-paste code in the two
> initializers, which can easily get out of sync if one is edited without
> being diligent about editing the other one in the same way. The exception,
> of course, if if you make init(coder:) a convenience initializer, but then
> subclasses cannot call super’s implementation of init(coder:), which makes
> this unworkable in a lot of circumstances.
>
> I’m not sure “selfless” is the right keyword for this, but some sort of
> feature along these lines would be incredibly helpful.
>
> Charles
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151216/4e7e5844/attachment.html>


More information about the swift-evolution mailing list