Please provide a succinct description of the issue.
I was attempting to index into array-like collections using SRTP and encountered the error using strings. It appears the underlying cause is that the indexer method is not necessarily get_Item and may be overridden using [<IndexerName>]. This is the case in String.cs with the attribute [IndexerName("Chars")] that results in a get_Chars method instead of get_Item.
Provide the steps required to reproduce the problem:
It can be reproduced using FSI
let inline indexInto (slice: ^T when ^T: (member get_Item: int -> ^U)) i : ^U =
slice.get_Item i
let array = [| 1; 2; 3; 4; 5 |] // Ok
let list = ResizeArray<int>(array) // Ok
let str = "abcde"
printfn $"{indexInto array 2}" // Ok
printfn $"{indexInto list 2}" // Ok
printfn $"{indexInto str 2}" // error FS0192: internal error: unknown builtin witness 'get_ItemDynamic'
let inline indexChars (slice: ^T when ^T: (member get_Chars: int -> ^U)) i : ^U =
slice.get_Chars i
printfn $"{indexChars array 2}" // The type 'int array' does not support the operator 'get_Chars'
printfn $"{indexChars str 2}" // Ok
Expected behavior
My initial expectation was that indexInto would allow indexing into any type that had an indexer (using either get_Item or [i]) but after learning about [<IndexerName>] I'm no longer sure if this should be the case. Some suggestions for a resolution:
- Change the compiler's understanding of
member get_Item in SRTP
Make get_Item a compiler-known method that checks for usage of [<IndexerName>] on the target type and inserts the appropriate call.
Despite being "magical" this is probably the expected behavior of most F# developers unaware of the existence of [<IndexerName>].
- Change the error and provide alternate mechanism to combine SRTP and indexers
The error should become "The type 'string' does not support the operator 'get_Item'" rather than "FS0192 internal error" to match other type errors.
Consider some other syntax to allow indexers to be accessed for all types using SRTP:
member []
member Item[]
[<Indexer>] member get_Item
member op_Item
let inline indexInto (slice: ^T when ^T: (member []: int -> ^U)) i : ^U =
slice.[i] // or slice[i]
Known workarounds
- Instead of SRTP, use interfaces to access elements (it's noteworthy that
String doesn't implement IReadOnlyList which would seem appropriate for this case)
- Use
Span which unifies some indexable types but has other usage limitations
- Wrap the string and re-implement the indexer
[<Struct>]
type Wrapper =
| Wrapper of string
member this.Item with get i =
let (Wrapper s) = this
s.[i]
printfn $"{indexInto (Wrapper str) 2}"
Please provide a succinct description of the issue.
I was attempting to index into array-like collections using SRTP and encountered the error using strings. It appears the underlying cause is that the indexer method is not necessarily
get_Itemand may be overridden using[<IndexerName>]. This is the case in String.cs with the attribute[IndexerName("Chars")]that results in aget_Charsmethod instead ofget_Item.Provide the steps required to reproduce the problem:
It can be reproduced using FSI
Expected behavior
My initial expectation was that
indexIntowould allow indexing into any type that had an indexer (using eitherget_Itemor[i]) but after learning about[<IndexerName>]I'm no longer sure if this should be the case. Some suggestions for a resolution:member get_Itemin SRTPMake
get_Itema compiler-known method that checks for usage of[<IndexerName>]on the target type and inserts the appropriate call.Despite being "magical" this is probably the expected behavior of most F# developers unaware of the existence of
[<IndexerName>].The error should become "The type 'string' does not support the operator 'get_Item'" rather than "FS0192 internal error" to match other type errors.
Consider some other syntax to allow indexers to be accessed for all types using SRTP:
member []member Item[][<Indexer>] member get_Itemmember op_ItemKnown workarounds
Stringdoesn't implementIReadOnlyListwhich would seem appropriate for this case)Spanwhich unifies some indexable types but has other usage limitations