TBH, I think you're trying to solve this problem in a very complicated way. What you're describing screams out for its own value subtype with let variables and an initializer that will provide defaults. I'm skeptical such a complicated design as you propose is necessary to achieve what you want.<br><br><div class="gmail_quote"><div dir="ltr">On Tue, Dec 27, 2016 at 05:25 Adrian Zubarev via swift-evolution <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class="gmail_msg"><div class="m_-8810590392941529495bloop_markdown gmail_msg"><p class="gmail_msg">Okay now I see your point there. :) Thank you Xiaodi and Tony.</p>
<hr class="gmail_msg">
<p class="gmail_msg">It’s an interesting approach you have there, but I see another problem with <code class="gmail_msg">Self</code> and <code class="gmail_msg">- ProtocolName</code>. <code class="gmail_msg">Self</code> does not refer to the current type returned from the protocol member. SE–0068 might help there, but as soon we’re working with non-final classes it will be problematic again.</p>
<p class="gmail_msg">That means something like this will be possible <code class="gmail_msg">constraint.x(1).y(1).x(2)</code>, which by solving the main problem of this topic we’d like to avoid.</p>
<p class="gmail_msg">We’d need a way to subtract a protocol from the returned type + the ability of keeping <code class="gmail_msg">T</code> only members.</p>
<p class="gmail_msg">As for <code class="gmail_msg">T : P1 & P2 & P3</code>, <code class="gmail_msg">T - P1</code> should return <code class="gmail_msg">T + P2 & P3</code>, because it’s what the user would logically assume there. The next chain needs to remember <code class="gmail_msg">- P1</code> on that path, so the result for the followed reduction of <code class="gmail_msg">- P3</code> would be equivalent to <code class="gmail_msg">T - P1 & P3</code> = <code class="gmail_msg">T + P2</code>.</p>
<p class="gmail_msg">As you already mentioned, one would assume that we might be able to cast back to <code class="gmail_msg">T</code> from <code class="gmail_msg">T - P1 & P3</code>. I think this leads us to the right direction where we should realize that we should escape from <code class="gmail_msg">T</code> in general. That means that the return type should somehow create a new subtraction type, which can be reduced further by member chaining or escaped similar to what I wrote in the original post.</p>
<p class="gmail_msg">We’d need a new type or keyword that refers to the current (reduced) type. Let’s call it <code class="gmail_msg">Current</code> instead of <code class="gmail_msg">Self</code>. Furthermore we’d need a concrete result type, to be able to pass the result value around. Let’s call the latter type <code class="gmail_msg">Subtraction<T></code>.</p>
<pre class="gmail_msg"><code class="m_-8810590392941529495swift gmail_msg">protocol WidthConstrainable {
func width(_ v: CGFloat) -> Subtraction<Current – WidthConstrainable>
}
protocol HeightConstrainable {
func height(_ v: CGFloat) -> Subtraction<Current – HeightConstrainable>
}
protocol XConstrainable {
func x(_ v: CGFloat) -> Subtraction<Current – XConstrainable>
}
protocol YConstrainable {
func y(_ v: CGFloat) -> Subtraction<Current – YConstrainable>
}
struct Constraint: WidthConstrainable, HeightConstrainable, XConstrainable, YConstrainable {
...
}
</code></pre>
<p class="gmail_msg"><code class="gmail_msg">Subtraction<T></code> could be a similar type, like we’re proposing to change the metatypes from <code class="gmail_msg">T.Type/Protocol</code> to <code class="gmail_msg">Type<T></code> and <code class="gmail_msg">AnyType<T></code>. That means that it would know all the members of <code class="gmail_msg">Current</code> without the subtrahend. Each further member chain would create ether a nested <code class="gmail_msg">Subtraction<Subtraction<T - P1> - P2></code> or a flattened type like <code class="gmail_msg">Subtraction<T - P1 & P2></code>.</p>
<pre class="gmail_msg"><code class="m_-8810590392941529495swift gmail_msg">let constraint = Constraint()
let a: Subtraction<Constraint - XConstrainable> = constraint.x(1)
let b: Subtraction<Subtraction<Constraint - XConstrainable> - YConstrainable> = a.y(2)
let c: Subtraction<Subtraction<Subtraction<Constraint - XConstrainable> - YConstrainable> - WidthConstrainable> = b.width(100)
_ = constraint.x(1).y(2).width(100)
</code></pre>
<p class="gmail_msg">That way we could even remove the new <code class="gmail_msg">-</code> operator and use generics parameter list instead. Maybe instead of <code class="gmail_msg">Subtraction</code> we could call the new type <code class="gmail_msg">Difference<T></code></p>
<pre class="gmail_msg"><code class="m_-8810590392941529495swift gmail_msg">type Difference<Minuend, Subtrahend> : Minuend - Subtrahend { … } // should know everything `Minuend` has, but exclude everything from `Subtrahend`
struct Constraint: WidthConstrainable, HeightConstrainable, XConstrainable, YConstrainable {
func width(_ v: CGFloat) -> Difference<Current, WidthConstrainable> {
var copy = self
copy.width = v
return Difference(copy)
}
func height(_ v: CGFloat) -> Difference<Current, HeightConstrainable> { … }
func x(_ v: CGFloat) -> Difference<Current, XConstrainable> { … }
func y(_ v: CGFloat) -> Difference<Current, YConstrainable> { … }
}
</code></pre>
<p class="gmail_msg">What do you guys think about this approach? :)</p>
<p class="gmail_msg"></p></div><div class="m_-8810590392941529495bloop_original_html gmail_msg"></div></div><div style="word-wrap:break-word" class="gmail_msg"><div class="m_-8810590392941529495bloop_original_html gmail_msg"><div id="m_-8810590392941529495bloop_customfont" style="font-family:Helvetica,Arial;font-size:13px;color:rgba(0,0,0,1.0);margin:0px;line-height:auto" class="gmail_msg"><br class="gmail_msg"></div> <br class="gmail_msg"> <div id="m_-8810590392941529495bloop_sign_1482828564757652992" class="m_-8810590392941529495bloop_sign gmail_msg"><div style="font-family:helvetica,arial;font-size:13px" class="gmail_msg">-- <br class="gmail_msg">Adrian Zubarev<br class="gmail_msg">Sent with Airmail</div></div> <br class="gmail_msg"></div></div><div style="word-wrap:break-word" class="gmail_msg"><div class="m_-8810590392941529495bloop_original_html gmail_msg"><p class="m_-8810590392941529495airmail_on gmail_msg">Am 26. Dezember 2016 um 17:17:29, Tony Allevato (<a href="mailto:allevato@google.com" class="gmail_msg" target="_blank">allevato@google.com</a>) schrieb:</p> <blockquote type="cite" class="m_-8810590392941529495clean_bq gmail_msg"><span class="gmail_msg"><div class="gmail_msg"><div class="gmail_msg"></div><div class="gmail_msg">
<div dir="ltr" class="gmail_msg">Xiaodi's point is really important—being able to
express the notions simultaneously that "T has method a()" and "T
does not have method a()" would break the type system.
<div class="gmail_msg"><br class="gmail_msg"></div>
<div class="gmail_msg">Instead of focusing on the proposed syntax, let's consider the
problem you're trying to solve. It sounds like what you're asking
for could be expressed more cleanly with a richer protocol algebra
that supported subtraction. It wouldn't be quite as automatic as
what you propose, but it would feel like a more natural extension
of the type system if you could do something like below, and would
avoid combinatorial explosion of protocol types (you go from O(n!)
to O(n) things you actually have to define concretely):</div>
<div class="gmail_msg"><br class="gmail_msg"></div>
<div class="gmail_msg">```</div>
<div class="gmail_msg">protocol WidthConstrainable {</div>
<div class="gmail_msg"> func width(_ v: CGFloat) -> Self –
WidthConstrainable</div>
<div class="gmail_msg">}</div>
<div class="gmail_msg">protocol HeightConstrainable {</div>
<div class="gmail_msg"> func height(_ v: CGFloat) -> Self –
HeightConstrainable</div>
<div class="gmail_msg">}</div>
<div class="gmail_msg">protocol XConstrainable {</div>
<div class="gmail_msg"> func x(_ v: CGFloat) -> Self – XConstrainable</div>
<div class="gmail_msg">}</div>
<div class="gmail_msg">protocol YConstrainable {</div>
<div class="gmail_msg"> func y(_ v: CGFloat) -> Self – YConstrainable</div>
<div class="gmail_msg">}</div>
<div class="gmail_msg">struct Constraint: WidthConstrainable, HeightConstrainable,
XConstrainable, YConstrainable {</div>
<div class="gmail_msg"> ...</div>
<div class="gmail_msg">}</div>
<div class="gmail_msg">```</div>
<div class="gmail_msg"><br class="gmail_msg"></div>
<div class="gmail_msg">If a type X is just a union or protocols (for example, X:
WidthConstrainable & HeightConstrainable & XConstrainable
& YConstrainable), the subtraction (X – something) is easy to
define. It's either valid if the subtrahend is present in the set,
or it's invalid (and detectable at compile time) if it's not.</div>
<div class="gmail_msg"><br class="gmail_msg"></div>
<div class="gmail_msg">But there are still some rough edges: what does it mean when a
concrete type is involved? Let's say you have T: P1 & P2 &
P3, and you write (T – P1). That could give you a type that
contains all the members of T except those in P1, which would be
the members in P2, P3, and any that are defined directly on T that
do not come from protocol conformances.</div>
<div class="gmail_msg"><br class="gmail_msg"></div>
<div class="gmail_msg">But what is the relationship between types T and (T – P1)? (T
– P1) being a supertype of T seems fairly straightforward—any
instance of T can be expressed as (T – P1). But if I have an
instance of type (T – P1), should I be able to cast that back to T?
On the one hand, why not? I can obviously only get (T – P1) by
starting with T at some point, so any instance of (T – P1) must
*also* be an instance of T. So that implies that T is a supertype
of (T – P1). In other words, they're supertypes of each other,
without being the same type? That would be a first in Swift's type
system, I believe. And if we allow the cast previously mentioned,
that effectively circumvents the goal you're trying to achieve. (We
could argue that you'd have to use a force-cast (as!) in this
case.)</div>
<div class="gmail_msg"><br class="gmail_msg"></div>
<div class="gmail_msg">This could be worked around by forbidding subtraction from
concrete types and reducing T to the union of its protocols before
performing the subtraction. In that case, (T – P1) would equal P2
& P3. But that relationship is still a little wonky: in that
case, (T – P1) would also not contain any members that are only
defined on T, even though the expression (T – P1) implies that they
should. You would have to make that reduction explicit somehow in
order for that to not surprise users (require writing something
like `#protocols(of: T) – P1`?), and it leaves a certain subset of
possible type expressions (anything that wants members defined on T
without members of a protocol) unexpressible.</div>
<div class="gmail_msg"><br class="gmail_msg"></div>
<div class="gmail_msg">I actually glossed over this earlier by writing "..." in the
struct body. If I defined `width(_:)` there, what would my return
type be? We currently forbid `Self` in that context. Would `Self –
WidthConstrainable` be allowed? Would I have to use the new
protocol-reduction operator above? More details that would have to
be worked out.</div>
<div class="gmail_msg"><br class="gmail_msg"></div>
<div class="gmail_msg">Protocol inheritance would pose similar questions. If you have
this:</div>
<div class="gmail_msg"><br class="gmail_msg"></div>
<div class="gmail_msg">```</div>
<div class="gmail_msg">protocol P1 {}</div>
<div class="gmail_msg">protocol P2: P1 {}</div>
<div class="gmail_msg">```</div>
<div class="gmail_msg"><br class="gmail_msg"></div>
<div class="gmail_msg">What is the subtype/supertype relationship between P2 and (P2
– P1)? It's the same situation we had with a concrete type. Maybe
you just can't subtract a super-protocol without also subtracting
its lowest sub-protocol from the type?</div>
<div class="gmail_msg"><br class="gmail_msg"></div>
<div class="gmail_msg">My PL type theory knowledge isn't the deepest by any means,
but if something like this was workable, I think it would be more
feasible and more expressive than the member permutation approach.
And that being said, this is probably a fairly narrow use case that
wouldn't warrant the complexity it would bring to the type system
to make it work.</div>
<div class="gmail_msg"><br class="gmail_msg"></div>
</div>
<br class="gmail_msg">
<div class="gmail_quote gmail_msg">
<div dir="ltr" class="gmail_msg">On Mon, Dec 26, 2016 at 7:03 AM Xiaodi Wu via
swift-evolution <<a href="mailto:swift-evolution@swift.org" class="gmail_msg" target="_blank">swift-evolution@swift.org</a>>
wrote:<br class="gmail_msg"></div>
<blockquote class="gmail_quote gmail_msg" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Should the following compile?<br class="gmail_msg">
<br class="gmail_msg">
let bar = foo.a()<br class="gmail_msg">
func f(_ g: T) {<br class="gmail_msg">
_ = g.a()<br class="gmail_msg">
}<br class="gmail_msg">
f(bar)<br class="gmail_msg">
<br class="gmail_msg">
If so, your proposal cannot guarantee each method is called only
once. If not, how can bar be of type T?<br class="gmail_msg">
<br class="gmail_msg">
<div class="gmail_quote gmail_msg">
<div dir="ltr" class="gmail_msg">On Mon, Dec 26, 2016 at 06:30
Adrian Zubarev <<a href="mailto:adrian.zubarev@devandartist.com" class="gmail_msg" target="_blank">adrian.zubarev@devandartist.com</a>> wrote:<br class="gmail_msg"></div>
<blockquote class="gmail_quote gmail_msg" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div style="word-wrap:break-word" class="gmail_msg">
<div class="m_-8810590392941529495m_-3067540519206532711m_2486499801731300355bloop_markdown gmail_msg">
<p class="gmail_msg">I think I revise what I said about value
semantics in my last post.</p>
<pre class="gmail_msg"><code class="m_-8810590392941529495m_-3067540519206532711m_2486499801731300355swift gmail_msg">let chain: T = foo.a()
let new = chain
new. // should not see `a` here
</code></pre>
<p class="gmail_msg">It’s more something like a local scoped chain.
I’m not sure how to call it correctly here. I’m not a native
English speaker. =)</p>
<p class="gmail_msg"></p>
</div>
<div class="m_-8810590392941529495m_-3067540519206532711m_2486499801731300355bloop_original_html gmail_msg">
</div>
</div>
<div style="word-wrap:break-word" class="gmail_msg">
<div class="m_-8810590392941529495m_-3067540519206532711m_2486499801731300355bloop_original_html gmail_msg">
<div id="m_-8810590392941529495m_-3067540519206532711m_2486499801731300355bloop_customfont" style="font-family:Helvetica,Arial;font-size:13px;color:rgba(0,0,0,1.0);margin:0px;line-height:auto" class="gmail_msg"><br class="gmail_msg"></div>
<br class="gmail_msg">
<div id="m_-8810590392941529495m_-3067540519206532711m_2486499801731300355bloop_sign_1482751593527631872" class="m_-8810590392941529495m_-3067540519206532711m_2486499801731300355bloop_sign gmail_msg">
<div style="font-family:helvetica,arial;font-size:13px" class="gmail_msg">-- <br class="gmail_msg">
Adrian Zubarev<br class="gmail_msg">
Sent with Airmail</div>
</div>
<br class="gmail_msg"></div>
</div>
<div style="word-wrap:break-word" class="gmail_msg">
<div class="m_-8810590392941529495m_-3067540519206532711m_2486499801731300355bloop_original_html gmail_msg">
<p class="m_-8810590392941529495m_-3067540519206532711m_2486499801731300355airmail_on gmail_msg">
Am 26. Dezember 2016 um 12:11:23, Adrian Zubarev (<a href="mailto:adrian.zubarev@devandartist.com" class="gmail_msg" target="_blank">adrian.zubarev@devandartist.com</a>) schrieb:</p>
<blockquote type="cite" class="m_-8810590392941529495m_-3067540519206532711m_2486499801731300355clean_bq gmail_msg">
<div style="word-wrap:break-word" class="gmail_msg">
<div class="gmail_msg"></div>
<div class="gmail_msg">
<div class="m_-8810590392941529495m_-3067540519206532711m_2486499801731300355bloop_markdown gmail_msg">
<p class="gmail_msg"><span class="gmail_msg">By ‘calling once’ I
meant, calling once at a single permutation chain. If the chain is
escaped or followed by a non-permuting member that returns the same
protocol, you’d have the ability to use all members at the starting
point of the new chain.</span></p>
<pre class="gmail_msg"><span class="gmail_msg"><code class="m_-8810590392941529495m_-3067540519206532711m_2486499801731300355swift gmail_msg">permuting protocol T {
func a()
func b()
func c()
func d()
}
var foo: T = …
func boo(_ val: T) -> U {
// Here val escapes the chain and creates a new one
// That means that you can create a local permutation chain here again
val.a() // we can use `a` here
return …
}
boo(foo.a()) // a is immediately invoked here
</code></span></pre>
<p class="gmail_msg"><span class="gmail_msg">I imagine this keyword
to follow value semantics, so that any possible mutation is handled
locally with a nice extra ability of permutation member
chaining.</span></p>
<p class="gmail_msg"><span class="gmail_msg">Did I understood your
point correctly here?</span></p>
<hr class="gmail_msg">
<p class="gmail_msg"><span class="gmail_msg">Sure the idea needs to
be more fleshed out, but I’m curious if that’s something that we
might see in Swift one day. :)</span></p>
</div>
<div class="m_-8810590392941529495m_-3067540519206532711m_2486499801731300355bloop_original_html gmail_msg">
<div id="m_-8810590392941529495m_-3067540519206532711m_2486499801731300355bloop_customfont" style="font-family:Helvetica,Arial;font-size:13px;color:rgba(0,0,0,1.0);margin:0px;line-height:auto" class="gmail_msg"><span class="gmail_msg"><br class="gmail_msg"></span></div>
<span class="gmail_msg"><br class="gmail_msg"></span>
<div id="m_-8810590392941529495m_-3067540519206532711m_2486499801731300355bloop_sign_1482749838336907008" class="m_-8810590392941529495m_-3067540519206532711m_2486499801731300355bloop_sign gmail_msg">
<div style="font-family:helvetica,arial;font-size:13px" class="gmail_msg"><span class="gmail_msg">-- <br class="gmail_msg">
Adrian Zubarev<br class="gmail_msg">
Sent with Airmail</span></div>
</div>
<span class="gmail_msg"><br class="gmail_msg"></span>
<p class="m_-8810590392941529495m_-3067540519206532711m_2486499801731300355airmail_on gmail_msg">
<span class="gmail_msg">Am 26. Dezember 2016 um 11:50:50, Xiaodi Wu
(<a href="mailto:xiaodi.wu@gmail.com" class="gmail_msg" target="_blank">xiaodi.wu@gmail.com</a>) schrieb:</span></p>
<blockquote type="cite" class="m_-8810590392941529495m_-3067540519206532711m_2486499801731300355clean_bq gmail_msg">
<div class="gmail_msg"><span class="gmail_msg"><span class="gmail_msg"><span style="color:rgb(0,0,0);font-family:'helvetica Neue',helvetica;font-size:14px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);display:inline!important;float:none" class="gmail_msg">Given `foo: T` and methods a(), b(), c(), d(),
each of which can only be called once, how can the return value of
these methods be represented in the type system?</span><br style="color:rgb(0,0,0);font-family:'helvetica Neue',helvetica;font-size:14px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class="gmail_msg">
<br style="color:rgb(0,0,0);font-family:'helvetica Neue',helvetica;font-size:14px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class="gmail_msg">
<span style="color:rgb(0,0,0);font-family:'helvetica Neue',helvetica;font-size:14px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);display:inline!important;float:none" class="gmail_msg">That is, if `foo.a()` can be passed as an
argument to an arbitrary function of type `(T) -> U`, either the
function cannot immediately invoke a(), in which case foo is not of
type T, or it can immediately invoke a(), in which case your
keyword does not work.</span></span></span></div>
</blockquote>
</div>
<div class="m_-8810590392941529495m_-3067540519206532711m_2486499801731300355bloop_markdown gmail_msg">
</div>
</div>
</div>
</blockquote>
</div>
</div>
</blockquote>
</div>
_______________________________________________<br class="gmail_msg">
swift-evolution mailing list<br class="gmail_msg">
<a href="mailto:swift-evolution@swift.org" class="gmail_msg" target="_blank">swift-evolution@swift.org</a><br class="gmail_msg">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" class="gmail_msg" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="gmail_msg">
</blockquote>
</div>
</div></div></span></blockquote></div></div>_______________________________________________<br class="gmail_msg">
swift-evolution mailing list<br class="gmail_msg">
<a href="mailto:swift-evolution@swift.org" class="gmail_msg" target="_blank">swift-evolution@swift.org</a><br class="gmail_msg">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" class="gmail_msg" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="gmail_msg">
</blockquote></div>