Can't implement generic subscript in protocol

Greetings

Now we've got generic subscripts, I thought I'd play…

protocol DataProvider
{
  subscript<itemType>(index: Int) -> itemType { get }
}

class Test : DataProvider // error : Type 'Test' does not conform to protocol 'DataProvider'
{
  subscript(index: Int) -> String
  {
    return "Fred"
  }
}

Simple questions:

1. why does this not compile?
2. should it?
3. is there a workaround without declaring an associated type in the protocol?

Joanna

···

--
Joanna Carter
Carter Consulting

Xcode Version 9.0 (9A235)

Hmmm. I'm now getting a segmentation fault : 11 on a constructor when trying to implement type erasure :

protocol DataProvider
{
  associatedtype ItemType
  
  subscript(index: Int) -> ItemType { get }
}

class _AnyDataProviderBoxBase<itemType>: DataProvider
{
  subscript(index: Int) -> itemType
  {
    fatalError()
  }
}

class _AnyDataProviderBox<providerType: DataProvider>: _AnyDataProviderBoxBase<providerType.ItemType>
{
  private let _subscript: (_ index: Int) -> providerType.ItemType
  
  init(_ base: providerType) // segmentation fault : 11
  {
    _subscript = base.subscript
  }
  
  override subscript(index: Int) -> providerType.ItemType
  {
    return _subscript(index)
  }
}

final class AnyDataProvider<providerType : DataProvider>: DataProvider
{
  private let box: _AnyDataProviderBox<providerType>
  
  init(_ base: providerType)
  {
    self.box = _AnyDataProviderBox(base)
  }
  
  subscript(index: Int) -> providerType.ItemType
  {
    return box[index]
  }
}

Joanna

···

--
Joanna Carter
Carter Consulting

Greetings

Now we've got generic subscripts, I thought I'd play…

protocol DataProvider
{
subscript<itemType>(index: Int) -> itemType { get }
}

This is a valid usage of your protocol:

func doesStuff(p: DataProvider) {
  let i: Int = p[0]
  let s: String = p[1]
}

class Test : DataProvider // error : Type 'Test' does not conform to protocol 'DataProvider'
{
subscript(index: Int) -> String
{
   return "Fred"
}
}

Simple questions:

1. why does this not compile?

Imagine if I pass an instance of class Test to my function doesStuff() above. What would the first line of code do, given that it’s expecting to get back an Int result but the subscript in the class always returns a String?

2. should it?
3. is there a workaround without declaring an associated type in the protocol?

Either the protocol should have a non-generic subscript, or the class should have a generic subscript. Note that the same would happen if you do something like

protocol P {
  func f<T>() -> T
}

class C : P {
  func f() -> String
}

Again, here C.f is ‘too concrete’.

Slava

···

On Sep 15, 2017, at 12:40 PM, Joanna Carter via swift-users <swift-users@swift.org> wrote:

Joanna

--
Joanna Carter
Carter Consulting

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Xcode Version 9.0 (9A235)

Hmmm. I'm now getting a segmentation fault : 11 on a constructor when trying to implement type erasure :

Swift 4.0 had issues with members and member references named ‘subscript’. On master, I get the correct error message without crashing:

Slavas-MBP:swift slava$ ../build/Ninja-ReleaseAssert/swift-macosx-x86_64/bin/swiftc sub.swift
sub.swift:22:17: error: value of type 'providerType' has no member 'subscript'
   _subscript = base.subscript
                ^~~~ ~~~~~~~~~

Indeed you’re not supposed to be able to refer to a subscript member like this. You could use a keypath, or try some other approach.

Slava

···

On Sep 15, 2017, at 12:40 PM, Joanna Carter via swift-users <swift-users@swift.org> wrote:

protocol DataProvider
{
associatedtype ItemType

subscript(index: Int) -> ItemType { get }
}

class _AnyDataProviderBoxBase<itemType>: DataProvider
{
subscript(index: Int) -> itemType
{
   fatalError()
}
}

class _AnyDataProviderBox<providerType: DataProvider>: _AnyDataProviderBoxBase<providerType.ItemType>
{
private let _subscript: (_ index: Int) -> providerType.ItemType

init(_ base: providerType) // segmentation fault : 11
{
   _subscript = base.subscript
}

override subscript(index: Int) -> providerType.ItemType
{
   return _subscript(index)
}
}

final class AnyDataProvider<providerType : DataProvider>: DataProvider
{
private let box: _AnyDataProviderBox<providerType>

init(_ base: providerType)
{
   self.box = _AnyDataProviderBox(base)
}

subscript(index: Int) -> providerType.ItemType
{
   return box[index]
}
}

Joanna

--
Joanna Carter
Carter Consulting

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

The answer to the segmentation fault is that I was trying to assign the subscript "method" to a closure var of the same signature.

It would seem Swift doesn't allow this :-(

Joanna

···

--
Joanna Carter
Carter Consulting

Xcode Version 9.0 (9A235)

Hmmm. I'm now getting a segmentation fault : 11 on a constructor when trying to implement type erasure :

Swift 4.0 had issues with members and member references named ‘subscript’. On master, I get the correct error message without crashing:

Slavas-MBP:swift slava$ ../build/Ninja-ReleaseAssert/swift-macosx-x86_64/bin/swiftc sub.swift
sub.swift:22:17: error: value of type 'providerType' has no member 'subscript'
  _subscript = base.subscript
               ^~~~ ~~~~~~~~~

Indeed you’re not supposed to be able to refer to a subscript member like this. You could use a keypath, or try some other approach.

You could also write an explicit closure that loads the subscript:

let fn = { base[$0] }

Slava

···

On Sep 15, 2017, at 4:26 PM, Slava Pestov <spestov@apple.com> wrote:

On Sep 15, 2017, at 12:40 PM, Joanna Carter via swift-users <swift-users@swift.org> wrote:

Slava

protocol DataProvider
{
associatedtype ItemType

subscript(index: Int) -> ItemType { get }
}

class _AnyDataProviderBoxBase<itemType>: DataProvider
{
subscript(index: Int) -> itemType
{
  fatalError()
}
}

class _AnyDataProviderBox<providerType: DataProvider>: _AnyDataProviderBoxBase<providerType.ItemType>
{
private let _subscript: (_ index: Int) -> providerType.ItemType

init(_ base: providerType) // segmentation fault : 11
{
  _subscript = base.subscript
}

override subscript(index: Int) -> providerType.ItemType
{
  return _subscript(index)
}
}

final class AnyDataProvider<providerType : DataProvider>: DataProvider
{
private let box: _AnyDataProviderBox<providerType>

init(_ base: providerType)
{
  self.box = _AnyDataProviderBox(base)
}

subscript(index: Int) -> providerType.ItemType
{
  return box[index]
}
}

Joanna

--
Joanna Carter
Carter Consulting

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Hi Slava

You could also write an explicit closure that loads the subscript:

let fn = { base[$0] }

Thank you so much ! This indeed is the answer and is absolutely logical, I just couldn't see it.

Joanna

···

--
Joanna Carter
Carter Consulting