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

Add object initializers to GDScript #3076

Open
AlexDarigan opened this issue Aug 2, 2021 · 5 comments
Open

Add object initializers to GDScript #3076

AlexDarigan opened this issue Aug 2, 2021 · 5 comments

Comments

@AlexDarigan
Copy link

AlexDarigan commented Aug 2, 2021

Describe the project you are working on

A Multiplayer Card Game (akin to Hearthstone, Magic The Gathering: Arena etc)

Describe the problem or limitation you are having in your project

When instantiating classes I don't own that require properties to be set, such as the peer and root node of a custom MultiplayerAPI I have to do so individually.

var custom_multiplayer = MultiplayerAPI.new()
custom_multiplayer.peer = _peer
custom_multiplayer.root_node = self

A similar issue also occurs when I want to pass data to a scene that I instance (such as card data to a card scene).

var data = load("res://%s.tres" % setcode)
var card = Card.instance()
card.title = data.title
card.faction = data.faction
card.power = data.power

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Add Object Initializers (similar to those that already exist in C#) so that users can set named properties immediately after object construction without the need for an explicit and or accessible constructor.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

If the object that is to be created is followed by an unassigned dictionary, it consumes it with the keys referencing its own properties.

var custom_multiplayer = MultiplayerAPI.new() { peer = _peer, root_node = self }
var data = load("res://%s.tres" % setcode)
var card = Card.instance() { title = data.title, faction = data.faction, power = data.power }

The internal code would perform the equivalent of this.

for key in args:
    get(key) = args[key]

Alternatively there is the With Syntax mentioned back in 2016 in which case the examples would be something like this

If this enhancement will not be used often, can it be worked around with a few lines of script?

I believe this would be used quite often with scene instances.

Is there a reason why this should be core and not an add-on in the asset library?

It affects core GDScript Syntax.

@Calinou
Copy link
Member

Calinou commented Aug 2, 2021

See also #1513.

@willnationsdev
Copy link
Contributor

willnationsdev commented Aug 3, 2021

Would it make more sense to have the initializer list be a post-colon indented list of void-returning expressions?

var custom_multiplayer = MultiplayerAPI.new():
    peer = _peer,
    root_node = self

Only bad thing is that it would be incompatible with scenarios where the post-creation-initialized expression is itself part of some other block-opening statement. But I'm not sure if that should be supported anyway.

@export var card_display: PackedScene
@export var card_name: String

func create_card():
    # Could work? Only performs post-init if .instance() returns non-null value.
    if card_display.instance() { card_data.name = card_name }:
        pass

    # Will NOT work (can't tell what : is for till later)
    if card_display.instance():
        card_data.name = card_name:
            pass

Would also be interesting if it supported other "builder"-like APIs seamlessly by supporting method calls as well.

var list_of_nums := PackedIntArray():
    append(1),
    append(2),
    append(3)
print(list_of_nums) # prints 1, then 2, then 3

Edit: Ah, but if you do a colon, then it might conflict with the new setter/getter syntax anytime you used it on a member variable as opposed to a local variable. Unless you just make the assumption that you have to pick either set: and/or get: OR a list of statements (since doing both with method support would potentially imply calling set() or get() and could become confusing/impossible).

@Calinou Calinou changed the title Add Object Initializers To GDScript Add object initializers to GDScript Aug 3, 2021
@zinnschlag
Copy link

The proposal @Calinou linked (#1513) looks like a superset of this one, functionally at least. I would prefer that option, because it does not only allow for initialising variables, but for even more comprehensive initialisation, e.g. sanity checks and passing on values to the init function of a parent class.

@dalexeev
Copy link
Member

dalexeev commented Aug 3, 2021

This is not so important when there is autocompletion.
In some languages that have the with keyword, it is deprecated or "bad style" as far as I know.

@willnationsdev
Copy link
Contributor

See also #1935. Scripts with scene bindings would have the language implementation defer to the scene during instantiation, but they could also potentially have a custom post-instantiation initialization function that is called.

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

No branches or pull requests

5 participants