Regards
(From mobile)

> On May 16, 2016, at 8:16 PM, Thorsten Seitz via swift-evolution 
> <[email protected]> wrote:
> 
> 
>>> Am 16.05.2016 um 17:04 schrieb Karl via swift-evolution 
>>> <[email protected]>:
>>> 
>>> 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
> 
> Either you have the constraints first and the parameter list last or the 
> other way around. Fact is that *both* decide whether it is the function you 
> need.
> So just their order cannot help with that.
> I would still argue that the proposed version is more readable: just look at 
> your example above where the first part up to the where is identical at one 
> glance, so that the disambiguating part stands out whereas your other example 
> looks much more unstructured because of the different lengths of the generic 
> type list which makes the congruence of the parameter lists difficult to see 
> because they do not align anymore.
> 
>> 
>> 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.
> 
> The typealias idea can be combined with the where clause at the end:
> 
> func insert<T>(contentsOf:T) where T:RandomAccessCollectionOf<Element>
> func insert<T>(contentsOf:T) where T:CollectionOf<Element>
> func insert<T>(contentsOf:T) where T:SequenceOf<Element>
> 
> Much easier to discern (at least IMO) because everything is aligned.
> 
>> 
>> 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.
> 
> Yes, Ceylon places all constraints (it only knows inheritance constraints) at 
> the end:
> 
> shared Value sum<Value>({Value+} values) 
>         given Value satisfies Summable<Value> { ... }
> shared <Key->Item>[] zip<Key,Item>({Key*} keys, {Item*} items)
>         given Key satisfies Object
>         given Item satisfies Object { ... }
> 
> It does the same for type definitions:
> shared class Singleton<out Element>(Element element)
>         extends Object()
>         satisfies [Element+]
>         given Element satisfies Object { ... }
> 

This confirms my impression that WHERE does not fit as well at the end as if 
the information was inlined. WITH is my preferred replacement, which IMO has a 
similar connotation as ceylon's GIVEN.


> 
>> 
>>>> On 15 May 2016, at 16:05, Brent Royal-Gordon via swift-evolution 
>>>> <[email protected]> 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
>>> [email protected]
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> [email protected]
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to