-
-
Notifications
You must be signed in to change notification settings - Fork 21.3k
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
Implement access modifiers, private and protected, to GDScript to protect a class member from being accessed externally. #98136
Conversation
92f4242
to
c61f7f5
Compare
would |
Making an extra P.S: Plus I think the omission of |
I'm not sure it makes sense to tie export functionality to access functionality. In C#, you can currently do all of the following, and they all have their uses:1 GDScript is its own specialized language, and it doesn't necessarily need to follow this example. But be aware that tying exporting and access together does not match the current C# implementation, and would prevent one of these four use cases. Footnotes
|
personal nitpick, make it |
This does lower the number of annotations, but increases, on the other hand, the amount of constants and length of a modifier. This is not a very good practice because a longer annotation means longer typing time and because access-protecting annotations will be being frequently used, this may make the efficiency lag down. But anyways, thanks for your opinion :D |
I just imagined some situations where you may use both
Yep, maybe I need to allow this behavior in my future pushes |
I just found a new place to do access protection, which also fixes a bug that a derived class is able to access private members of its super class. |
I prefer the Python way of prefixing with |
This makes sense for constants, variables and signals, but not for functions. According to the discussion in the proposal, the single underline prefix may be confusing whether it means private or protected or virtual for a function. While someone else have suggested me to use double or triple underlines prefix to distinguish them from being vague. Double underlines refers to private a member and triple ones to a protected one. However imo this is also not a good practice, because multiple-underlines prefixes breaks the programming habbit of single underline as a better programming practice in GDScript. Personally speaking, this is not what I'd prefer to do. You may ask me, "Why not adding single underline suffix to declare a member as a private one?" I've thought of this, and the reason is similar to why not using multiple-underlines prefixes. The less underlines we use, the better and neater the code looks. As for what you said that these would break the readability, first, the words private and protected are keywords in many programming languages like C++, C# and Java, and the annotations with the same names may help devs who move from these languages to get familiar with these two in GDScript faster. Second, from a perspective of new learners in GDScript, once they have learnt about the usage of the two annotations and wanted to learn some languages like C# or C++, they will get fast familiar with these two as keywords in these language as well. Third, the implementation of access protection tips the new learners in GDScript the importance of guarding external data access, and helping a team member from accessing, by mistake, a data that should not be accessed externally to avoid a disastrous issue. Saying if it should be an error, which pauses the runtime, or a warning, it needs to be under discussion. These are my own opinions on your suggestion and thought. Anyways thanks for your thought of this pr :) |
I currently encountered a bug when trying accessing external function from other scripts: # In Class A:
@private static var a = 1
# In Class B that inherits from A:
static func test():
a = 10 # Will print error
# In Class C
var d = B.test() # However, this line will not be red; it will throw "Compile error" and "Could not resolve script ClassC.gd." However, I tried many methods to figure out how to make the class C throws the error "Could not resolve script ClassC.gd" and prevent "Compile error" from being thrown, as well as making the line with P.S. I seemed to use |
Hi @Lazy-Rabbit-2001, thanks for your effort! I haven't reviewed this PR in detail, but I'd like to point out a few things:
I don't think there is any confusion between private and virtual methods. It's just that all built-in virtual methods are private (or protected), you are not supposed to call I have nothing against access modifiers and consider them a useful language feature that provides more reliability. I would like to have them in GDScript, but we also need to consider the complexity of the implementation and maintainability of the feature. In my opinion, Python's underscore approach solves the problem of distinguishing between external and internal interfaces quite well and cheaply, requiring only a little discipline and adherence to common conventions from the user. I don't recall ever encountering the problem of accidentally accessing the internals of a class, unlike the problems of the type system, null safety, etc. |
Thanks for replying. I'd like to reply your response by each piece:
Yep, someone had mentioned this in some social media soft. However, it's my ceiling of contribution to this pr and very difficult for me to understand how these part works. Maybe an expert in this field can help with this problem.
Yes, @HolonProduction tipped this to me yesterday. Maybe I need to look through these parts...
Of course, this pr allows it. Because currently it only detects from static analyzer whether the access is from other classes or derived classes or not, it does not affect other instances of the same class to access the data of each other.
I'm not sure whether the current push may effect the access from the debugger, maybe not since it's currently analyzer-related. As for allowing
I've thought of removing Understood. But it's okay to think of a better solution during available time after your hard work of one day.
I've thought of this, but sadly I have no idea how to make a new keyword works. I only know how to register and make a new keyword (reserved word).
Having checked these two, say if a custom virtual method should not begin with
If you do believe Anyways, thanks for your response to this pr again. :) |
…`private` and `protected` keywords introduced as reserved words
Due to the reply of dalexeev mentioned in #98136 (comment) that says that the However, keywords are operated harder and more complex than someone operating an annotation, this needs a lot of hard work and multiple tests. I, perhaps together with some experts in GDScript language parsing, will think of how to parse a private and protected members, and how to implement them in a balanced way. |
@private
and @protected
annotations to protect a class member from being accessed from external classes.
Why close? |
This is my first contribution to godot, also the first try sending a pull request. So if there is any mistake, please let me know and I'm here to hear that. :)
Trying implementing godot-proposal-#641.
This pr provides GDScript users a way to protect their members accessibility, and prevent any illegal access from external classes.
We will have
@private
and@protected
annotations in GDScript soon:Introduction of new annotations
@private
@private
annotation allows a member (currently a constant, a variable or a method) to be accessible only within the current class scope:@protected
@protected
annotation allows a member (currently a constant, a variable or a method) to be accessible only within the current class scope, or the scope of derived classes:Common features:
* A member modified with(This will be obsolescent and check this to know why)@private
or@protected
cannot be modified with@export_*
annotations, and vice versa.@private
or@protected
will hide its documentation from auto-generated doc API, even if you use##
to document it.How these are done?
As is known, this two are trying to restrict the access to the member, so we have to modify
gdscript_parser.cpp
,gdscript_parser.h
andgdscript_analyzer.cpp
.In the head file of the parser, since a
Node
there refers to a lingual element of GDScript, I added an enumAccessRestriction
and an enum-ed variableaccess_restriction
under it to control the member's accessibility. When@private
or@protected
modifies a member, itsaccess_restriction
will be modified to other values thanAccessRestriction::ACCESS_RESTRICTION_PUBLIC
.Once analyzer starts analyzing external access, we detect the access of the member's
access_restriction
and figure out the relationship between the accessor class and the accessee class.Remaining WIP
reduce_identifier()
andreduce_call()
. (GDScriptAnalyzer)Discussion about if@private
and@protected
should be keywords or annotations. Allow@export_*
work with@private
and@protected
Hide GDScript intelliguess from providing hint of private and protected members.Test ifSet()
andGet()
in C# can get access to the access-restricted members in GDScript. (Cross-language programming)Compiler, codegen and runtime stuff. (The most difficult part)Not sure whether an invalid access should pop an error or a warning. (Warning / error system)Unit tests in.gd
and.out
files. (Unit test)Tracking after this PR gets merged: