[swift-evolution] [Review] SE-0081: Move where clause to end of declaration

Karl razielim at gmail.com
Mon May 16 10:04:02 CDT 2016

> internal func _arrayOutOfPlaceReplace
> <B: _ArrayBufferProtocol, C: Collection>
> (_ source: inout B, _ bounds: Range<Int>, _ newValues: C, _ insertCount: Int)
>  where
>  C.Iterator.Element == B.Element,
>  B.Index == Int
> {
> Now only the relatively unimportant details—that the buffer and collection must have elements of the same type, and that the buffer must have integer indices—are at the end, whereas the basic conformances required to make any sense at all of the declaration are still inline.

You see, I’m of the complete opposite opinion - I don’t think those details are “relatively unimportant”; I think they’re absolutely critical.

If you try and call it when your C.Iterator.Element is not equal to B.Element, the function does not exist. You’re talking about some other function in that case, not this one.

Same goes if B.Index is not an Int. If that was an unimportant detail, they would have given ‘bounds’ the type Range<B.Index> and not specified any constraints at all. The function requires the index be an Int - maybe it’s doing some mathematical operations which wouldn’t make sense for a more complex index type, such as DictionaryIndex.

Basically that is it - the ‘where’ clause is a vital part of the function declaration; it defines the specification under which the function exists at all (along with the function name, arguments and return type). If you don’t match every single part of that specification, the type checker won’t match your call to this function - if you don’t meet the constraints, you’re not talking about this function; imagine you have several overloaded function declarations which differ only by ‘where’ condition:

func insert<T>(contentsOf:T) where T:RandomAccessCollection, T.Element == Element
func insert<T>(contentsOf:T) where T:Collection, T.Element == Element
func insert<T>(contentsOf:T) where T:Sequence, T.Element == Element
… etc

the ‘where’ clause isn’t incidental here - it’s the only disambiguating feature between these declarations. I think it’s critical information and shouldn’t be stuffed at the end because you think it’s not important; it is important. If it hinders initial readability of the declaration so much, you can wrap it behind a typealias:

func insert<T: RandomAccessCollectionOf<Element>>(contentsOf: T)
func insert<T: CollectionOf<Element>>(contentsOf: T)
func insert<T: SequenceOf<Element>>(contentsOf: T)
… etc

I think that’s much easier to follow, and attempts to reduces the length and verbosity of the where clauses (i.e. like the fact that Collection’s associated type referring to its element is called ‘Element’; ‘CollectionOf’ encodes an equivalent constraint in less characters). This proposal just feels kind of lazy - we’ll just tack them on the end so we can ignore them a bit more easily, even though they’re still going to be monstrously long and difficult-to-read.

Are there any other languages that do this? Or anything even similar? It seems to me that the context-switching is something that human beings in general are not going to find very legible; like if you insert too many commas in a sentence.

> On 15 May 2016, at 16:05, Brent Royal-Gordon via swift-evolution <swift-evolution at swift.org> wrote:
>> There we are. I read the declaration of the function from beginning to end
>> and gradually formed a rough understanding of it without needing to change
>> my expectations halfway through. I still have doubts about 'insertCount',
>> but I was at least able to formulate an hypothesis about its use.
>> YMMV, but as far as I'm concerned, the original declaration was much easier
>> to understand.
> I actually agree with you for this case, but not *all* type information *has* to be moved to the end. Try this on for size, which is actually still the most natural way to write this declaration in SE-0081:
> This proposal *permits* you to hollow out the generic parameter list to the point of vacuousness, but that doesn't mean it's the right thing to do. It might make sense to ban a direct `X: Foo` requirement unless there was already an `X: Bar` in the generic parameter list. Or we might simply need to paraphrase the Perl manual page: "There are several ways to write a generic requirement, so consider picking the most readable one."
> -- 
> Brent Royal-Gordon
> Architechies
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

More information about the swift-evolution mailing list