swiftlang / swiftlang/swift-corelibs-libdispatch

[SR-7868] Data and DispatchData have subtly different signatures for enumerateBytes

Open
#652 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug Foundation libdispatch
Dominant language
C
Stars
2.6k
Forks
496
Avg merge
2d 6h
Merged PRs (30d)
3

Description

Previous ID SR-7868
Radar rdar://problem/40775762
Original Reporter @Lukasa
Type Bug
Environment

Swift 4.2 beta

Additional Detail from JIRA
Votes 0
Component/s Foundation, libdispatch
Labels Bug
Assignee None
Priority Medium

md5: 7f82935997669109761a47ee765077b8

Issue Description:

While attempting to write a protocol for both Data and DispatchData that covers their shared `enumerateBytes` method, I discovered that it is not really possible to do that. Consider the following example program:

import struct Foundation.Data
import struct Dispatch.DispatchData

protocol ByteEnumerator: Collection {
    func enumerateBytes(block: (UnsafeBufferPointer<UInt8>, Self.Index, inout Bool) -> Void)
}

extension Data: ByteEnumerator { }
extension DispatchData: ByteEnumerator { }

This does not compile, because Data has no label on its block:

test.swift:8:1: error: method 'enumerateBytes' has different argument labels from those required by protocol 'ByteEnumerator' ('enumerateBytes(block:)')
extension Data: ByteEnumerator { }
^
Foundation.Data:40:17: note: 'enumerateBytes' declared here
    public func enumerateBytes(_ block: (UnsafeBufferPointer<UInt8>, Data.Index, inout Bool) -> Void)
                ^
test.swift:5:10: note: requirement 'enumerateBytes(block:)' declared here
    func enumerateBytes(block: (UnsafeBufferPointer<UInt8>, Self.Index, inout Bool) -> Void)

If you try to suppress the label by changing the protocol method from func enumerateBytes(block: (UnsafeBufferPointer<UInt8>, Self.Index, inout Bool) -> Void) to func enumerateBytes(_ block: (UnsafeBufferPointer<UInt8>, Self.Index, inout Bool) -> Void), this will again fail to compile, this time because of DispatchData:

test.swift:9:1: error: method 'enumerateBytes(block:)' has different argument labels from those required by protocol 'ByteEnumerator' ('enumerateBytes')
extension DispatchData: ByteEnumerator { }
^
Dispatch.DispatchData:19:17: note: 'enumerateBytes(block:)' declared here
    public func enumerateBytes(block: (UnsafeBufferPointer<UInt8>, Int, inout Bool) -> Void)
                ^
test.swift:5:10: note: requirement 'enumerateBytes' declared here
    func enumerateBytes(_ block: (UnsafeBufferPointer<UInt8>, Self.Index, inout Bool) -> Void)

Given that these two data types can be bridged on Darwin, but not Linux, this inconsistency should probably be remedied.

(As a post-script, a tempting approach to bridge over this would be for my protocol to provide a default implementation for one case in terms of the other. However, because of the tail-closure syntax, doing this would cause an enormous number of compile errors.)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating the Data and DispatchData enumerateBytes declarations referenced in the compiler diagnostics, then compare their argument labels and closure signatures. Reproduce the protocol examples with the stated Swift 4.2 behavior and determine a consistent API shape; the issue is done when both types can satisfy the same protocol without label-related compilation errors.

Written by the indexing model from the issue text.

Assessment

Tech stack
swift
Domain
api
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.