-
-
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
GDScript: Design goals #18698
Comments
As a tutor the fact that GDscript is focused on gameplay programming at the moment is a great advantage. It does the job well yet it doesn't feel bloated and provided you're careful in how you implement things the code stays pretty easy to read. I'd recommend to bring Lars Kokemohr in the loop: he's got a lot of gamedev experience, including AAA, thinks seriously about code architecture and languages, and he's got experience teaching Godot and Unity at university level so he's got great insights to offer. |
As small as possible is exactly the crux of the matter, because as possible implies as possible while still fullfilling its purpose. Also, these are different concerns: a large library of functions does not necessarily imply a complex language. And this is exactly where I would try to draw the line:
TL;DR:
|
There should only be one (exposed and documented) way to do a thing, but that way should be as easy as possible.
Keep one Godot way to do things, like there is a Pythonic way to do things. |
Agreed with @mhilbrunner here. Especially on the:
Regarding the library part it means focusing on improving, adding nodes and other built-in classes right? Doing so benefits other languages too so it benefits every developer. |
@NathanLovato Exactly, nodes, classes and methods on them instead of keywords or statements in GDScript. Thats not possible for every feature; lamdbas or variadic functions need support in GDScript. But when we can add something to the standard library instead, we should strive to do so. |
Please make these things more consistent:
Hopefully none of these points ventured too far into feature request territory. Some things seemed necessary to implement to meet these design suggestions as a matter of course, but may not be necessarily reflective of the major contributors' design goals for the language... Edit: remind me not to write these things half-asleep. Point 3 meanders a bit too much to make a strong case for itself, but basically it's a "furthermore" to point 2, to make both initialization and declaration of a var more consistent, which are two separate but heavily intertwined things. |
In my opinion Gdscript has enough features right now and scripting with it is simple and fun. In the other hand GDNative is enough mature to counter gdscript lacks. If I need (?) lambda functions there's C# support, if I need fully functional languages I can bind my favorite one without trying to make gdscript like that. TL;DR |
I'm gonna be a stinker and say that the syntax sugar added in for 3.0 were some of my favourite additions, and they were a big factor in my decision to pick up Godot. This includes both the shift towards interacting with properties directly, and the Don't get me wrong, I don't want to see GDScript bloated by unnecessary sugar out of principle. However, the additions so far have been really neat IMO and I'd love to see more shorthand constructs like these considered in the future. I just don't know where exactly to draw the line other than "let someone with good judgement have the final say." |
@Homer666 Have to agree. Those were nice changes for sure. |
I'm in favour of keeping it small and tight and with a single Godot way to do stuff (eg we should standardise on .new() or .instance() ) As it is already python-esque, when gdscript needs a new feature I think it should track python as closely as possible. It allows new users to transfer their skills across very quickly and the large python dev community have solved problems gdscript is likely to encounter as it grows. Stuff I'd like to see: array slices, Array.extend, list comprehensions, optional keyword arguments, something equivalent to try except error catching, random.shuffle, random.choice. |
Multiple imports such as Python has would be handy, if we aimed to replicate basic Python features. |
I miss functional things a little, especially lambdas which were proposed 3 times now but for some reason never went merged... maybe not enough time to review / big updates were coming at the same time? Functions not being able to be first-class citizens feels really odd in a dynamic language. Also, I miss the ability to Finally, optional typing can be really good for tooling and maintainance, but I think that's on the way :) |
I mostly agree with @vnen. This is more a practical than a theoretical thing: GDScript codebase needs to stay small to be maintainable. The more features we add, the more unmaintainable it becomes. Features that you may use only a few times in your project that will save 2 or 3 lines of code, should not be included. If adding a cool feature that will be useful a few times only takes like, 1 or 2 lines of code.. this is fine, nothing against it. If adding it takes several dozen lines of code, then it will most likely be rejected. Property access and the $ operator were features you use often that definitely improve quality of life. The upcoming optional typing is the same.. so even if they need a few dozen lines of code, they are worth it. Lambdas may also be useful, but if it means hugely increasing GDScript size, then they should not be added. The best approach that needs to be taken here to implement features is to do it using the least amount of new code possible. |
But they are different things. First is for built-ins, second is for classes, third is not really even a constructor. I feel if they were all the same, it would be more confusing. |
This is great in theory, but in practice it makes the codebase more difficult to maintain. I think the fact Python will soon be an optional language will be a solution for developers who really can't live without the more advanced syntax sugar. |
I have nothing against them, but implementation needs to be better, and we knew for a long time optional typing was going to be added. I guess when @vnen is done with optional typing, we can take a look at it again. |
Disagree, Python is a different language with way different goals. But yeah, lambdas/first class functions and variable amount of arguments for functions (variadic functions) are the two biggest things I miss, Zylann. :P Sorry, thats kind of "feature wishlist" territory again. Again: Happy birthday, @reduz :) |
Exactly what I meant. |
Thank you for helping me understand the distinctions and why they are important. Rolling I'd argue against I'm glad that optional typing is on the roadmap, honestly. Optional typing is an important step to providing overload support, which would probably be necessary to make everything I'm saying make sense. My first instinct when starting GDScript a month ago was to "hint" to the script editor on uninitialized vars by using the same syntax used to return a new value type so I could get better autocomplete. Specifically, (apologies for the long-windedness!) |
Reminds me of something I was working with yesterday. When we want the size of an Array, do I use Personally I prefer using And similarly with Of course these are very specific examples, but I just wanted to highlight something worth considering. Also:
I don't think this should be an either/or question (not that I think that's what you're implying). Certain things are better handled with a functional approach, other things are better handled with a procedural approach. The two complement each other. |
Thanks for all the responses. First, let me clarify a few points that seem to stir confusion:
Not really. One are for primitive types, which are not "instances" per se (like
This is more about how you can use the array as queue, list, or stack using more conventional function names. But this should be another discussion since they are not GDScript constructs, they are part of the Godot API. There's an important difference there, because changing this API requires no change to GDScript itself.
My list was more about examples for discussion than strict decisions to make. Many of those can be viewed as a spectrum rather than a discrete boolean choice.
That's quite a complicated topic and it relates to my last bullet from the OP. The thing is that while you might want to do it in the way you're used to, there might be another (more Godot-y) way to do the same thing. Hence my question: should we embrace many paradigms or solve this by documenting the translation between those and the Godot way? For instance, signals are very important in Godot but many people seem to forget they exist.
This is a GDScript function but it serves more to generalize getting the length of different types of collections (for instance, From what I can gather from this discussion (and the previous history) so far:
Also, while I do like embracing the functional paradigm, if we add first-class functions we'll probably need more functional stuff as well (such as |
I have a recommendation and that is to look for some metric of improvement(e.g. ratio of LOC added in GdScript to LOC saved in example scripts). This is a technique I have read that Niklaus Wirth used in his languages, with the main metric in his case being the speed with which the compiler could compile itself. This led to tradeoffs between source code size and algorithmic optimizations, with simpler, cleaner algorithms often winning out when put to the test. Doing this will help in rejecting bloat going forward, while still allowing for some evolution. Features that eliminate whole classes of errors in user code would override a rule like this(maybe there is a way to capture potential error rate in a number?) |
IMHO LOC is a bad metric. It only measures volume, not quality. It doesn't capture whether the example code improves, or becomes more readable and maintainable. Shorter code isn't necessarily better. See arguments about better variables names. |
I assume LOC was only an example of metric, not an actual proposal. The idea of a metric is interesting, but I can't think of anything that would fit nicely into "the Godot way" of doing things. |
This is probably controversial, but in my opinion I think that moving towards reactive (not necessarily functional, although it kinda' comes with the territory) is what needs to happen. For multiple reasons, but most of all it's just natural to work with when dealing with time and multimedia interactions. It's the response to contemporary needs and most languages are moving in this direction, mostly through libraries, but there are a few that have built-in functionality (like dart). For generic info on reactive programming and why it's so useful check this. This imperative type of programming is suited very well for input -> crunch -> output type of applications, not interactive stuff. Think of the mouse, instead of getting one value at a time (through connecting to the event) and being forced to keep track of the time yourself and do maths with time, control flow etc. is very unnatural. Instead, with composable streams where you have "atomic" functions that operate on incoming data as data is fed into the pipe is far more natural, it's exactly what you'd expect to do, instead of keeping track of each individual event and having to think about all the interactions with future/past events, keeping track of them individually, a stream that takes say for example the events in the last 0.5 sec and gives them to you to process or combine multiple streams or just give you double taps as an event are much more natural. So I do agree with everyone before me about keeping it simple and maintainable, I just don't think that sticking with the imperative style is suited for interactive applications. It can be done sure but with a lot of boilerplate and it's very easy to get wrong the order in which you process stuff as things get passed around all over the place randomly really, if you think about the user interaction with the game. edit |
There has been a lot of discussion so far, and from what I gather it seems that we've been able to narrow down on some design goals for GDScript. Is there more to discuss, or is this ready to be concretized in the form of some docs in the roadmap repo, as originally mentioned? For what it's worth, I agree with a lot of what has already been mentioned, including the summary in #18698 (comment). I would suggest, though, adding "consistency" (both in APIs as well as in GDScript itself) as a goal in addition to the ones you already listed. Rationale:Consistency in syntax and naming decreases cognitive load and allows developers to build more of an intuition around how the system works. In some cases, it may be justifiable to break consistency in order to (for example) highlight a truly unique case or make slow / "dangerous" operations easier to detect - but in the general case, I think we should strive for consistency. For example, as mentioned, the 3 different syntaxes for "constructors" apply to different cases / types of entities, but we should consider whether the differences are important enough to justify different syntax. As a developer using Godot, do I really need to care that |
In terms of future elements that godot could have, a short hand for
Would basically be the equivalent of writing something like....
Idk how others would feel about this, but it could be kind of useful... |
I don't think it's worth adding a special operator just to shorten |
What do the discussions in this thread mean for issues such as #23101? Would such complex things ever be added if they are only useful in some situations for some users? |
@aaronfranke this comment is quite relevant regarding typed OO GDScript #23101 (comment) |
Adding this to the OP as well for visibility, but these are my current ideas:
|
This reminds me, it would be really nice to have local I agree with all your points, but I'm a bit confused as to what "LL(k)" means. Does LL(1) mean that any given token's behavior is not changed by the following token? That sounds good to me. |
I second @aaronfranke on local constants. In some longer files we've worked on lately, we had quite a few cases where we needed just that (specific tween-based animations with different durations and delays, among other things) |
@aaronfranke There's a proposal about immutable variables here: godotengine/godot-proposals#820 |
I'm already doing this in the GDScript rewrite.
That's indeed a quite technical term. One Note: It is possible to have an LL(0) language, which is super simple to parse, but it's very difficult to make it look natural and useful. |
Be newbie friendly. It already is and should stay that way while becoming even friendlier.
Newbie can be unaware of optionally skippable quotes. Or s/he could not notice there's Or here - newbie may think $ is fetching a node named
I'm no expert but i think removing optionally skippable parts of a syntax would make the implementation smaller and thus simpler. |
I'd like to point out an other area of focus that is rarely actually talked about which is productivity. Having a hammer which is easy to learn how to use, or easy to construct/repair for the manufacturer is all well and good, but the hammer exists to be used to achieve some result. A hammer which is more difficult to learn, or harder to make, is absolutely worth it if it produces better results. The point of scripting languages is not really to be easy to learn but instead to be easy to work with in order to get high productivity. (This is also what makes them easy to learn.) You want to be able to quickly write only a small amount of code and get your idea working. Compiled languages instead focus on runtime performance. Python is the epitome of productive languages and GDScript is inspired by it because it shares the same strong focus on productivity, with the desire to be able to quickly write game logic and mechanics. It is important to remember this when considering what features to add. It's true that maintaining all of the features of Python in GDScript would certainly be too much work, and some things wouldn't even fit at all because of performance since game code often needs to run every single frame. It is, however, not true that Python is difficult to learn - despite all those features. This is because you don't have to use features you don't know. With this in mind For instance, Array.extend and Dictionary.update. Making those functions yourself is only 4 lines of code each and most people don't need them most of the time. But including them costs nothing and it increases productivity. I'm guessing there'd also be quite a difference in performance. An other example is a lack of a simple builtin function for listing a directory. Python is full of functions like these and GDScript should be too. On the subject of list comprehension (with dictionaries too); I know some people really don't like them, and that's fine - you don't have to use them - but they're very productive if you're comfortable with them. Also, generators/iterators from yield in functions and array-slicing syntax. And sets. And itertools etc. Often you're only working with individual things but as soon as you have a bunch of something all of these functions and features become very useful. It's true that they can be hard to wrap your head around for beginners, and I don't know how much those features would affect the parser, but they're just so productivity once you learn them. Keyword arguments (optional unordered arguments with defaults) is an other example of an extremely productive feature, even for beginners. It almost doesn't matter what the implementation cost is, because it makes it so easy to create objects and call functions with only the arguments you want. With it you can have all the .new() of nodes etc accept the three parameters you want to change right away instead of having them on three extra lines afterwards. Then there are things like custom datatypes (for overloading operators). Beginners won't use them, that's fine. But in some situations it makes all the other code so much easier to work with, greatly increasing productivity. This feature has performance implications for other code, even when not used, but I think it can be implemented separated from the normal object. Again these are just examples, but I think productivity should absolutely be a core part of the design goals. GDScript exists to get more work done faster. |
Honestly a newbie will be unaware of many things, because they are a newbie. Such person should be reading documentation and tutorials to learn. The GDScript basics page is not that long (sure, it has a lot to soak in, but such mistakes can be avoided and understood by reading the relevant section again). That's not an excuse to bloat GDScript but we should not strip it and remove features from the pros to write optimal code just because a newbie might stumble on it. BTW the
Note that adding things to Godot should follow the proposal workflow. And if something is not used often it won't make the cut. The point is that those things do not need to be provided out of the box from Godot but instead provided as plugins that you can download from the Asset Library. So only those who need it will get it.
Well, it costs almost nothing to add one thing. But then one by one this becomes a lot of things, and then it does make a difference. How often you need to list a directory in a game project? If you need to process the entries, iterating a Directory object won't be much different than iterating a list you got with a builtin function. Also is it recursive or not? Should it show hidden (dot) files? As you start adding arguments to customize that, the function isn't so simple anymore (and if you don't add those then it's less useful thus less used). It's not that simple to add stuff without thinking of use cases, that's why we introduced the proposals.
Adding keyword arguments would make the release binary bigger and it would introduce a performance cost every time you use them. You know what's gonna happen? It will get a bad rap for the performance penalty and people will start recommending not using it, which renders the feature pointless.
My point is that GDScript should be easy to write, which kind of implies that we want people to be productive with it. But it should not happen in detriment of other points. Even though performance is not the goal above it all, we should not make it slow for an edge-case feature. And again: everybody can open a proposal for a particular feature they need. My ideal for this "design goals" is to be one parameter for the GDScript-related proposals to be considered (notice that I opened this issue way before the proposal system was in place). It's mostly guidelines that are a tad subjective. So most of the examples could actually be added, as long as they go through the workflow we set up. This is not a dismissal for the examples, just an explanation that it's not that simple to "just add everything that is marginally helpful" as that could have an impact in other areas even for people who don't use it. |
Closing, as GDScript 2.0 is now feature-complete. Further changes should be discussed on the Godot proposals repository. |
There are a lot of requests for changing stuff in GDScript, be it to extend functionality, make some syntax sugar, or add their favorite language feature. While it's good to know how people are using the language in order to improve it, deciding cases ad-hoc is prone to lead to inconsistency. It'll become more and more like a Frankenstein monster.
My proposal here is to create some master design goals for GDScript in the roadmap repository and decisions should be based on such document. That way there's a clear set of criteria to accept or reject proposals made by users.
This ticket is to ask about ideas on how to make such document, and what goals we should have in mind. This is not a place to ask for your wanted feature, this is more of "meta design", showing which way we should go in general, and not specific things that should go in and out of GDScript.
For instance, there are some decisions to be made:
And probably some other stuff that I'm forgetting.
The idea here is not to decide which features will go in (though that's the endpoint) but to make up which criteria we should use to decide the features.
These are some ideas that I gathered when I was writing a proposal for discussion. I'll leave them here as it is what I now have in mind:
The text was updated successfully, but these errors were encountered: