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

Declarative programming of Drawables #3055

Open
1 task done
luaneko opened this issue Nov 29, 2019 · 8 comments
Open
1 task done

Declarative programming of Drawables #3055

luaneko opened this issue Nov 29, 2019 · 8 comments

Comments

@luaneko
Copy link

luaneko commented Nov 29, 2019

This is a different approach to implementing #30

I am proposing an API to compose Drawable components in a declarative manner, inspired by React.

  • This introduces a completely separate scene graph composed of DrawableNodes which will be wrapped as a Drawable.
  • The idea is that implementing any markup language will become trivial once we define DrawableNode types and the declarative API. "Props" types are POCO and designed to be serializable.
  • Code generation is unnecessary because the code itself becomes a form of markup to compose the scene with the full power of C#. Declarative programming makes code extremely readable and maintainable.
  • Performance is a concern since many objects are created every re-render (in React terms), but this can be improved later.
  • Due to the scope of this proposal, I'm unsure if this should be implemented in the framework or in a different repository with a Nuget package.
  • (You could say we are basically reimplementing React without the JSX.)

Full Gist Gist is outdated

  • Combine -nodes and -props into one class without having them separately, to improve readability and avoid creating two objects for one component.
@peppy
Copy link
Member

peppy commented Nov 29, 2019

Definitely an approach, but possibly a bit too complex and not really what we're after (which is tight coupling with the existing drawable tree, rather than creating a shadow/virtual tree).

I think it's best we further outline our requirements before discussing this further, but the approach in #3041 seems closer to what we want, which is a lightweight (reflection based) method of adjusting existing classes for user customisation.

@huoyaoyuan
Copy link
Contributor

Based on my development experience in xaml, one of the biggest problem is to correctly handle re-calculating complex expressions.

Due to the difference nature between game and UI, I think declarative calculation won't get acceptable performance unless you are fully experienced about optimizing functional programming.

  • Code generation is unnecessary because the code itself becomes a form of markup to compose the scene with the full power of C#. Declarative programming makes code extremely readable and maintainable.
  • Performance is a concern since many objects are created every re-render (in React terms), but this can be improved later.

Code generation will probably be in fact necessary because of performance.

Personally, I don't suggest to learn from web too much, because JS type system is totally a mess, and it's performance is still not good even used react-like stuff.

@huoyaoyuan
Copy link
Contributor

Additional words:
Performance can regress very fast if you don't care well about it. For example, if you run a WPF window with 20 progress bars (or even less) on Windows 7, the UI thread will be fully eaten by the default light animation from PresentationFramework.Aero.

@swoolcock
Copy link
Collaborator

Note that we cannot do any kind of JIT code generation, or iOS will cease to function.

@luaneko
Copy link
Author

luaneko commented Nov 29, 2019

Performance can regress very fast if you don't care well about it. For example, if you run a WPF window with 20 progress bars (or even less) on Windows 7, the UI thread will be fully eaten by the default light animation from PresentationFramework.Aero.

20 progress bars for osu!framework is very different from 20 progress bars drawn with Windows GDI. Re-rendering logic can be optimized to work only on parts of the tree that changed. Not to mention that things like progress bars would probably use transforms, which means less re-rendering.

Drawables and DrawableNodes can interoperate, so performance-sensitive components can always derive Drawable. Optimization is always possible.

@huoyaoyuan
Copy link
Contributor

20 progress bars for osu!framework is very different from 20 progress bars drawn with Windows GDI.

WPF progress bar isn't Windows GDI one, which performs better.
The issue comes from animation, not re-rendering.
My main point is to keep performance in mind from the start, when dealing with non-static graphs.

@luaneko
Copy link
Author

luaneko commented Feb 13, 2020

I went ahead and wrote a basic implementation of this in a separate repository. The name "ofreact" is temporary until it is merged into the framework repository or rejected.

There is an included example class and a YAML component syntax that will become OML if this is merged (note that it is quite different to what is described in #3056.)

peppy:

Definitely an approach, but possibly a bit too complex and not really what we're after (which is tight coupling with the existing drawable tree, rather than creating a shadow/virtual tree).

I can understand that this feature is probably overly complex compared to #3041, but implementing OML is only one of the goals among implementing the base framework for writing Drawables in a declarative manner.

I don't think it's necessarily bad to be complex if we can achieve the goal of both OML and other things described in this issue.

huoyaoyuan:

My main point is to keep performance in mind from the start, when dealing with non-static graphs.

Performance is a primary consideration in my implementation. Expression trees are cached and used as much as possible (with fallback to reflection if without JIT). All objects used in rendering are designed to be lightweight. Other things like inlining, ref structs, etc. Overall, the rendering is designed to not do much, and I did many benchmarkings on this.


Please tell me your opinion about this approach, and if I should continue my work on the implementation or not.

@smoogipoo
Copy link
Contributor

It's very hard for us to look over a huge o!f system right now, so you may not get a response @phosphene47 . However in principle if there's demonstrable use-cases, we're generally not against it.

This seems pretty cool in general from the little I've looked at it, and all the better if it helps with implementing OML which it seems like it does.

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

No branches or pull requests

5 participants