Open zjin123 opened 3 days ago
Seems like a duplicate of https://github.com/godotengine/godot-proposals/issues/641
I think this consolidates #641 with some extra usages
Personally I'd prefer protected keyword over internal. Looking at all the related PRs and proposals they too all seem to use protected.
Personally I'd prefer protected keyword over internal. Looking at all the related PRs and proposals they too all seem to use protected.
The more ambiguous reason is that inner may lead new gdscript users to the concept of private
, which only allows a member to be accessed from the same class.
This also mentioned me of what dalexeev tipped under that pr of mine. In some languages like Haxe, private
= protected
. So if the author insist using private
and inner
as modifiers, it's better to swap their functions.
Limitation
This feature relys on static typing. So the following code works (and it should not):
extends Node class Foo: private func foo(): pass func bar(obj): # <-- obj's type is unknown obj.foo() func test(): bar(Foo.new())
because the type of
obj
cannot be determined at compiling time.
GDScript is a gradually typed language, i.e. it combines the qualities of both dynamically and statically typed languages. Type hints are optional and help with static analysis and performance. However, typed code must easily interoperate with untyped code. We don't want to limit users of untyped GDScript and there are no plans to make GDScript a fully statically typed language, as far as I know. So this limitation raises serious concerns about whether we should include the feature in this form.
For new project, add a project setting
gdscript/default_access_level
which is an enum of Public, Internal and Private. It will change the default access level for all class methods and class variables without modifier for the whole project.
I really don't think we should make GDScript behaviour configurable through project settings.
Limitation This feature relys on static typing. So the following code works (and it should not):
extends Node class Foo: private func foo(): pass func bar(obj): # <-- obj's type is unknown obj.foo() func test(): bar(Foo.new())
because the type of
obj
cannot be determined at compiling time.GDScript is a gradually typed language, i.e. it combines the qualities of both dynamically and statically typed languages. Type hints are optional and help with static analysis and performance. However, typed code must easily interoperate with untyped code. We don't want to limit users of untyped GDScript and there are no plans to make GDScript a fully statically typed language, as far as I know. So this limitation raises serious concerns about whether we should include the feature in this form.
Thanks for the reply. The feature is indeed optional. It is a pure static checking for typed code without involving any runtime change. For untyped code, this feature actually has no effect and those codes will work like usual. Only when a user decides to opt-in this feature by explicitly marking types and applying access level modifier, the feature can provide additional check at compiling time as a bonus. If a user chooses to stay with untyped code, then the feature appears as it does not exist (like the code in the limitation section will compile and run as usual without triggering any access level check at all). Hence I think it does not limit user of untyped code or force them to make any change. Purely optional. It is all up to user's decision.
For new project, add a project setting
gdscript/default_access_level
which is an enum of Public, Internal and Private. It will change the default access level for all class methods and class variables without modifier for the whole project.I really don't think we should make GDScript behaviour configurable through project settings.
Indeed. I will remove it.
Personally I'd prefer protected keyword over internal. Looking at all the related PRs and proposals they too all seem to use protected.
Sure. I will change internal
to protected
. Actually I have no preference over those two :)
One other change I'd like to see is pub changed to public. You're using the full word for private and protected, but abbreviating public to pub which is inconsistent and may cause confusion.
One other change I'd like to see is pub changed to public. You're using the full word for private and protected, but abbreviating public to pub which is inconsistent and may cause confusion.
I just pick pub
from Rust as it is short and convenient... But you are right, I will change it.
Thanks for the reply. The feature is indeed optional. It is a pure static checking for typed code without involving any runtime change. For untyped code, this feature actually has no effect and those codes will work like usual. Only when a user decides to opt-in this feature by explicitly marking types and applying access level modifier, the feature can provide additional check at compiling time as a bonus. If a user chooses to stay with untyped code, then the feature appears as it does not exist (like the code in the limitation section will compile and run as usual without triggering any access level check at all). Hence I think it does not limit user of untyped code or force them to make any change. Purely optional. It is all up to user's decision.
While developers can opt-in to typing, they cannot opt another developer out of typing by "forgetting" the type of a variable. e.g.
class Foo:
var x := "hello"
func _ready() -> void:
var y : Variant = Foo.new()
y.x = 3.0 # valid at compile time, but fails at runtime because I can't make Foo.x ignore its own type
But this proposal and associated PR do trivially allow me to bypass somebody else's access restrictions. e.g.
class Foo:
private var x := "hello"
func _ready() -> void:
var y : Variant = Foo.new()
y.x = "world" # valid at compile time, and doesn't fail at runtime: Foo.x ignores its own access restriction
This behaviour may be surprising, especially for the author of Foo
.
While I like the feature, I worry about this limitation.
reduz's initial core values for gdscript were centered around being easy to learn and fast prototyping.
even though gdscript has changed over the years, i still think those values are integral to godot. if the dev needs access to variables/functions that are private in c++, they can compile from source.
vice versa if they need to implement access specifiers for classes in gdscript, they can make a module or use gdnative. imo, piling on extra keywords in gdscript can make it overly complex for the developer
if they need to implement access specifiers for classes in gdscript, they can make a module or use gdnative
This is currently the 11th most requested feature in godot-proposals and that's not even including all the duplicates of the same request. Suffice to say, the desire by the community is high enough for it to be added to the engine IMO.
if they need to implement access specifiers for classes in gdscript, they can make a module or use gdnative
This is currently the 11th most requested feature in godot-proposals and that's not even including all the duplicates of the same request. Suffice to say, the desire by the community is high enough for it to be added to the engine IMO.
https://www.mtfca.com/discus/messages/506218/541602.png
core functionality shouldn't be added just because it's popular. it should be gauged whether it's truly needed. there's already two solutions the developer can do: compile from source or use gdnative. the more stuff that gets piled in gdscript, the more bugs that arise from it (which can negatively effect godot's development).
i've seen numerous threads in this section where users are wanting to turn gdscript into some god-like c++ language with STL support, access specifiers, etc. imo it goes against the entire purpose the language was designed for..
I've grown to like the simple and succinct Python-style underscore for private stuff, and I believe GDScript manages just fine with that.
As a bonus, I like how explicit the underscore is, I can see from the function call-site and variable usage, whether the element is private.
Personally, regarding GDScript, I would simply make a single underscore account for both private & protected, and not introduce any additional keywords.
Describe the project you are working on
A cross-platform app
Describe the problem or limitation you are having in your project
I think hiding class method/variable from outside may reduce potential bugs and makes code more clean.
Describe the feature / enhancement and how it helps to overcome the problem or limitation
Allow access level modifier on class method and variable.
Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
Implemented in https://github.com/godotengine/godot/pull/98606
UPDATE:
internal
changed toprotected
.pub
changed topublic
. Project setting for global default access level is removed.The following should not break existing code.
Add keywords
public
protected
private
as access level modifier for class method and class variable and an additional keywordreadonly
for class variable.public
the method/variable can be accessed by anyone.protected
the method/variable can be only accessed by the class defining it and its subclasses.private
the method/variable can be only accessed by the class defining it.readonly
the variable can be read by anyone but can be only assigned to by the class defining it.All of the four keywords can be used as identifier to not break existing code.
For class method/variable without explicit access level modifier in one script, add two top-most annotations
@private
@protected
.@private
implicatesprivate
.@protected
implicatesprotected
. If no such annotation is applied, default topublic
to not break existing code.Limitation
This feature works only at compiling time and rely on typed code. It has no effect on untyped code both at compiling time and at runtime. For example, the following untyped code will compile and run without triggering any access level check. It is up to the user to decide to opt-in this feature (by writing types and access level modifiers) or not.
If this enhancement will not be used often, can it be worked around with a few lines of script?
No.
Is there a reason why this should be core and not an add-on in the asset library?
Need to modify GDScript's compiler.