Skip to content
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

Merged
merged 7 commits into from
Nov 1, 2023
Merged

Conversation

PadraigK
Copy link
Contributor

@PadraigK PadraigK commented Oct 28, 2023

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 as VariantRepresentable we can add a single init(_ variant: some VariantRepresentable) method to Variant, instead of needing a separate initializer for each type. This gives us a contract where we (and the type-checker) know that any VariantRepresentable 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 implement toVariant().

I'll call out some of the good things here:

  • public required init? (_ from: Variant) is no longer generated on each object, instead the VariantStorable protocol has a default implementation that can initialize any VariantStorable from a Variant.
  • public func toVariant () -> Variant no longer needed and is removed from generation — instead you can just do Variant(vector)
  • Many initializers are removed from Variant as they're now handled by init(_ variant: some VariantRepresentable)
  • Conformances to VariantRepresentable and VariantStorable 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) and init() are public and required.
  • Various ContentType internals are public
    * VariantCollection < String > is no longer possible because String is not a direct 1:1 VariantRepresentable type, so these now generate as VariantCollection < GString >. There are still conveniences around String ←→ GString, so I am not sure if this is a problem or not. Update: I did some more work so that any VariantStorable types (including String) can be used anywhere a VariantRepresentable can, so this change is no longer necessary.

@PadraigK
Copy link
Contributor Author

@PadraigK
Copy link
Contributor Author

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
@PadraigK
Copy link
Contributor Author

Hold off on reviewing/merging this please, I have a couple more improvements that address the compromises above.

Ok, this is in better shape now, it no longer messes up VariantCollection<String>

@PadraigK
Copy link
Contributor Author

@migueldeicaza
Copy link
Owner

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.

@PadraigK
Copy link
Contributor Author

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.

@migueldeicaza
Copy link
Owner

Thank you for your contribution!

@migueldeicaza migueldeicaza merged commit 2a75d1a into migueldeicaza:main Nov 1, 2023
1 check passed
@migueldeicaza
Copy link
Owner

One question: how does this pass a subclass of Wrapper/Object to a Variant?

@migueldeicaza
Copy link
Owner

Ok, figured that out - but it does not seem like it is possible to create Nil values right now:

Variant (Nil())

This produces:

Initializer 'init(_:)' requires that 'Nil' conform to 'VariantStorable'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants