-
-
Notifications
You must be signed in to change notification settings - Fork 97
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 public/private access modifiers to GDScript and autocompletion improvements #641
Add public/private access modifiers to GDScript and autocompletion improvements #641
Comments
Related to godotengine/godot#18411 and godotengine/godot#23110. |
I'm going to repeat myself but, I've always found GDScript to be very similar to C++. Yeah I know it's a weird statement but it just the way it feels, especially with static typing being a thing now. In fact when I ported some of the C++ classes back to GDScript, I had to make mostly minimal changes in order for those classes to work. Allowing access modifiers is just a natural step to making GDScript feel like C++ on the mental level. I'm mostly biased as a Godot modules developer, where I dedicate ~30% of development time to C++ programming. |
As an experienced programmer just starting to learn godot idly, I'm also bouncing off this as a vague irritation. I'm fine with 'public by default', and honestly prefer it, but not having a way of making this 'private' makes it more difficult 'remember' how to use the code I've written later. And yes, you can _underscore things but they still appear visible and clutter the autocomplete list even further. :( |
this would allow encapsulation which I support |
Totally agree, public by default, but I really want to be able to mark things as private. |
I'd like to be able to have a variable with private setter and public getter. |
There's one detail i'd do differently: i wouldn't use the verbose syntax like the one in C# but rather the less verbose syntax of C++
To avoid typing extra keyword before every single var/func. It works better when the code is grouped by access modifier which is recommended by GdScript Style Guide. |
@hilfazer I'm not really fond of disconnecting the access modifier from the variable/method name. It makes it harder to visually check an individual member's access modifier. Also, if you copy-paste a snippet around, the access modifier will be lost. |
I am very much in favour of having access modifiers in gdscript. also, the good old SOLID principles are virtually impossible without access modifiers. |
You can have de jure access modifiers via annotations or conventions and still obey SOLID principles. They don't have to be enforced by the compiler (that's how I see it at least). |
private methods are vital when creating plugins. |
GD script definitifly needs such option to mark a class/function/members as private/proteced or by default as public. A Project will be unmaintainable when the amount of classes increases. Please add private and protected modifiers to can manage such stuff, this will help a lot. I prefear to use like in common languages
like the 'static' keyword
Best regards Mike |
if this was implemented I think the best way to go about it is make everything protected by default. that way people can choose what they want to expose. |
I don't think you want |
@me2beats agreed, I think public by default makes the most sense. It gives beginners the save experience as today. |
I strongly disagree. EDIT: also I understand thinking about beginners, but godot tends to take away control from the user to make it simple for beginners. and while making it easier for someone to use is good, taking away control is worse. |
@Shadowblitz16 I'm saying public by default, but with private and protected as explicit options. |
@Shadowblitz16 public should be the default, private and protected be optional |
I really do want to have private members. My biggest problem is the following: class ParentClass:
var a = 10
var random_var = a/2 # I want to make this private
class ChildClass extends ParentClass:
var random_var # throws an error, since it already exists in parent class.
# I don't want to limit all the child classes just because I needed a helper variable for something Also, it would be great if I could make a variable private in the following example as well. class Enemy extends Node2D:
var max_health : int = 100
var health := max_health setget _health_changed
var health_percent : float = 1.0 # This is the variable I want to make private
func _health_changed(val : int):
health = val
health_percent = float(health) / max_health
func _process(delta):
scale.y = health_percent
# Other uses of health_percent This |
I think something like this should be done..
It seems more pythonic since the function and variable keywords are shortened I don't see why these can't be |
I'm not really against this one... But I'm not sure about the readablity either. pub export(int) onready var things vs public export(int) onready var things But it's already kind of long. However I still like the C++ style the most. Although people don't seem to like it as much. That being said, if this was the final choice, I wouldn't mind that much... |
This is an instance where #641 (comment) would make it more readable. My stance on access modifiers is that they are not necessary for following OOP standards (In my time using Godot I never had a case where I needed them. They only add visual noise, the information they provide can be easily added by using underscores: private var health = 10 setget set_health
public var name = "name"
private var inventory = []
public func set_health(to):
health = to vs var health = 10 setget set_health
var name = "name"
var _inventory = []
func set_health(to):
health = to One actually useful keyword would be |
This can be implemented using a |
Too many annotations are a bad thing, it makes code ugly and unreadable. |
I dunno how many people (if anyone) was watching this eagerly, but just in case since I said I was going to work on it: I put this project on hold for now. tx350z's and JojOatXGME's notes made me realize there were flaws with my implementation, especially with the fact that I was comparing on a per-object basis rather than a per-class basis (i.e., different instances of the same class couldn't access each others' Perhaps a little later, when I've got fewer active projects on my plate, I'll take another stab at it, propose my implementation to the GDScript team, and see how things go from there? |
I'm still watching this proposal eagerly. I'm in a similar boat of wanting to work on it, but not having a lot of experience with the codebase. While you're taking a break, I'll take a shot at making it work. See how far I can get. It seems that people are happy with the idea of the |
Sounds good - I wish you luck! 😄 One of the things I learned/saw, I think both here and in the Godot Contributors RocketChat, was that people seemed to prefer it being a keyword rather than an annotation, so that may be something to consider. That being said, I imagine the core behavior of refusing access when the callee and caller types are different should be the hard part, so switching that behavior from an annotation to a keyword should be relatively trivial? Anyways, good luck again! |
That's good to know! I'll start working on a keyword then. |
Implementing the |
What about private methods? We already use the _ there. Does that mean we will never have private methods? Declaring a private method to a private variable will be different? Or we change the current use of an underscore in methods? All of the above is bad imo. The options have already been wildly discussed here with lots of very good points against using an _. |
(The screenshot is from https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_styleguide.html) |
I've found that another (albeit perhaps minor) downside of prefixing private members and properties is that, if you decide to change something from private to public or vice versa, the symbol itself has to change. And when you change the symbol, you have to through your code to fix all the instances of it. VS Code is smart enough to be able to rename all the instances of the symbol, but last I recall, the built-in Godot editor only has a simple string-match capability. At the same time, Godot users are used to that prefix, and being able to recognize script-internal symbols from other places in the code at a quick glance is nice. I would be a bit concerned with tying behavioral changes to the use of the underscore as the first character. Removing it from autocomplete when in another class would be relatively okay, I think, but making the editor throw errors could break existing projects where people have "cheated" and referenced private symbols from other classes since they weren't enforced. Maybe the editor could have an opt-in toggle for "strict control access mode" that enforces underscored symbol access restrictions? |
There won't be any editor changes, if I'm understanding things correctly it's purely a naming convention. Or at least I don't see any point in having editor support for hiding things with a leading underscore. |
The current style guide is for what we currently use. For example using an _ and not using the variable in that class, will throw a warning. So this works currently. But if this proposal is implemented using an _, how will my code know if my method is private or supposed to be overridden? How will auto complete know I have a method in a class that is expected to be overridden if its now been hidden because it thinks its private? Or we just state only built in functions can be overridden which are excluded? But to me it still seems very awkward. Others have also expressed they don't use underscore (myself included) because they are very hard to see or read. There are some that want to use an _ because prefixing a var with more text is quite verbose. So if that's case, what would be the thoughts on excluding the var keyword if using the private keyword? |
I'm sorry everyone, I misunderstood the intent in the contributors chat. The desired feature seems to be to hide things with a hidden underscore, in some situations at least. I'm stepping down from being the implementer, if anyone wants to do that it's up for grabs again. |
No worries, thanks for looking into it! It sounds like there's still not a great consensus on how exactly it should work or be triggered 😅 |
This isn't a "solution", |
I'm for automatically hiding variables with a _ prefix (Go is similar with Uppercase-public lowercase-private); but won't this break existing scripts that access variables prefixed with _? Unsure if Godot has any compatibility guarantees in GDScript, so maybe this is ok. |
But Go does have "public/private", it just does not use a keyword and uses the naming for that. Doing the same on the GDScript would not work, since the |
Another $0.02. I've always questioned the seemingly inconsistent style guide recommendation to use '' prefix to denote "private" properties and methods since Godot also uses the '' prefix for virtual method overrides which are similar in concept to "protected" in fully OOP languages. In most OOP languages private, protected, and public support full implementation of OOP encapsulation. These access (or scope) modifiers are primarily implemented during the symbol parsing and resolution phase of compilation (or byte-code generation). For example, class-private properties are conceptually the same as local variables defined within a method. It's really that simple (yes I know local variables are commonly stored on the stack - that's an implementation detail unrelated to this discussion). Use of a "keyword" or a "decoration" to designate scope is semantic and explicit. Using '' is implicit and potentially creates edge cases that complicate implementation and code readability. For example, is a method prefixed with an '' a private method or an override of a 'virtual' method? Somewhere in this thread is a recommendation to use optional @Private and @public decorations with @public being the default. This approach is non-breaking to existing code and requires extra typing ONLY if you want to use private properties and/or methods, or want to be explicit about scope by tagging important properties/methods. If you don't want to type those few extra characters where needed, you can completely ignore that modifiers exist in the same way you can ignore variable and method type hints. Ok, that's probably more like $0.20. |
Please use backticks `Like this` to avoid pinging users on Github when writing annotations. Sidenote, it is generally agreed upon that if |
A current workaround could be to internally use get_meta/set_meta and externally define a getter.
Maybe some tooling could polyfill or transpile an |
# Public by default, for compatibility.
var public_one: int
@private
var private_one: int
var private_two: int
@protected
var protected_one: int
@public
var public_two: int
public func public_func():
pass
private func private_func():
pass
protected func protected_func():
pass
func public_by_default():
pass
public func _ready():
# Print Error, can't use access modifiers for overriden functions.
pass
|
I agree that @private
var private_one: int
var private_two: int # This is also private doesn't make sense to me - I would expect @export
var exported_var: int
var non_exported_var: int works. Being able to repeat annotations across multiple statements could be nice. For example, if you had several variables you wanted to export, you could do @export:
var exported_1: int
var exported_2: int
var exported_3: int
var exported_4: int or something like that. I'm not sure how I feel about the bracket syntax, since GDScript's syntax is overall more Python-like, which uses colons and whitespace to denote this sort of nesting. Regardless of the precise syntax though, I think repeating annotations like this would make more sense as an independent proposal that this one could benefit from. |
That's already covered in: So let's not focus on that as that would be covered by that proposal |
Was thinking about how to implement this without adding an extra property usage. for property in object.get_property_list():
if property["access"] == PROPERTY_ACCESS_PRIVATE:
print("private")
We can introduce this for properties only at first, it will be usefull to prevent users from editing core variables when making a plugin or a mod in gdscript, for example in my project, a plugin can access all the project classes and it can easily break the whole release if they messed up with the private variables since most of them gets saved after any change. |
Describe the project you are working on:
2.5d beat'em up
Describe the problem or limitation you are having in your project:
Inside a GDScript class i often use "private" variables and functions that shouldn't be visible ouside but that instead are "public", hence visible and usable by everyone.
More or less related is the fact that autocompletion is cluttered, yes alphabetic order is good but the list always starts with lots of constants and the function or variable we want is usually buried in lots of other things that aren't useful in that moment.
Describe the feature / enhancement and how it helps to overcome the problem or limitation:
Let us specify if a variable or function is private or protected(or whatever keywords you want to use), a private variable can only be used by the functions of the same class, protected means that it's also accessible by the classes that inherit from the class the variable is in.
About autocompletion in my opinion it would be even more useful if suggestions were grouped by class, ordered from the leaf of the class tree back to the root class, or maybe add to the editor's options the possibility to order and filter what is shown.
Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams:
var v(no access modifier means public)
protected var v(accessible only in the class it's in and the ones that inherit it)
private var v(accessible only in the class it's in)
Autocompletion suggestions would be grouped by class, ordered from the leaf to the root of the class tree, maybe with their class written somewhere.
It would be also helpful if the suggestions were colored the same way as in the editor, this way it would be even faster and easier to find what we want.
If this enhancement will not be used often, can it be worked around with a few lines of script?:
Access modifiers and autocompletion are essential features so they would be used very often and probably they can't be made with few lines of script.
Is there a reason why this should be core and not an add-on in the asset library?:
It seems to me that a GDScript feature like these ones should be core.
The text was updated successfully, but these errors were encountered: