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

Idea for adding support for multiple classes in one file. #59

Open
adamuso opened this issue Dec 17, 2021 · 15 comments · May be fixed by #61
Open

Idea for adding support for multiple classes in one file. #59

adamuso opened this issue Dec 17, 2021 · 15 comments · May be fixed by #61

Comments

@adamuso
Copy link
Contributor

adamuso commented Dec 17, 2021

In readme there is a task in Road to superior development saying:

would be nice to declare multiple classes in the same .ts file and have the compiler sort it out

I have an idea. Godot for every .gd file has one main class and can have subclasses defined by class keyword. This really nicely match typescript export default and export. This way ts2gd will have an easy way of telling if a class in godot should be generated as class_name SomeClass or class SomeClass:. @johnfn what do you think about it?

See #61 for proof of concept.

@johnfn
Copy link
Owner

johnfn commented Dec 17, 2021

Oh no - you're going to be annoyed with me for this but I've actually already implemented multiple classes in a single file! That TODO list is sadly out of date (I was maintaining it back when no one was actually using this project.... lol).

Just so you know, the most up-to-date list of things to do on this project can be found here: https://github.com/johnfn/ts2gd/blob/main/main.ts#L3

I suppose I should update the README to have this information in it. :)

@johnfn
Copy link
Owner

johnfn commented Dec 17, 2021

Two quick comments about your implementation though:

  1. I currently don't create subclasses in the Godot style at all. Every class is its own proper thing in its own file. I like this because it means they way we codegen classes is uniform.
  2. A bit more of a personal preference, but I don't like export default that much because it doesn't work well with autocomplete imports.

@adamuso
Copy link
Contributor Author

adamuso commented Dec 17, 2021

Nah, don't worry. I suspected that it is already implemented by looking at the code. I also do not prefer export default because of lack of good support for auto imports and auto completion, but I've checked recently on VS Code and actually it really has been improved to a point that is quite usable.

My thought was just that default classes are very similiar to godot main class in .gd file. Also it would be very natural for people using default export to think that this is a main class.

@adamuso
Copy link
Contributor Author

adamuso commented Dec 17, 2021

One thing that I do not like about current solution is that one .ts file can correspond to multiple .gd files. That is a bit counter intuitive for me.

@johnfn
Copy link
Owner

johnfn commented Dec 17, 2021

Wow I didn't know that about default imports, thats awesome :)

Yeah it makes sense for people to think the default class is the main one, but how would that affect the TS code? I feel like all the TS code would be the same with either implementation - except I guess we could allow import Blah from file...

@johnfn
Copy link
Owner

johnfn commented Dec 17, 2021

Ah yeah, I hear you on one ts -> multiple gd being counterintuitive, but the thing is, how else are you supposed to add two classes from the same script to different scenes? At least thats what I was imagining it would be used for...

@adamuso
Copy link
Contributor Author

adamuso commented Dec 17, 2021

For an app like ts2gd I think it should not limit the developer from using a specific gdscript functionality. Currently godot allows inner classes and we cannot make use of that feature through TypeScript.

Mainly I think that everything that is possible to do in gdscript should be possible to be represented in TypeScript. In a easy way that TS developers understand of course. Creating multiple classes in one file is very frequent for someone using TS, but then we generate multiple files when we could just create inner classes.

From TypeScript point currently we would only add default keyword and update imports, but this way we create a opening for new feature that is intuitive from TypeScript perspective.

@adamuso
Copy link
Contributor Author

adamuso commented Dec 17, 2021

Here is an example what it could look like:

export default class MyNode {
  a: int
}

export class HelperClass {
   b: string
}

// Class that is not exported have no sense in gdscript, but in TS we can
// use this to limit someone from using that class through an import.
// This is important when we are writing a library for example
// Both cases with export and no export would generate same code for gdscript.
class NotExportedClass {
  c: boolean
}

Example generated code

class_name MyNode

var a: int

class HelperClass:
  var b: int

class NotExportedClass 
  var c: boolean

When you look at both codes you can clearly see exactly which part of gdscript is generated from which lines of TypeScript.

@adamuso
Copy link
Contributor Author

adamuso commented Dec 17, 2021

Ah yeah, I hear you on one ts -> multiple gd being counterintuitive, but the thing is, how else are you supposed to add two classes from the same script to different scenes? At least thats what I was imagining it would be used for...

Godot separates inner classes from the main ones, because inner classes cannot be used to create a node and they also cannot be used to attach a script. We should also tell people that export default will give you clearly a class in gdscript that is visible to Godot and export or no export will give you a helper class that can be used only in other code. At least that is what i'm thinking :)

@johnfn
Copy link
Owner

johnfn commented Dec 18, 2021

Mainly I think that everything that is possible to do in gdscript should be possible to be represented in TypeScript.

