<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class="">Here’s a quick review of a strong-“typedef” idea I’ve mentioned here:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Monaco" class="">typecopy MyNewType: OriginalValueType, AnyProtocolsIWant {</font></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Monaco" class="">// Direct member declarations</font></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Monaco" class="">// “publish MemberFromOriginalType” for all overloads (or the singular item for non-functions)</font></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Monaco" class="">// “publish MemberWithSignatureFromOriginalType” to pick out one subset of overloads</font></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Monaco" class="">// “publish MemberWithSignatureAndParameterNamesFromOriginalType” to pick out one overload</font></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Monaco" class="">// “publish ProtocolThatOriginalTypeConfromsTo"</font></div></blockquote></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Monaco" class="">}</font></div></blockquote><div class=""><br class=""></div><div class="">(The name “typecopy” is changed from “alter”.)</div><div class=""><br class=""></div><div class="">All type-copies automatically conform to the new system AnyTypeCopy protocol, which derives from RawRepresentable. It just adds the “CoreRawValue” type. This type alias matches RawValue if that is a non-typecopy; otherwise it aliases that type copy’s CoreRawValue type. AnyTypeCopy cannot be added to non-typecopy types. Any protocol that derives from it can only be applied to typecopy types. Type-copies are value types, and can only shadow structures, enumerations, other type-copies, tuples, and fixed-size arrays (if added).</div><div class=""><br class=""></div><div class="">The initializer used to conform to RawRepresentable is the type’s designated initializer. It’s the only one that can access “super.” Any other initializers added must be convenience and reference the designated one. (Published initializers are considered convenience.) The designated initializer can be fail-able to model subtypes. The designated initializer can pass on an altered value to model quotient types (or any other crazy mapping scheme); including being fail-able too (i.e. a quotient type of a subtype).</div><div class=""><br class=""></div><div class="">Of course, the designated initializer could do neither changes nor filtering:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Monaco" class="">typecopy MyResourceID: Int16, Hashable {</font></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Monaco" class="">init(rawValue: RawValue) { super = rawValue }</font></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Monaco" class="">publish Equatable</font></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Monaco" class="">var hashValue: Int { get {return rawValue.hashValue & 0x01} }</font></div></blockquote></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Monaco" class="">}</font></div></blockquote><div class=""><br class=""></div><div class="">Since every valid state of Int16 is also a valid state of MyResourceID, and without remapping, this type-copy is a trivial copy of its source. Besides downcasts (and cross-casts) never being fail-able, all sorts of other type-punning and related optimizations should be possible. (Upcasts are always trivial, even when the designated initializer isn’t.) We should be able to easily copy/type-pun between Array<MyResourceID> with Array<T>, where T is either Int16 or another type-copy that (eventually) trivially shadows Int16. (Of course, this applies to Unsafe*Pointer or fixed-size arrays (if added) too.) These optimizations can’t be done with non-trivial type copies, since downcasts (and the downcast parts of cross-casts) need to have their designated initializers called for each element.</div><div class=""><br class=""></div><div class="">1. Now we get to the question in the Subject. Before now, I just wanted the compiler to see the definition of the designated initializer to determine if the type-copy is trivial or not. Now I realize that may have problems. One is that it may not be easy for the compiler to check if a given initializer matches the form I gave in the “MyResourceID” example. Another is that if the user prints out a prototype summary of the type, with members but without their definitions, s/he would have no idea if the type-copy was trivial or not.</div><div class=""><br class=""></div><div class="">I’m wondering if we should define trivial-ness with a keyword added to the definition:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Monaco" class="">typecopy MyResourceID1 trivial: Int16, Hashable {</font></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Monaco" class="">// Initializer not given</font></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Monaco" class="">publish Equatable</font></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Monaco" class="">var hashValue: Int { get{return rawValue.hashValue & 0x01} }</font></div></blockquote></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Monaco" class="">}</font></div><div class=""><font face="Monaco" class=""><br class=""></font></div><div class=""><font face="Monaco" class="">typecopy MyResourceID2: Int16, Hashable {</font></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Monaco" class="">trivial init(rawValue: RawValue) // Looks incomplete, but it’s actually the full thing</font></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Monaco" class="">publish Equatable</font></div></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Monaco" class="">var hashValue: Int { get{return rawValue.hashValue & 0x01} }</font></div></div></blockquote></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Monaco" class="">}</font></div></div><div class=""><font face="Monaco" class=""><br class=""></font></div><div class=""><div class=""><font face="Monaco" class="">typecopy MyResourceID3: Int16, Hashable {</font></div></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Monaco" class="">init(rawValue: RawValue) = trivial</font></div></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><div class=""><font face="Monaco" class="">publish Equatable</font></div></div></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Monaco" class="">var hashValue: Int { get{return rawValue.hashValue & 0x01} }</font></div></div></blockquote></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Monaco" class="">}</font></div></div></blockquote><div class=""><br class=""></div><div class="">I kind-of like the look of the second, but it may be confusing to (new) users since there’s no code block after the initializer declaration. My next-liked look is the first one, but I’m not sure where the “trivial” should go (before “typecopy”, after it, current spot, or before the original type’s name after the colon). The third choice looks the weirdest to me, but it’s probably the easiest parsing-wise. It does remind me of the C++ class built-in life-management overrides.</div><div class=""><br class=""></div><div class="">(Now completing the post, maybe option 3 isn’t the easiest to parse. We go from “init” then Code-Block to “init” then either Code-Block or “= trivial”.)</div><div class=""><br class=""></div><div class="">For actual use, I’m leaning on placing “trivial” right before the original type’s name but after the colon. What does everyone else think?</div><div class=""><br class=""></div><div class="">1a. If “trivial” is added to the “typecopy” line, should explicitly defining a designated initializer anyway be banned? I’m leaning towards yes.</div><div class=""><br class=""></div><div class="">2. If no initializers are declared, either directly or with a publish, then a designated initializer is automatically added. It would have the same form as the one I gave in the example. If “trivial” goes inside the initializer’s declaration instead of the “typecopy” line, then the initializer is declared trivial (if possible). If no direct initializers are given, but at least one is added through a “publish,” should an automatic designated initializer still be synthesized, or should the user be forced to declare one?</div><div class=""><br class=""></div><div class="">If we’re going to use “trivial” on the “typecopy” line and ban explicitly defining a designated initializer anyway, then the user shouldn’t (and can’t(!)) be forced to declare one. Otherwise, I think the user should be forced to manually declare the designated initializer if any others are either published or directly declared. It would get weird in one case: if there are no initializers directly declared or published, a protocol is published, and then that protocol is changed to add an initializer; suddenly the user would have to ensure a designated initializer in their code.</div><div class=""><br class=""></div><div class="">3. I finished all of the preceding text, and realized a new problem. There’s no way to determine if a given type-copy is trivial in code, in a meta-programming way. If there’s a way for a derived protocol to restrict how its parent’s members are expressed, then we could define a AnyTrivialTypeCopy as a sub-protocol, but only if we can update the “init?(rawValue: RawValue)” to always be “init(rawValue: RawValue)”. (AnyTrivialTypeCopy would be automatically added to type-copy types that are trivial. It can be manually added to parameters or protocols, but not types unless they already qualify.) Or we could have an “isTrivial” type-level constant Bool property. A separate type-traits helper, like the one for memory layout? Other ideas?</div><div class=""><br class=""></div><div class="">
<div style="color: rgb(0, 0, 0); letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">— </div><div class="">Daryle Walker<br class="">Mac, Internet, and Video Game Junkie<br class="">darylew AT mac DOT com </div></div>
</div>
<br class=""></body></html>