Optional generics question


#1

Hi all,

Is there any support for having an optional type in an initializer? My use
case is I want to have a struct SectionWrapper that includes information
about a Collection View Section. So you can pass the CellType, Cell Data
Source, and an Optional HeaderType and HeaderDataSource if there is a
Section Header. Here's the code. I first have a protocol
ViewModelConfigurable that the Cell and Header subclasses conform to:

protocol ViewModelConfigurable

{

    associatedtype ViewModelType

    func configure(with viewModel : ViewModelType);

}

class TestCell : UICollectionViewCell, ViewModelConfigurable

{

    typealias ViewModelType = String

    func configure(with viewModel: String) {

        //todo

    }

}

class HeaderFooter : UICollectionReusableView, ViewModelConfigurable

{

    typealias ViewModelType = String

    func configure(with viewModel: String) {

        //todo

    }

}

I then have a SectionWrapper struct where I want to initialize with a
concrete UICollectionViewCell type that conforms to ViewModelType and pass
the associated dataSource which must be an array of ViewModelType. I also
want to have the ability to pass an optional UICollectionReusableView type
that conforms to ViewModelType with the associated dataSource. You could
then pass nil if this section does not have a Header. See below:

struct SectionWrapper

{

    let cellConfigure: (UICollectionViewCell, Int) -> ()

    let headerConfigure: ((UICollectionReusableView) -> ())?

    init<ActualCellType : UICollectionViewCell & ViewModelConfigurable,
HeaderType : UICollectionReusableView & ViewModelConfigurable>(cellType :
ActualCellType.Type, cellDataSource : [ActualCellType.ViewModelType],
headerType : (HeaderType.Type)?, headerDataSource : (HeaderType.
ViewModelType)?)

    {

        self.cellConfigure = { cell, index in

            (cell as! ActualCellType).configure(with: cellDataSource[index])

        }

        if let headerDataSource = headerDataSource

        {

            self.headerConfigure = { header in

                (header as! HeaderType).configure(with: headerDataSource);

            }

        }

        else

        {

            self.headerConfigure = nil

        }

    }

}

If I pass nil for headerType and headerDataSource, I get the following
error:

error: Swift4Test.playground:86:31: error: generic parameter
'ActualCellType' could not be inferred

let noHeader = SectionWrapper.init(cellType: TestCell.self,
cellDataSource: ["Test"], headerType: nil, headerDataSource: nil) //Gives
error

let header = SectionWrapper.init(cellType: TestCell.self, cellDataSource: [
"Test"], headerType: HeaderFooter.self, headerDataSource: "Header") //No
error

let noHeader = SectionWrapper.init(cellType: TestCell.self, cellDataSource:
["Test"], headerType: nil, headerDataSource: nil) //Gives error

I have also attached the Playground that I'm working through. Please let me
know if you have any questions and thanks in advance for your help!

Swift4Test.playground.zip (7.81 KB)


(Slava Pestov) #2

Hi all,

Is there any support for having an optional type in an initializer? My use case is I want to have a struct SectionWrapper that includes information about a Collection View Section. So you can pass the CellType, Cell Data Source, and an Optional HeaderType and HeaderDataSource if there is a Section Header. Here's the code. I first have a protocol ViewModelConfigurable that the Cell and Header subclasses conform to:

protocol ViewModelConfigurable
{
    associatedtype ViewModelType
    
    func configure(with viewModel : ViewModelType);
}

class TestCell : UICollectionViewCell, ViewModelConfigurable
{
    typealias ViewModelType = String
    func configure(with viewModel: String) {
        //todo
    }
}

class HeaderFooter : UICollectionReusableView, ViewModelConfigurable
{
    typealias ViewModelType = String
    func configure(with viewModel: String) {
        //todo
    }
}

I then have a SectionWrapper struct where I want to initialize with a concrete UICollectionViewCell type that conforms to ViewModelType and pass the associated dataSource which must be an array of ViewModelType. I also want to have the ability to pass an optional UICollectionReusableView type that conforms to ViewModelType with the associated dataSource. You could then pass nil if this section does not have a Header. See below:

struct SectionWrapper
{
    let cellConfigure: (UICollectionViewCell, Int) -> ()
    let headerConfigure: ((UICollectionReusableView) -> ())?
    
    init<ActualCellType : UICollectionViewCell & ViewModelConfigurable, HeaderType : UICollectionReusableView & ViewModelConfigurable>(cellType : ActualCellType.Type, cellDataSource : [ActualCellType.ViewModelType], headerType : (HeaderType.Type)?, headerDataSource : (HeaderType.ViewModelType)?)
    {
        self.cellConfigure = { cell, index in
            (cell as! ActualCellType).configure(with: cellDataSource[index])
        }
        
        if let headerDataSource = headerDataSource
        {
            self.headerConfigure = { header in
                (header as! HeaderType).configure(with: headerDataSource);
            }
        }
        else
        {
            self.headerConfigure = nil
        }
    }
}

If I pass nil for headerType and headerDataSource, I get the following error:
error: Swift4Test.playground:86:31: error: generic parameter 'ActualCellType' could not be inferred
let noHeader = SectionWrapper.init(cellType: TestCell.self, cellDataSource: ["Test"], headerType: nil, headerDataSource: nil) //Gives error

let header = SectionWrapper.init(cellType: TestCell.self, cellDataSource: ["Test"], headerType: HeaderFooter.self, headerDataSource: "Header") //No error

let noHeader = SectionWrapper.init(cellType: TestCell.self, cellDataSource: ["Test"], headerType: nil, headerDataSource: nil) //Gives error

I have also attached the Playground that I'm working through. Please let me know if you have any questions and thanks in advance for your help!

You could overload SectionWrapper.init(), providing two versions: one takes non-optional headerType and headerDataSource parameters, and the other does not take them at all, and only has a single generic parameter for ActualCellType.

Unfortunately we don’t support explicit specialization on function calls right now; if we did, you could write SectionWrapper.init<T, U> to explicitly bind the generic arguments.

Slava

···

On Jun 8, 2017, at 11:11 AM, Joel Loeshelle via swift-users <swift-users@swift.org> wrote:

<Swift4Test.playground.zip>_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users