Hmm, I don't understand why the goal would be to generate all possible gdscript? In my mind the goal has always been for people using ts2gd to write their entire project in TS, without ever having to worry what the generated GD looks like. So, in my mind, we should target all possible TS, but not worry about targeting all possible GD.

Unless you're thinking of some TS-GD interoperability? But I can't think of how not having inner classes would hamper interoperability...

Open to be convinced the other way though!

@adamuso
Copy link
Contributor Author

adamuso commented Dec 18, 2021

If you want to make ts2gd popular and usable you need to take account what kind of people can use it and what would they like in such tool. I see at least thee kinds of people:

  • first we have people that were only using GDScript but searching for something new/fresh - these people want usually almost 1 to 1 conversion. We are assuming that they do not know TS very well but they want to learn it and because of they GDScript knowledge they want to be able to use every feature that they always used in GDScript. They want their generated GDScript looking good and readable, because then they know if ts2gd is generating unoptimized or wrongly written code. They want to feel safe about it.
  • then there are people that never touched GDScript (or do not like python style coding) but have experience in TS, saw this project and thought that it might allow to create games without learning whole new language - these kind of people mostly expect that the code they write in TS will just work in GDScript. Some of them will want or start to learn GDScript for better game engine understanding, fine tuning or control. If we create some magic convoluted or unintuitive generation they might get demotived to do so and will be unhappy that they do not have control over the code.
  • at last there are people that know both worlds well GDScript and TS - I think it will be really hard to create code generation that suits everyone needs. There will be always some people that will not be happy how generated GDScript looks and they need to be able to create some code manually using GDScript. We should not limit them to write only in TS or assume that if they using ts2gd they will never use additional .gd files written by themselves. This way they will have a way of creating code that ts2gd for some reason cannot generate.

I really like this project, because I myself do not like python syntax style. What I would really like is that the code I write in TypeScript gets converted to GDScript in a natural way which should not need a lot of additional explanations. I hope my opinion does not scare you ;)

Unless you're thinking of some TS-GD interoperability? But I can't think of how not having inner classes would hamper interoperability...

No i do not think right now about interoperability, more likely about reflection of TS code in GDScript code and vice versa for easier learning curve. It would be so nice if this project could attract more TS developers to create games in godot :D

@johnfn
Copy link
Owner

johnfn commented Dec 18, 2021

By all means keep sending me more scary opinions! :D

Preface: the way I've been thinking of the use cases around ts2gd converting TS to GD is in the same way that I think about how TypeScript converts TS to JS. E.g. most people these days just write TS and don't worry too much about the JS output. In fact, when I write TS I basically never look at the JS at all.

However I see that maybe the core issue here is in inspecting the output and making sure it's sane. I kinda noticed that with everyone else as well, that they wanted to inspect the output to make sure it makes sense. I definitely wasn't thinking about that case before, but it seems pretty important. It's kinda hard to do this all the time, I mean even right now we emit a ton of typeof checks when checking equality because of some godot quirkiness, and that makes things hard to read. Maybe we could improve that too...

I think the thing I don't understand is if inner classes are really making the code less readable? I suppose that it's a bit less intuitive if the class ends up in a separate file - they could be confused wondering where it ended up.

@ksjogo
Copy link
Contributor

ksjogo commented Dec 18, 2021

One thing I would add as that we should consider the debugging experience within Godot.
One great advantage of the transpilation approach is that you don't break core godot functionality.
Instead I can still use the embedded debugger.
For TS->JS readability there is not as important, as the sourcemap will make TS show up in the debugger.
But afaik Godot debugger doesn't have sourcemaps, so the user will debug in GDScript.
For that it is massively helpful if the structure corresponds to the original file, so the user can know what the change.

@adamuso
Copy link
Contributor Author

adamuso commented Dec 18, 2021

Preface: the way I've been thinking of the use cases around ts2gd converting TS to GD is in the same way that I think about how TypeScript converts TS to JS. E.g. most people these days just write TS and don't worry too much about the JS output. In fact, when I write TS I basically never look at the JS at all.

The thing is that TypeScript has been around for a long time now. There is no need to check if it generates good JS code because with such maturity a lot of people can just blindly trust it. ts2gd however is just starting and most of the time people will be in doubt that this project is actually generating good quality gdscript. We need to ensure people that this project actually tries to generate efficient and understandable code so we can earn their trust.

Through my long experience with TS I had few situations where it generated not valid or the output in JS was really different from what I expected. Of course with next updates TS usually was fixed, but still it is not always good to fully trust a program without good understand what is underneath in its implementation.

@adamuso
Copy link
Contributor Author

adamuso commented Dec 19, 2021

@johnfn I've implemented most of needed features for this change in PR #61 you can review the code and decide what direction you want to take. If you don't like it then we can try to figure out some other solution. Also don't worry I won't cry if you reject all my code in this PR ;) I just wanted to show to you how in my opinion multiple classes should be handled. It does not need to be this way if you feel like it doesn't match your plans.

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

Successfully merging a pull request may close this issue.

3 participants