Good morning everyone. Welcome to our discussion Brent.
There is nothing bad about Type<T> being a final class. To be honest I played
with the idea of Type<T> being a class for optimization purposes, because it
does feel like a performance drop if we had to instantiate tons of the same
types (which may or may not be really heavy):
func dynamicType<T>(_ instance: T) -> Type<T>
let someHeavyViewController = …
dynamicType(someHeavyViewController)
dynamicType(someHeavyViewController)
dynamicType(someHeavyViewController)
dynamicType(someHeavyViewController)
dynamicType(someHeavyViewController)
With structs we would do the heavy work over and over again which can decrease
our performance.
The reason why I dropped the class was because I though someone might subclass
it, and I totally forgot about final.
If we had public final class Type<T> we can optimize the above example and
return a reference to the specific Type<T> we already instantiated once.
Bikeshedding:
internal var _typeStore: [Int: Type<Any>] = [:]
extension Type {
internal static var sharedInstance: Type<T> {
let identifier = _uniqueIdentifierOf(Type<T>.metatype)
if let typeReference = Type<T>(casting: _typeStore[identifier]) {
return typeReference
}
let newType = Type<T>()
// downcast `T` to `Any` but still store `T` in `_underlyingMetatype`
if let downcastedType = Type<Any>(casting: newType) {
_typeStore[identifier] = downcastedType
}
return newType
}
}
Now we can use Type<T>.sharedInstance to instantiate it or just to return an
existing instance.
I did some tweaking to the Type<T> api to make this work. I also filed a bug
SR–2085 where Metatype<T> does not behave like T.Type which is strange.
Furthermore the api uses a workaround T.Metatype (renamed T.Type).
init?(casting: Type<T>?) is now optional, to make sharedInstance work with the
dictionary. This change doesn’t hurt at all.
I also implemented a check if T is Any to make downcasting to Any work as
expected (T.self is Any.Type is the wrong way to go, because it’s always true
no matter what). Took me a few hours to debug and fix these strange bugs.
You can check the (not compiling) gist here:
https://gist.github.com/DevAndArtist/a5744f21107812b2d4e6baee2c55e0bf.
If anyone want me to implement a version that does compile, just let me know.
It’s already possible, but I’ll have to use .self, .Type instead of .metatype
and Metatype<T>.
--
Adrian Zubarev
Sent with Airmail
Am 15. Juli 2016 um 08:25:40, Brent Royal-Gordon ([email protected])
schrieb:
> On Jul 14, 2016, at 6:33 PM, Anton Zhilin <[email protected]> wrote:
>
> And such a feature would look odd on a struct.
But why would it be a struct? Types are obvious candidates to have identities;
the type is the same "thing" everywhere it's referred to. Types don't have
value semantics; if you perform a mutating operation on a type, that mutation
is visible everywhere. Types (at least class types) have subtype relationships;
structs can't express those.
I like the `Type<>` syntax, especially if it's something that could at least
partially be written in the standard library (how nice would it be if we had
`final class Type<Describing>` in the generated headers?), and I really like
the idea of extending a metatype to conform to a protocol. But a lot of what's
being discussed here, I just don't get. What's the benefit of switching to
structs? Of removing type members?
> I don't see any problems with Type<Type<T>>. There is finite number of types
> that are used in the program, and compiler can collect and store information
> about them all statically. Am I right?
Maybe not:
func recursivelyPrint<T>(type: T.Type, depth: Int) {
print(type)
guard depth > 0 else { return }
recursivelyPrint(type: type.dynamicType, depth: depth - 1)
}
recursivelyPrint(type: Int.self, depth: 5)
--
Brent Royal-Gordon
Architechies
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution