-
Notifications
You must be signed in to change notification settings - Fork 82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Variant Refactor #199
Variant Refactor #199
Conversation
Hold off on reviewing/merging this please, I have a couple more improvements that address the compromises above. |
# Conflicts: # Sources/SimpleExtension/Demo.swift # Sources/SwiftGodot/Core/SignalRegistration.swift
Ok, this is in better shape now, it no longer messes up |
My initial take is that I like this patch very much. I would love if you could review the existing documentation in SwiftGodot/Sources/SwiftGodot/SwiftGodot.docc/Variants.md as part of this PR, to make sure they do not contradict each other. |
Thanks — I reviewed these and the other two spots you mentioned. Please take another look when you have a chance. |
Thank you for your contribution! |
One question: how does this pass a subclass of Wrapper/Object to a Variant? |
Ok, figured that out - but it does not seem like it is possible to create Nil values right now:
This produces:
|
Here is some refactoring in advance of adding back the Signal macro.
The core idea is to leverage the type system a bit more, which lets us reduce the amount of code we're generating and make it possible to use protocols as generic constraints in the Signal macro stuff (coming soon).
By marking all types that can be stored directly in a native Godot
Variant
asVariantRepresentable
we can add a singleinit(_ variant: some VariantRepresentable)
method toVariant
, instead of needing a separate initializer for each type. This gives us a contract where we (and the type-checker) know that anyVariantRepresentable
type can travel in and out of a Variant.Previously this two-way travel worked, but it was not expressed in a way that the type system could reason about it, so we needed to add things like
toVariant()
and an extra protocol to promise that a given type would implementtoVariant()
.I'll call out some of the good things here:
public required init? (_ from: Variant)
is no longer generated on each object, instead theVariantStorable
protocol has a default implementation that can initialize anyVariantStorable
from aVariant
.public func toVariant () -> Variant
no longer needed and is removed from generation — instead you can just doVariant(vector)
Variant
as they're now handled byinit(_ variant: some VariantRepresentable)
VariantRepresentable
andVariantStorable
are not code-generated, they're just implemented as extensions. I think this is an improvement because the compiler can tell us about any problems instead of needing to generate the code first.And here are some compromises that enable the good things above:
init (content: ContentType)
andinit()
are public and required.*Update: I did some more work so that anyVariantCollection < String >
is no longer possible because String is not a direct 1:1 VariantRepresentable type, so these now generate asVariantCollection < GString >
. There are still conveniences around String ←→ GString, so I am not sure if this is a problem or not.VariantStorable
types (includingString
) can be used anywhere aVariantRepresentable
can, so this change is no longer necessary.