Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic parameter 'Element' could not be inferred #53

Closed
2 tasks done
wousser opened this issue Sep 17, 2019 · 5 comments
Closed
2 tasks done

Generic parameter 'Element' could not be inferred #53

wousser opened this issue Sep 17, 2019 · 5 comments

Comments

@wousser
Copy link

wousser commented Sep 17, 2019

Checklist

Expected Behavior

While updating from RC2 to RC4, the next issue happens.

Current Behavior

Array of class [ClassName], using the group function to list as cells.

cells: {
                        Group(of: state.todos.enumerated()) { offset, todo in
                            TodoText(todo: todo, isCompleted: false)
}}

Detailed Description (Include Screenshots)

However, using another class results in this error:
Generic parameter 'Element' could not be inferred. Explicitly specify the generic arguments to fix this issue
When explicitly specifying arguments I get the following error:
Unable to infer closure type in the current context.

What am I doing wrong?

Environment

  • Carbon version:
    RC4
@ra1028
Copy link
Owner

ra1028 commented Sep 17, 2019

@wousser

The compiler may have output an incorrect error.
Is TodoText conform to Identifiable Component?
TodoText(todo: todo, isCompleted: false).identified(by: \.todo.id)
Isn't there any other parameters wrong?

BTW, thank you for opening some issues.
However, they were the general question related to the Swift type system, so please try-and-error by referring to the API doc before opening the issue.

@wousser
Copy link
Author

wousser commented Sep 17, 2019

Thanks for your quick answers.

The reason I'm asking here is that it worked with RC2, I didn't expect any breaking changes in an RC.

I'm trying to rewrite this part:

struct UpcomingEvent {
    typealias ID = UUID

    var id: ID
    var date: Date
    var events: [Any] // Contact, (Reminder, Contact), (Date, Contact)
}

struct State {
  var upcomingEvents = [UpcomingEvent]()
}
Section(id: "upcoming") { section in
                section.header = ViewNode(UpcomingHeader())

                state.upcomingEvents.forEach({ event in
                    section.cells.append(
                        CellNode(UpcomingDateCard(date: event.date))
                    )

                    event.events.forEach({ (eventType) in

                        //contact
                        if let contact = eventType as? Contact {
                            section.cells.append(
                                CellNode(UpcomingContactCellNode(contact: contact))
                            )
                        }

                        //reminder
                        if let reminder = eventType as? (Reminder, Contact) {
                            section.cells.append(
                                CellNode(UpcomingReminderCellNode(reminder: reminder))
                            )
                        }

                        //birthday
                        if let birthday = eventType as? (Date, Contact) {
                            section.cells.append(
                                CellNode(UpcomingBirthday(birthday: birthday))
                            )
                        }
                    })
                })
        }

All CellNode's conform to Identifiable Component.

I tried to rewrite it as Group(of: ) but wasn't able to. Maybe you can share the best way to go ahead?

@ra1028
Copy link
Owner

ra1028 commented Sep 17, 2019

Dynamic type casting isn't compatible with function builder because if let and switch statements are not allowed.
I recommended to rewrite using enum, but you can also take the following workaround with legacy API.
This hasn't actually try to compiled, but it probably works.

Section(
    id: "upcoming",
    header: ViewNode(UpcomingHeader()),
    cells: state.upcomingEvents.flatMap { event -> [CellNode] in
        event.events.compactMap { eventType -> CellNode? in
            //contact
            if let contact = eventType as? Contact {
                return CellNode(UpcomingContact(contact: contact))
            }

            //reminder
            if let reminder = eventType as? (Reminder, Contact) {
                return CellNode(UpcomingReminder(reminder: reminder))
            }

            //birthday
            if let birthday = eventType as? (Date, Contact) {
                return CellNode(UpcomingBirthday(birthday: birthday))
            }

            return  nil
        }
    }
)

@ra1028
Copy link
Owner

ra1028 commented Sep 17, 2019

Another approach with function builder.

func component(for eventType: Any) -> AnyComponent? {
    //contact
    if let contact = eventType as? Contact {
        return AnyComponent(UpcomingContactCellNode(contact: contact))
    }

    //reminder
    if let reminder = eventType as? (Reminder, Contact) {
        return AnyComponent(UpcomingReminderCellNode(reminder: reminder))
    }

    //birthday
    if let birthday = eventType as? (Date, Contact) {
        return AnyComponent(UpcomingBirthday(birthday: birthday))
    }

    return  nil
}


Section(
    id: "upcoming",
    header:UpcomingHeader(),
    cells: {
        Group(of: state.upcomingEvents) { event in
            Group(of: event.events.compactMap { eventType in
                component(for: eventType)
            }
        }
    }
)

@wousser
Copy link
Author

wousser commented Sep 17, 2019

Thanks for your help. That approach works great.

@wousser wousser closed this as completed Sep 17, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants