reimplementation of a function added in a protocol extension isn’t called
I added a protocol extension for a protocol with an associated type called PickerType
. I wrote a reimplementation of a function, refresh(:,completion:)
that’s defined in the protocol and implemented in a different protocol extension.
But the function inside my new extension isn’t called when I call refresh(:,completion:)
unless the compiler knows what type PickerType
is. I wrote the following:
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we're trying to have this implementation called")
PickerType.startSync()
}
}
It gets called as I would expect if I call refresh(:,completion:)
on a PickerSectionProvider<ObservationType>
(see the code from my Playground below) but not when I call refresh(:,completion:)
on an ItemProvider
, which is a generic type that must conform to PickerItemProvider
(again see my code below).
// We are trying to get our pickers to sync their provided type when you pull to refresh. But the implementation of refresh(:, completion:) that we added doesn’t get called.
import Foundation
protocol PickerItemProvider: class {
associatedtype PickerType
func findItem(by identifier: NSNumber) -> PickerType?
func itemAt(_ indexPath: IndexPath) -> PickerType?
func refresh(_ sender: Any, completion: (() -> Void)?)
}
extension PickerItemProvider {
func findItem(by identifier: NSNumber) -> PickerType? {
return nil
}
public func refresh(_ sender: Any, completion: (() -> Void)?) {
print("the default refresh implementation")
}
}
public class PickerSectionProvider<ProvidedType: Equatable> : PickerItemProvider {
func itemAt(_ indexPath: IndexPath) -> ProvidedType? {
return nil
}
}
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we’re trying to have this implementation called instead of the above implementation of refresh")
PickerType.startSync()
}
}
protocol SyncableEntity {
static func startSync()
}
extension SyncableEntity {
static func startSync() {
}
}
class ObservationType: Equatable, SyncableEntity {
}
func ==(lhs: ObservationType, rhs: ObservationType) -> Bool {
return false
}
class GenericPickerViewController<PickerType: Equatable, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == PickerType {
var itemProvider: ItemProvider?
init() {
}
func foo() {
// Why doesn’t the implementation of refresh(:,completion:) we added get called here?
itemProvider?.refresh("dummy sender") {
}
}
}
class PopupPickerRow<T: Equatable, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == T {
var pickerController = GenericPickerViewController<T, ItemProvider>()
}
let pickerSectionProvider = PickerSectionProvider<ObservationType>()
let row = PopupPickerRow<ObservationType, PickerSectionProvider<ObservationType>>()
row.pickerController.itemProvider = pickerSectionProvider
row.pickerController.foo()
swift
add a comment |
I added a protocol extension for a protocol with an associated type called PickerType
. I wrote a reimplementation of a function, refresh(:,completion:)
that’s defined in the protocol and implemented in a different protocol extension.
But the function inside my new extension isn’t called when I call refresh(:,completion:)
unless the compiler knows what type PickerType
is. I wrote the following:
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we're trying to have this implementation called")
PickerType.startSync()
}
}
It gets called as I would expect if I call refresh(:,completion:)
on a PickerSectionProvider<ObservationType>
(see the code from my Playground below) but not when I call refresh(:,completion:)
on an ItemProvider
, which is a generic type that must conform to PickerItemProvider
(again see my code below).
// We are trying to get our pickers to sync their provided type when you pull to refresh. But the implementation of refresh(:, completion:) that we added doesn’t get called.
import Foundation
protocol PickerItemProvider: class {
associatedtype PickerType
func findItem(by identifier: NSNumber) -> PickerType?
func itemAt(_ indexPath: IndexPath) -> PickerType?
func refresh(_ sender: Any, completion: (() -> Void)?)
}
extension PickerItemProvider {
func findItem(by identifier: NSNumber) -> PickerType? {
return nil
}
public func refresh(_ sender: Any, completion: (() -> Void)?) {
print("the default refresh implementation")
}
}
public class PickerSectionProvider<ProvidedType: Equatable> : PickerItemProvider {
func itemAt(_ indexPath: IndexPath) -> ProvidedType? {
return nil
}
}
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we’re trying to have this implementation called instead of the above implementation of refresh")
PickerType.startSync()
}
}
protocol SyncableEntity {
static func startSync()
}
extension SyncableEntity {
static func startSync() {
}
}
class ObservationType: Equatable, SyncableEntity {
}
func ==(lhs: ObservationType, rhs: ObservationType) -> Bool {
return false
}
class GenericPickerViewController<PickerType: Equatable, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == PickerType {
var itemProvider: ItemProvider?
init() {
}
func foo() {
// Why doesn’t the implementation of refresh(:,completion:) we added get called here?
itemProvider?.refresh("dummy sender") {
}
}
}
class PopupPickerRow<T: Equatable, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == T {
var pickerController = GenericPickerViewController<T, ItemProvider>()
}
let pickerSectionProvider = PickerSectionProvider<ObservationType>()
let row = PopupPickerRow<ObservationType, PickerSectionProvider<ObservationType>>()
row.pickerController.itemProvider = pickerSectionProvider
row.pickerController.foo()
swift
add a comment |
I added a protocol extension for a protocol with an associated type called PickerType
. I wrote a reimplementation of a function, refresh(:,completion:)
that’s defined in the protocol and implemented in a different protocol extension.
But the function inside my new extension isn’t called when I call refresh(:,completion:)
unless the compiler knows what type PickerType
is. I wrote the following:
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we're trying to have this implementation called")
PickerType.startSync()
}
}
It gets called as I would expect if I call refresh(:,completion:)
on a PickerSectionProvider<ObservationType>
(see the code from my Playground below) but not when I call refresh(:,completion:)
on an ItemProvider
, which is a generic type that must conform to PickerItemProvider
(again see my code below).
// We are trying to get our pickers to sync their provided type when you pull to refresh. But the implementation of refresh(:, completion:) that we added doesn’t get called.
import Foundation
protocol PickerItemProvider: class {
associatedtype PickerType
func findItem(by identifier: NSNumber) -> PickerType?
func itemAt(_ indexPath: IndexPath) -> PickerType?
func refresh(_ sender: Any, completion: (() -> Void)?)
}
extension PickerItemProvider {
func findItem(by identifier: NSNumber) -> PickerType? {
return nil
}
public func refresh(_ sender: Any, completion: (() -> Void)?) {
print("the default refresh implementation")
}
}
public class PickerSectionProvider<ProvidedType: Equatable> : PickerItemProvider {
func itemAt(_ indexPath: IndexPath) -> ProvidedType? {
return nil
}
}
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we’re trying to have this implementation called instead of the above implementation of refresh")
PickerType.startSync()
}
}
protocol SyncableEntity {
static func startSync()
}
extension SyncableEntity {
static func startSync() {
}
}
class ObservationType: Equatable, SyncableEntity {
}
func ==(lhs: ObservationType, rhs: ObservationType) -> Bool {
return false
}
class GenericPickerViewController<PickerType: Equatable, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == PickerType {
var itemProvider: ItemProvider?
init() {
}
func foo() {
// Why doesn’t the implementation of refresh(:,completion:) we added get called here?
itemProvider?.refresh("dummy sender") {
}
}
}
class PopupPickerRow<T: Equatable, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == T {
var pickerController = GenericPickerViewController<T, ItemProvider>()
}
let pickerSectionProvider = PickerSectionProvider<ObservationType>()
let row = PopupPickerRow<ObservationType, PickerSectionProvider<ObservationType>>()
row.pickerController.itemProvider = pickerSectionProvider
row.pickerController.foo()
swift
I added a protocol extension for a protocol with an associated type called PickerType
. I wrote a reimplementation of a function, refresh(:,completion:)
that’s defined in the protocol and implemented in a different protocol extension.
But the function inside my new extension isn’t called when I call refresh(:,completion:)
unless the compiler knows what type PickerType
is. I wrote the following:
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we're trying to have this implementation called")
PickerType.startSync()
}
}
It gets called as I would expect if I call refresh(:,completion:)
on a PickerSectionProvider<ObservationType>
(see the code from my Playground below) but not when I call refresh(:,completion:)
on an ItemProvider
, which is a generic type that must conform to PickerItemProvider
(again see my code below).
// We are trying to get our pickers to sync their provided type when you pull to refresh. But the implementation of refresh(:, completion:) that we added doesn’t get called.
import Foundation
protocol PickerItemProvider: class {
associatedtype PickerType
func findItem(by identifier: NSNumber) -> PickerType?
func itemAt(_ indexPath: IndexPath) -> PickerType?
func refresh(_ sender: Any, completion: (() -> Void)?)
}
extension PickerItemProvider {
func findItem(by identifier: NSNumber) -> PickerType? {
return nil
}
public func refresh(_ sender: Any, completion: (() -> Void)?) {
print("the default refresh implementation")
}
}
public class PickerSectionProvider<ProvidedType: Equatable> : PickerItemProvider {
func itemAt(_ indexPath: IndexPath) -> ProvidedType? {
return nil
}
}
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we’re trying to have this implementation called instead of the above implementation of refresh")
PickerType.startSync()
}
}
protocol SyncableEntity {
static func startSync()
}
extension SyncableEntity {
static func startSync() {
}
}
class ObservationType: Equatable, SyncableEntity {
}
func ==(lhs: ObservationType, rhs: ObservationType) -> Bool {
return false
}
class GenericPickerViewController<PickerType: Equatable, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == PickerType {
var itemProvider: ItemProvider?
init() {
}
func foo() {
// Why doesn’t the implementation of refresh(:,completion:) we added get called here?
itemProvider?.refresh("dummy sender") {
}
}
}
class PopupPickerRow<T: Equatable, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == T {
var pickerController = GenericPickerViewController<T, ItemProvider>()
}
let pickerSectionProvider = PickerSectionProvider<ObservationType>()
let row = PopupPickerRow<ObservationType, PickerSectionProvider<ObservationType>>()
row.pickerController.itemProvider = pickerSectionProvider
row.pickerController.foo()
swift
swift
asked Nov 15 '18 at 22:28
Justin GarciaJustin Garcia
1137
1137
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
See the corrected implementation below,
import Foundation
protocol PickerItemProvider: class {
associatedtype PickerType
func findItem(by identifier: NSNumber) -> PickerType?
func itemAt(_ indexPath: IndexPath) -> PickerType?
}
extension PickerItemProvider {
func findItem(by identifier: NSNumber) -> PickerType? {
return nil
}
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("the default refresh implementation")
}
}
public class PickerSectionProvider<ProvidedType: Equatable> : PickerItemProvider {
func itemAt(_ indexPath: IndexPath) -> ProvidedType? {
return nil
}
}
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we’re trying to have this implementation called instead of the above implementation of refresh")
PickerType.startSync()
}
}
protocol SyncableEntity {
static func startSync()
}
extension SyncableEntity {
static func startSync() {
}
}
class ObservationType: Equatable, SyncableEntity {
}
func ==(lhs: ObservationType, rhs: ObservationType) -> Bool {
return false
}
class GenericPickerViewController<PickerType: Equatable & SyncableEntity, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == PickerType {
var itemProvider: ItemProvider?
init() {
}
func foo() {
// Why doesn’t the implementation of refresh(:,completion:) we added get called here?
itemProvider?.refresh("dummy sender") {
}
}
}
class PopupPickerRow<T: Equatable & SyncableEntity, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == T {
var pickerController = GenericPickerViewController<T, ItemProvider>()
}
let pickerSectionProvider = PickerSectionProvider<ObservationType>()
let row = PopupPickerRow<ObservationType, PickerSectionProvider<ObservationType>>()
row.pickerController.itemProvider = pickerSectionProvider
row.pickerController.foo()
First of all, when you want to override
a method
implementation declared as a requirement in the protocol
and provided some default implementation in the protocol
extension
it will always call the method implemented in the extension
discarding the where
clause requirements. You can see similar issues in this question and this.
So to make the protocol
look for the method
fulfilling the constraints in where
clause you need to remove the method
signature from the protocol
and keep it only inside the extension
as i did above.
Secondly you were missed the PickerType
requirement to be Equatable & SyncableEntity
while defining GenericPickerViewController
and PopupPickerRow
so i updated that also.
Thank you for your response, but we are trying to letPopupPickerRow
andGenericPickerViewController
work with anything as long as it’s Equatable, not restrict ourselves toEquatable & SyncableEntity
. If I remove that change you made the problem persists.
– Justin Garcia
Nov 15 '18 at 23:29
1
Yes, but then yourprotocol
requirement to call that method implementation will break and it will call the default method without considering any constraints. I hope you got the idea what was wrong with your implementation so its up to you how you want to handle it.
– Kamran
Nov 15 '18 at 23:35
I think I’m starting to understand. so at compile time the default implementation ofrefresh(:,completion:)
is chosen because all that is known about itemProvider is that it’s of a type that conforms to PickerItemProvider where PickerType is Equatable?
– Justin Garcia
Nov 15 '18 at 23:44
so I added an extension onGenericPickerViewController
wherePickerType
conforms toEquatable
andSyncableEntity
that adds a different implementation offoo()
. calls torefresh(:,completion:)
on itemProvider in that extension result in calls to therefresh(:,completion:)
implementation I added.
– Justin Garcia
Nov 15 '18 at 23:51
Well that works in the Playground but not in my project. I guess that’s because when the real foo() is compiled the compiler doesn’t know what type PickerType is going to be, so it chooses the default one not the one in the extension I added.
– Justin Garcia
Nov 16 '18 at 0:20
add a comment |
I added two functions on GenericPickerViewController
, one for setting it up with a PickerItemProvider
whose PickerType
simply conforms to Equatable
, and another to set it up with a PickerItemProvider
whose PickerType
conforms to SyncableEntity
. This way the compiler knows which refresh(:,completion:)
to call. Here is the Playground code:
import Foundation
import CoreData
protocol PickerItemProvider: class {
associatedtype PickerType
func itemAt(_ indexPath: IndexPath) -> PickerType?
}
extension PickerItemProvider {
public func refresh(_ sender: Any, completion: (() -> Void)?) {
print("the default refresh implementation")
}
}
public class PickerSectionProvider<ProvidedType: Equatable> : PickerItemProvider {
func itemAt(_ indexPath: IndexPath) -> ProvidedType? {
return nil
}
}
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we’re trying to have this implementation called instead of the above implementation of refresh")
PickerType.startSync()
completion?()
}
}
protocol SyncableEntity {
associatedtype EntityType
static func startSync()
}
extension SyncableEntity {
static func startSync() {
print("starting sync")
}
}
class ObservationType: Equatable, SyncableEntity {
typealias EntityType = NSManagedObject
}
func ==(lhs: ObservationType, rhs: ObservationType) -> Bool {
return false
}
class GeneralPickerViewController<PickerType: Equatable, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == PickerType {
private var itemProvider: ItemProvider?
private var refresher: ((Any, (() -> ())?) -> ())?
func setup<T: PickerItemProvider>(with itemProvider: T) where T.PickerType == PickerType {
refresher = { sender, completion in
itemProvider.refresh(self, completion: {
completion?()
})
}
self.itemProvider = (itemProvider as! ItemProvider)
}
func setup<T: PickerItemProvider>(with itemProvider: T) where T.PickerType == PickerType, PickerType: SyncableEntity {
refresher = { sender, completion in
itemProvider.refresh(self, completion: {
completion?()
})
}
self.itemProvider = (itemProvider as! ItemProvider)
}
func foo() {
refresher?(self, {
print("finished")
})
}
}
class PopupPickerRow<T: Equatable, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == T {
var pickerController = GeneralPickerViewController<T, ItemProvider>()
}
let pickerSectionProvider = PickerSectionProvider<ObservationType>()
let row = PopupPickerRow<ObservationType, PickerSectionProvider<ObservationType>>()
row.pickerController.setup(with: pickerSectionProvider)
row.pickerController.foo()
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53328770%2freimplementation-of-a-function-added-in-a-protocol-extension-isn-t-called%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
See the corrected implementation below,
import Foundation
protocol PickerItemProvider: class {
associatedtype PickerType
func findItem(by identifier: NSNumber) -> PickerType?
func itemAt(_ indexPath: IndexPath) -> PickerType?
}
extension PickerItemProvider {
func findItem(by identifier: NSNumber) -> PickerType? {
return nil
}
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("the default refresh implementation")
}
}
public class PickerSectionProvider<ProvidedType: Equatable> : PickerItemProvider {
func itemAt(_ indexPath: IndexPath) -> ProvidedType? {
return nil
}
}
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we’re trying to have this implementation called instead of the above implementation of refresh")
PickerType.startSync()
}
}
protocol SyncableEntity {
static func startSync()
}
extension SyncableEntity {
static func startSync() {
}
}
class ObservationType: Equatable, SyncableEntity {
}
func ==(lhs: ObservationType, rhs: ObservationType) -> Bool {
return false
}
class GenericPickerViewController<PickerType: Equatable & SyncableEntity, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == PickerType {
var itemProvider: ItemProvider?
init() {
}
func foo() {
// Why doesn’t the implementation of refresh(:,completion:) we added get called here?
itemProvider?.refresh("dummy sender") {
}
}
}
class PopupPickerRow<T: Equatable & SyncableEntity, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == T {
var pickerController = GenericPickerViewController<T, ItemProvider>()
}
let pickerSectionProvider = PickerSectionProvider<ObservationType>()
let row = PopupPickerRow<ObservationType, PickerSectionProvider<ObservationType>>()
row.pickerController.itemProvider = pickerSectionProvider
row.pickerController.foo()
First of all, when you want to override
a method
implementation declared as a requirement in the protocol
and provided some default implementation in the protocol
extension
it will always call the method implemented in the extension
discarding the where
clause requirements. You can see similar issues in this question and this.
So to make the protocol
look for the method
fulfilling the constraints in where
clause you need to remove the method
signature from the protocol
and keep it only inside the extension
as i did above.
Secondly you were missed the PickerType
requirement to be Equatable & SyncableEntity
while defining GenericPickerViewController
and PopupPickerRow
so i updated that also.
Thank you for your response, but we are trying to letPopupPickerRow
andGenericPickerViewController
work with anything as long as it’s Equatable, not restrict ourselves toEquatable & SyncableEntity
. If I remove that change you made the problem persists.
– Justin Garcia
Nov 15 '18 at 23:29
1
Yes, but then yourprotocol
requirement to call that method implementation will break and it will call the default method without considering any constraints. I hope you got the idea what was wrong with your implementation so its up to you how you want to handle it.
– Kamran
Nov 15 '18 at 23:35
I think I’m starting to understand. so at compile time the default implementation ofrefresh(:,completion:)
is chosen because all that is known about itemProvider is that it’s of a type that conforms to PickerItemProvider where PickerType is Equatable?
– Justin Garcia
Nov 15 '18 at 23:44
so I added an extension onGenericPickerViewController
wherePickerType
conforms toEquatable
andSyncableEntity
that adds a different implementation offoo()
. calls torefresh(:,completion:)
on itemProvider in that extension result in calls to therefresh(:,completion:)
implementation I added.
– Justin Garcia
Nov 15 '18 at 23:51
Well that works in the Playground but not in my project. I guess that’s because when the real foo() is compiled the compiler doesn’t know what type PickerType is going to be, so it chooses the default one not the one in the extension I added.
– Justin Garcia
Nov 16 '18 at 0:20
add a comment |
See the corrected implementation below,
import Foundation
protocol PickerItemProvider: class {
associatedtype PickerType
func findItem(by identifier: NSNumber) -> PickerType?
func itemAt(_ indexPath: IndexPath) -> PickerType?
}
extension PickerItemProvider {
func findItem(by identifier: NSNumber) -> PickerType? {
return nil
}
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("the default refresh implementation")
}
}
public class PickerSectionProvider<ProvidedType: Equatable> : PickerItemProvider {
func itemAt(_ indexPath: IndexPath) -> ProvidedType? {
return nil
}
}
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we’re trying to have this implementation called instead of the above implementation of refresh")
PickerType.startSync()
}
}
protocol SyncableEntity {
static func startSync()
}
extension SyncableEntity {
static func startSync() {
}
}
class ObservationType: Equatable, SyncableEntity {
}
func ==(lhs: ObservationType, rhs: ObservationType) -> Bool {
return false
}
class GenericPickerViewController<PickerType: Equatable & SyncableEntity, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == PickerType {
var itemProvider: ItemProvider?
init() {
}
func foo() {
// Why doesn’t the implementation of refresh(:,completion:) we added get called here?
itemProvider?.refresh("dummy sender") {
}
}
}
class PopupPickerRow<T: Equatable & SyncableEntity, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == T {
var pickerController = GenericPickerViewController<T, ItemProvider>()
}
let pickerSectionProvider = PickerSectionProvider<ObservationType>()
let row = PopupPickerRow<ObservationType, PickerSectionProvider<ObservationType>>()
row.pickerController.itemProvider = pickerSectionProvider
row.pickerController.foo()
First of all, when you want to override
a method
implementation declared as a requirement in the protocol
and provided some default implementation in the protocol
extension
it will always call the method implemented in the extension
discarding the where
clause requirements. You can see similar issues in this question and this.
So to make the protocol
look for the method
fulfilling the constraints in where
clause you need to remove the method
signature from the protocol
and keep it only inside the extension
as i did above.
Secondly you were missed the PickerType
requirement to be Equatable & SyncableEntity
while defining GenericPickerViewController
and PopupPickerRow
so i updated that also.
Thank you for your response, but we are trying to letPopupPickerRow
andGenericPickerViewController
work with anything as long as it’s Equatable, not restrict ourselves toEquatable & SyncableEntity
. If I remove that change you made the problem persists.
– Justin Garcia
Nov 15 '18 at 23:29
1
Yes, but then yourprotocol
requirement to call that method implementation will break and it will call the default method without considering any constraints. I hope you got the idea what was wrong with your implementation so its up to you how you want to handle it.
– Kamran
Nov 15 '18 at 23:35
I think I’m starting to understand. so at compile time the default implementation ofrefresh(:,completion:)
is chosen because all that is known about itemProvider is that it’s of a type that conforms to PickerItemProvider where PickerType is Equatable?
– Justin Garcia
Nov 15 '18 at 23:44
so I added an extension onGenericPickerViewController
wherePickerType
conforms toEquatable
andSyncableEntity
that adds a different implementation offoo()
. calls torefresh(:,completion:)
on itemProvider in that extension result in calls to therefresh(:,completion:)
implementation I added.
– Justin Garcia
Nov 15 '18 at 23:51
Well that works in the Playground but not in my project. I guess that’s because when the real foo() is compiled the compiler doesn’t know what type PickerType is going to be, so it chooses the default one not the one in the extension I added.
– Justin Garcia
Nov 16 '18 at 0:20
add a comment |
See the corrected implementation below,
import Foundation
protocol PickerItemProvider: class {
associatedtype PickerType
func findItem(by identifier: NSNumber) -> PickerType?
func itemAt(_ indexPath: IndexPath) -> PickerType?
}
extension PickerItemProvider {
func findItem(by identifier: NSNumber) -> PickerType? {
return nil
}
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("the default refresh implementation")
}
}
public class PickerSectionProvider<ProvidedType: Equatable> : PickerItemProvider {
func itemAt(_ indexPath: IndexPath) -> ProvidedType? {
return nil
}
}
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we’re trying to have this implementation called instead of the above implementation of refresh")
PickerType.startSync()
}
}
protocol SyncableEntity {
static func startSync()
}
extension SyncableEntity {
static func startSync() {
}
}
class ObservationType: Equatable, SyncableEntity {
}
func ==(lhs: ObservationType, rhs: ObservationType) -> Bool {
return false
}
class GenericPickerViewController<PickerType: Equatable & SyncableEntity, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == PickerType {
var itemProvider: ItemProvider?
init() {
}
func foo() {
// Why doesn’t the implementation of refresh(:,completion:) we added get called here?
itemProvider?.refresh("dummy sender") {
}
}
}
class PopupPickerRow<T: Equatable & SyncableEntity, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == T {
var pickerController = GenericPickerViewController<T, ItemProvider>()
}
let pickerSectionProvider = PickerSectionProvider<ObservationType>()
let row = PopupPickerRow<ObservationType, PickerSectionProvider<ObservationType>>()
row.pickerController.itemProvider = pickerSectionProvider
row.pickerController.foo()
First of all, when you want to override
a method
implementation declared as a requirement in the protocol
and provided some default implementation in the protocol
extension
it will always call the method implemented in the extension
discarding the where
clause requirements. You can see similar issues in this question and this.
So to make the protocol
look for the method
fulfilling the constraints in where
clause you need to remove the method
signature from the protocol
and keep it only inside the extension
as i did above.
Secondly you were missed the PickerType
requirement to be Equatable & SyncableEntity
while defining GenericPickerViewController
and PopupPickerRow
so i updated that also.
See the corrected implementation below,
import Foundation
protocol PickerItemProvider: class {
associatedtype PickerType
func findItem(by identifier: NSNumber) -> PickerType?
func itemAt(_ indexPath: IndexPath) -> PickerType?
}
extension PickerItemProvider {
func findItem(by identifier: NSNumber) -> PickerType? {
return nil
}
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("the default refresh implementation")
}
}
public class PickerSectionProvider<ProvidedType: Equatable> : PickerItemProvider {
func itemAt(_ indexPath: IndexPath) -> ProvidedType? {
return nil
}
}
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we’re trying to have this implementation called instead of the above implementation of refresh")
PickerType.startSync()
}
}
protocol SyncableEntity {
static func startSync()
}
extension SyncableEntity {
static func startSync() {
}
}
class ObservationType: Equatable, SyncableEntity {
}
func ==(lhs: ObservationType, rhs: ObservationType) -> Bool {
return false
}
class GenericPickerViewController<PickerType: Equatable & SyncableEntity, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == PickerType {
var itemProvider: ItemProvider?
init() {
}
func foo() {
// Why doesn’t the implementation of refresh(:,completion:) we added get called here?
itemProvider?.refresh("dummy sender") {
}
}
}
class PopupPickerRow<T: Equatable & SyncableEntity, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == T {
var pickerController = GenericPickerViewController<T, ItemProvider>()
}
let pickerSectionProvider = PickerSectionProvider<ObservationType>()
let row = PopupPickerRow<ObservationType, PickerSectionProvider<ObservationType>>()
row.pickerController.itemProvider = pickerSectionProvider
row.pickerController.foo()
First of all, when you want to override
a method
implementation declared as a requirement in the protocol
and provided some default implementation in the protocol
extension
it will always call the method implemented in the extension
discarding the where
clause requirements. You can see similar issues in this question and this.
So to make the protocol
look for the method
fulfilling the constraints in where
clause you need to remove the method
signature from the protocol
and keep it only inside the extension
as i did above.
Secondly you were missed the PickerType
requirement to be Equatable & SyncableEntity
while defining GenericPickerViewController
and PopupPickerRow
so i updated that also.
edited Nov 15 '18 at 23:13
answered Nov 15 '18 at 23:03
KamranKamran
6,55821028
6,55821028
Thank you for your response, but we are trying to letPopupPickerRow
andGenericPickerViewController
work with anything as long as it’s Equatable, not restrict ourselves toEquatable & SyncableEntity
. If I remove that change you made the problem persists.
– Justin Garcia
Nov 15 '18 at 23:29
1
Yes, but then yourprotocol
requirement to call that method implementation will break and it will call the default method without considering any constraints. I hope you got the idea what was wrong with your implementation so its up to you how you want to handle it.
– Kamran
Nov 15 '18 at 23:35
I think I’m starting to understand. so at compile time the default implementation ofrefresh(:,completion:)
is chosen because all that is known about itemProvider is that it’s of a type that conforms to PickerItemProvider where PickerType is Equatable?
– Justin Garcia
Nov 15 '18 at 23:44
so I added an extension onGenericPickerViewController
wherePickerType
conforms toEquatable
andSyncableEntity
that adds a different implementation offoo()
. calls torefresh(:,completion:)
on itemProvider in that extension result in calls to therefresh(:,completion:)
implementation I added.
– Justin Garcia
Nov 15 '18 at 23:51
Well that works in the Playground but not in my project. I guess that’s because when the real foo() is compiled the compiler doesn’t know what type PickerType is going to be, so it chooses the default one not the one in the extension I added.
– Justin Garcia
Nov 16 '18 at 0:20
add a comment |
Thank you for your response, but we are trying to letPopupPickerRow
andGenericPickerViewController
work with anything as long as it’s Equatable, not restrict ourselves toEquatable & SyncableEntity
. If I remove that change you made the problem persists.
– Justin Garcia
Nov 15 '18 at 23:29
1
Yes, but then yourprotocol
requirement to call that method implementation will break and it will call the default method without considering any constraints. I hope you got the idea what was wrong with your implementation so its up to you how you want to handle it.
– Kamran
Nov 15 '18 at 23:35
I think I’m starting to understand. so at compile time the default implementation ofrefresh(:,completion:)
is chosen because all that is known about itemProvider is that it’s of a type that conforms to PickerItemProvider where PickerType is Equatable?
– Justin Garcia
Nov 15 '18 at 23:44
so I added an extension onGenericPickerViewController
wherePickerType
conforms toEquatable
andSyncableEntity
that adds a different implementation offoo()
. calls torefresh(:,completion:)
on itemProvider in that extension result in calls to therefresh(:,completion:)
implementation I added.
– Justin Garcia
Nov 15 '18 at 23:51
Well that works in the Playground but not in my project. I guess that’s because when the real foo() is compiled the compiler doesn’t know what type PickerType is going to be, so it chooses the default one not the one in the extension I added.
– Justin Garcia
Nov 16 '18 at 0:20
Thank you for your response, but we are trying to let
PopupPickerRow
and GenericPickerViewController
work with anything as long as it’s Equatable, not restrict ourselves to Equatable & SyncableEntity
. If I remove that change you made the problem persists.– Justin Garcia
Nov 15 '18 at 23:29
Thank you for your response, but we are trying to let
PopupPickerRow
and GenericPickerViewController
work with anything as long as it’s Equatable, not restrict ourselves to Equatable & SyncableEntity
. If I remove that change you made the problem persists.– Justin Garcia
Nov 15 '18 at 23:29
1
1
Yes, but then your
protocol
requirement to call that method implementation will break and it will call the default method without considering any constraints. I hope you got the idea what was wrong with your implementation so its up to you how you want to handle it.– Kamran
Nov 15 '18 at 23:35
Yes, but then your
protocol
requirement to call that method implementation will break and it will call the default method without considering any constraints. I hope you got the idea what was wrong with your implementation so its up to you how you want to handle it.– Kamran
Nov 15 '18 at 23:35
I think I’m starting to understand. so at compile time the default implementation of
refresh(:,completion:)
is chosen because all that is known about itemProvider is that it’s of a type that conforms to PickerItemProvider where PickerType is Equatable?– Justin Garcia
Nov 15 '18 at 23:44
I think I’m starting to understand. so at compile time the default implementation of
refresh(:,completion:)
is chosen because all that is known about itemProvider is that it’s of a type that conforms to PickerItemProvider where PickerType is Equatable?– Justin Garcia
Nov 15 '18 at 23:44
so I added an extension on
GenericPickerViewController
where PickerType
conforms to Equatable
and SyncableEntity
that adds a different implementation of foo()
. calls to refresh(:,completion:)
on itemProvider in that extension result in calls to the refresh(:,completion:)
implementation I added.– Justin Garcia
Nov 15 '18 at 23:51
so I added an extension on
GenericPickerViewController
where PickerType
conforms to Equatable
and SyncableEntity
that adds a different implementation of foo()
. calls to refresh(:,completion:)
on itemProvider in that extension result in calls to the refresh(:,completion:)
implementation I added.– Justin Garcia
Nov 15 '18 at 23:51
Well that works in the Playground but not in my project. I guess that’s because when the real foo() is compiled the compiler doesn’t know what type PickerType is going to be, so it chooses the default one not the one in the extension I added.
– Justin Garcia
Nov 16 '18 at 0:20
Well that works in the Playground but not in my project. I guess that’s because when the real foo() is compiled the compiler doesn’t know what type PickerType is going to be, so it chooses the default one not the one in the extension I added.
– Justin Garcia
Nov 16 '18 at 0:20
add a comment |
I added two functions on GenericPickerViewController
, one for setting it up with a PickerItemProvider
whose PickerType
simply conforms to Equatable
, and another to set it up with a PickerItemProvider
whose PickerType
conforms to SyncableEntity
. This way the compiler knows which refresh(:,completion:)
to call. Here is the Playground code:
import Foundation
import CoreData
protocol PickerItemProvider: class {
associatedtype PickerType
func itemAt(_ indexPath: IndexPath) -> PickerType?
}
extension PickerItemProvider {
public func refresh(_ sender: Any, completion: (() -> Void)?) {
print("the default refresh implementation")
}
}
public class PickerSectionProvider<ProvidedType: Equatable> : PickerItemProvider {
func itemAt(_ indexPath: IndexPath) -> ProvidedType? {
return nil
}
}
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we’re trying to have this implementation called instead of the above implementation of refresh")
PickerType.startSync()
completion?()
}
}
protocol SyncableEntity {
associatedtype EntityType
static func startSync()
}
extension SyncableEntity {
static func startSync() {
print("starting sync")
}
}
class ObservationType: Equatable, SyncableEntity {
typealias EntityType = NSManagedObject
}
func ==(lhs: ObservationType, rhs: ObservationType) -> Bool {
return false
}
class GeneralPickerViewController<PickerType: Equatable, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == PickerType {
private var itemProvider: ItemProvider?
private var refresher: ((Any, (() -> ())?) -> ())?
func setup<T: PickerItemProvider>(with itemProvider: T) where T.PickerType == PickerType {
refresher = { sender, completion in
itemProvider.refresh(self, completion: {
completion?()
})
}
self.itemProvider = (itemProvider as! ItemProvider)
}
func setup<T: PickerItemProvider>(with itemProvider: T) where T.PickerType == PickerType, PickerType: SyncableEntity {
refresher = { sender, completion in
itemProvider.refresh(self, completion: {
completion?()
})
}
self.itemProvider = (itemProvider as! ItemProvider)
}
func foo() {
refresher?(self, {
print("finished")
})
}
}
class PopupPickerRow<T: Equatable, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == T {
var pickerController = GeneralPickerViewController<T, ItemProvider>()
}
let pickerSectionProvider = PickerSectionProvider<ObservationType>()
let row = PopupPickerRow<ObservationType, PickerSectionProvider<ObservationType>>()
row.pickerController.setup(with: pickerSectionProvider)
row.pickerController.foo()
add a comment |
I added two functions on GenericPickerViewController
, one for setting it up with a PickerItemProvider
whose PickerType
simply conforms to Equatable
, and another to set it up with a PickerItemProvider
whose PickerType
conforms to SyncableEntity
. This way the compiler knows which refresh(:,completion:)
to call. Here is the Playground code:
import Foundation
import CoreData
protocol PickerItemProvider: class {
associatedtype PickerType
func itemAt(_ indexPath: IndexPath) -> PickerType?
}
extension PickerItemProvider {
public func refresh(_ sender: Any, completion: (() -> Void)?) {
print("the default refresh implementation")
}
}
public class PickerSectionProvider<ProvidedType: Equatable> : PickerItemProvider {
func itemAt(_ indexPath: IndexPath) -> ProvidedType? {
return nil
}
}
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we’re trying to have this implementation called instead of the above implementation of refresh")
PickerType.startSync()
completion?()
}
}
protocol SyncableEntity {
associatedtype EntityType
static func startSync()
}
extension SyncableEntity {
static func startSync() {
print("starting sync")
}
}
class ObservationType: Equatable, SyncableEntity {
typealias EntityType = NSManagedObject
}
func ==(lhs: ObservationType, rhs: ObservationType) -> Bool {
return false
}
class GeneralPickerViewController<PickerType: Equatable, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == PickerType {
private var itemProvider: ItemProvider?
private var refresher: ((Any, (() -> ())?) -> ())?
func setup<T: PickerItemProvider>(with itemProvider: T) where T.PickerType == PickerType {
refresher = { sender, completion in
itemProvider.refresh(self, completion: {
completion?()
})
}
self.itemProvider = (itemProvider as! ItemProvider)
}
func setup<T: PickerItemProvider>(with itemProvider: T) where T.PickerType == PickerType, PickerType: SyncableEntity {
refresher = { sender, completion in
itemProvider.refresh(self, completion: {
completion?()
})
}
self.itemProvider = (itemProvider as! ItemProvider)
}
func foo() {
refresher?(self, {
print("finished")
})
}
}
class PopupPickerRow<T: Equatable, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == T {
var pickerController = GeneralPickerViewController<T, ItemProvider>()
}
let pickerSectionProvider = PickerSectionProvider<ObservationType>()
let row = PopupPickerRow<ObservationType, PickerSectionProvider<ObservationType>>()
row.pickerController.setup(with: pickerSectionProvider)
row.pickerController.foo()
add a comment |
I added two functions on GenericPickerViewController
, one for setting it up with a PickerItemProvider
whose PickerType
simply conforms to Equatable
, and another to set it up with a PickerItemProvider
whose PickerType
conforms to SyncableEntity
. This way the compiler knows which refresh(:,completion:)
to call. Here is the Playground code:
import Foundation
import CoreData
protocol PickerItemProvider: class {
associatedtype PickerType
func itemAt(_ indexPath: IndexPath) -> PickerType?
}
extension PickerItemProvider {
public func refresh(_ sender: Any, completion: (() -> Void)?) {
print("the default refresh implementation")
}
}
public class PickerSectionProvider<ProvidedType: Equatable> : PickerItemProvider {
func itemAt(_ indexPath: IndexPath) -> ProvidedType? {
return nil
}
}
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we’re trying to have this implementation called instead of the above implementation of refresh")
PickerType.startSync()
completion?()
}
}
protocol SyncableEntity {
associatedtype EntityType
static func startSync()
}
extension SyncableEntity {
static func startSync() {
print("starting sync")
}
}
class ObservationType: Equatable, SyncableEntity {
typealias EntityType = NSManagedObject
}
func ==(lhs: ObservationType, rhs: ObservationType) -> Bool {
return false
}
class GeneralPickerViewController<PickerType: Equatable, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == PickerType {
private var itemProvider: ItemProvider?
private var refresher: ((Any, (() -> ())?) -> ())?
func setup<T: PickerItemProvider>(with itemProvider: T) where T.PickerType == PickerType {
refresher = { sender, completion in
itemProvider.refresh(self, completion: {
completion?()
})
}
self.itemProvider = (itemProvider as! ItemProvider)
}
func setup<T: PickerItemProvider>(with itemProvider: T) where T.PickerType == PickerType, PickerType: SyncableEntity {
refresher = { sender, completion in
itemProvider.refresh(self, completion: {
completion?()
})
}
self.itemProvider = (itemProvider as! ItemProvider)
}
func foo() {
refresher?(self, {
print("finished")
})
}
}
class PopupPickerRow<T: Equatable, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == T {
var pickerController = GeneralPickerViewController<T, ItemProvider>()
}
let pickerSectionProvider = PickerSectionProvider<ObservationType>()
let row = PopupPickerRow<ObservationType, PickerSectionProvider<ObservationType>>()
row.pickerController.setup(with: pickerSectionProvider)
row.pickerController.foo()
I added two functions on GenericPickerViewController
, one for setting it up with a PickerItemProvider
whose PickerType
simply conforms to Equatable
, and another to set it up with a PickerItemProvider
whose PickerType
conforms to SyncableEntity
. This way the compiler knows which refresh(:,completion:)
to call. Here is the Playground code:
import Foundation
import CoreData
protocol PickerItemProvider: class {
associatedtype PickerType
func itemAt(_ indexPath: IndexPath) -> PickerType?
}
extension PickerItemProvider {
public func refresh(_ sender: Any, completion: (() -> Void)?) {
print("the default refresh implementation")
}
}
public class PickerSectionProvider<ProvidedType: Equatable> : PickerItemProvider {
func itemAt(_ indexPath: IndexPath) -> ProvidedType? {
return nil
}
}
extension PickerItemProvider where PickerType: Equatable & SyncableEntity {
func refresh(_ sender: Any, completion: (() -> Void)?) {
print("we’re trying to have this implementation called instead of the above implementation of refresh")
PickerType.startSync()
completion?()
}
}
protocol SyncableEntity {
associatedtype EntityType
static func startSync()
}
extension SyncableEntity {
static func startSync() {
print("starting sync")
}
}
class ObservationType: Equatable, SyncableEntity {
typealias EntityType = NSManagedObject
}
func ==(lhs: ObservationType, rhs: ObservationType) -> Bool {
return false
}
class GeneralPickerViewController<PickerType: Equatable, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == PickerType {
private var itemProvider: ItemProvider?
private var refresher: ((Any, (() -> ())?) -> ())?
func setup<T: PickerItemProvider>(with itemProvider: T) where T.PickerType == PickerType {
refresher = { sender, completion in
itemProvider.refresh(self, completion: {
completion?()
})
}
self.itemProvider = (itemProvider as! ItemProvider)
}
func setup<T: PickerItemProvider>(with itemProvider: T) where T.PickerType == PickerType, PickerType: SyncableEntity {
refresher = { sender, completion in
itemProvider.refresh(self, completion: {
completion?()
})
}
self.itemProvider = (itemProvider as! ItemProvider)
}
func foo() {
refresher?(self, {
print("finished")
})
}
}
class PopupPickerRow<T: Equatable, ItemProvider: PickerItemProvider> where ItemProvider.PickerType == T {
var pickerController = GeneralPickerViewController<T, ItemProvider>()
}
let pickerSectionProvider = PickerSectionProvider<ObservationType>()
let row = PopupPickerRow<ObservationType, PickerSectionProvider<ObservationType>>()
row.pickerController.setup(with: pickerSectionProvider)
row.pickerController.foo()
answered Nov 16 '18 at 5:50
Justin GarciaJustin Garcia
1137
1137
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53328770%2freimplementation-of-a-function-added-in-a-protocol-extension-isn-t-called%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown