> On 1 Dec 2015, at 06:17, Quincey Morris <quinceymor...@rivergatesoftware.com> 
> wrote:
> 
> On Nov 30, 2015, at 04:12 , Roland King <r...@rols.org 
> <mailto:r...@rols.org>> wrote:
>> 
>> I want to say that timeSeries is any TimeSeries with an underlying type of 
>> Float, but you can’t.
> 
> The problem is that this says that you want a generic protocol, and there’s 
> no such thing. Unfortunately, TimeSeries is not (in a sense) non-generic 
> either, because of its associated type requirement.
> 
> I agree that the two types of protocols in the current Swift (conformable 
> protocols and constraint protocols) is Swift’s biggest defect right now. I 
> don’t know if it’s technically feasible (or even makes sense), but I’d love 
> to see those unspecified typealias’s in protocols turn into generic type 
> parameters, so the whole thing just turns into a comprehensible generic 
> system. (Yeah, right.)
> 
> 


TL;DR version - don’t bother reading it, this is just my ramblings partly so I 
can find them later on google and re-read what I wrote

That’s how I feel too - the combination of parameters for Generics and 
associated types for protocols get into conflict in situations like this and 
while generically it’s a hard problem, there are cases in which you could 
express intent and the compiler could write the code, and I hope that comes in 
the next iteration. It’s really easy to get in this mess too. My thinking went, 
“I need a time series, what would one look like, let me make it a protocol with 
methods to add a value, get values, subsequence etc. What do I want it to be a 
timeseries of .. I don’t really care, Floats, Doubles, Bananas, let’s just make 
that an Element". At this point I have now nailed one foot to the floor, I have 
a protocol with an associated type AND Self requirements (the subsequence gives 
you that). 

I do, when I get to this point, understand why what I want to express isn’t 
sufficient, I want to have a time series of floats, I want to type a variable 
as one, perhaps with a syntax like this (which I just made up)

        var series : T:TimeSeries where T.Element == Float

or perhaps putting the protocol constraints in as if they were generic 
parameters, I made this up too, along the lines of Quincey’s ‘typealiases 
turning into generic type parameters'

        var series : TimeSeries<Element == Float>

You think that defines the behaviour of ‘series’ enough for the compiler to 
work with it, and it does, it says what you can *do* with series, that should 
allow you to use ‘series’ in the code, call its methods, mutate its properties, 
but it doesn’t tell you how big it is, is it a struct with 123 bytes of data or 
a class, ie a  pointer. Without knowing what actually implements this protocol, 
the compiler can’t actually build the object which contains it. I understand 
this, although I always understand it after the fact.  

Swift lets you hoist that information up into a description of a generic 
parameter to a type

    public struct UserOfTimeSeriesOfFloat<T:TimeSeries where T.Element == Float>
    {
        var series : T
    }

The compiler similarly knows what a ’T’ can do and what can be called on it and 
what it can return and because the actual type is passed when you make one, the 
compiler knows how big ‘series’ is and can make the concrete type which 
contains it. 

There are cases where the compiler I think could do better. If TimeSeries is a 
class, or if you could specify in the constraint that TimeSeries in this 
instance must be implemented by a class, the compiler knows how big series is, 
it’s a pointer, and any implementation of TimeSeries where the Element is a 
Float which is implemented by a class, works and the type’s size is known. 
UserOfTimeSeriesOfFloat is (I think) fully compilable at that point. That’s a 
restriction I would probably happily accept. 

C++, ugly though it is when you have multiple nested <> and you’ve typedef’ed 
yourself into oblivion, manages to let you express this kind of intent because 
when you do you always end up using a pointer or a reference, so the type 
defines the behaviour you can use, and the pointer/reference defines the 
storage size. 

For anyone still reading, it actually got worse^H^H^H^H^H more interesting. 
TimeSeries is a SequenceType, made sense right, I want to iterate them and I 
love embracing standards. A SequenceType returns a GeneratorType which itself 
generates Elements. In this particular case what you get out of iterating a 
TimeSeries is a TimeSeriesPoint which is a struct { time : Int, value : 
Underlying }, both the full and compressed series implementations return 
Generators which generate those. So I wrote this

        for tick in series { total += tick.value }

and of course it didn’t compile. The error was something like "cannot call 
‘value’ on T.Generator.Element” which stumped me for a while. But indeed, just 
because my two implementations of TimeSeries produced GeneratorTypes who’s 
Elements were TimeSeriesPoints didn’t mean that *any* implementation of 
TimeSeries would make GeneratorTypes which generated those, they could have 
generated series of Underlying, or CGPoints or Giraffes. So I ended up 
specifying that too

    public struct UserOfTimeSeriesOfFloat<T:TimeSeries where T.Element == 
Float, T.Generator.Element == TimeSeriesPoint<Float>>{ .. }

which, to its credit, Swift allows me to write. That let me use the results of 
generate() because the compiler knows what their behaviour is and constrains 
what concrete types I can use for a UserOfTimeSeriesOfFloat<>. 

I wish I’d been able to express that constraint at the protocol definition 
level instead. I would have liked to have been able to write

        protocol TimeSeries : SequenceType where TimeSeries.Generator.Element 
== TimeSeriesPoint<TimeSeries.Underlying>

because that’s really what I actually wanted a TimeSeries to be. I would have 
been happy to impose those requirements at that lower point on every TimeSeries 
implementation because I never really needed one to generate Giraffes. 

I don’t know how much of this is ‘fixable’ because it’s not really broken, it’s 
just different and I don’t know either whether adding more syntactic sugar or 
compiler smarts would make it more or less comprehensible, I do look forward to 
the next WWDC and Swift 3.0 to see if this pretty common situation is addressed 
either by clever language additions or more ‘best practice’ suggestions. 




_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to