Thread overview | |||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
May 06, 2019 Framework design, initialization and framework usage | ||||
---|---|---|---|---|
| ||||
I want to build a framework which gives some structure to the app using it. To create this structure I would like to use interfaces. The application then uses these interfaces and implements the required functions. I want to provide a clear initialization sequence for the app through the framework. Which means, specific functions are called at specific points in the framework startup code. The framework should be the main frame for the application.
struct myFramework {
myFrameworkApp myFWApp;
}
interface myFrameworkApp {
void init();
}
main(){
myFramework mf = new myFramework;
mf.myFWApp.init(); // this bombs because myFWApp is NULL
}
class myAppCode : myFrameworkApp {
void init() {...}
}
How can I create an instance of myAppCode from within the framework code an have it call the init function? Or do I have to create a myAppCode global with a predefined name and use this symbol within the framework code?
I'm a bit lost, now to get things started from the framework and plug-in user specific application code.
--
Robert M. Münch
http://www.saphirion.com
smarter | better | faster
|
May 06, 2019 Re: Framework design, initialization and framework usage | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert M. Münch | On Monday, 6 May 2019 at 16:50:14 UTC, Robert M. Münch wrote: > myFramework mf = new myFramework; I'd make that thing's constructor private, and then offer a helper template function that actually creates it and the user passes a type. --- // inside your library struct myFramework { private MyFramework app; private this(MyFramework app) { this.app = app; } } myFramework initializeMyFramework(FrameworkClass)() if(is(FrameworkClass : myFrameworkApp)) { return myFramework(new FrameworkClass()); } --- Then the user's code would look something like this: --- import my_framework; class myAppCode : myFrameworkApp { // implementations.... } void main() { auto thing = initializeMyFramework!myAppCode; // if you have other stuff to do with thing, you can here. } --- |
May 06, 2019 Re: Framework design, initialization and framework usage | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On 2019-05-06 17:04:47 +0000, Adam D. Ruppe said: > I'd make that thing's constructor private, and then offer a helper template function that actually creates it and the user passes a type. Any reason why makeing things private? The struct is more like an application state to avoid globals. And I expect that the struct members are needed in many places. > --- > // inside your library > struct myFramework { > private MyFramework app; > private this(MyFramework app) { > this.app = app; > } > } > > myFramework initializeMyFramework(FrameworkClass)() if(is(FrameworkClass : myFrameworkApp)) > { > return myFramework(new FrameworkClass()); > } > --- > > Then the user's code would look something like this: > > --- > import my_framework; > class myAppCode : myFrameworkApp { > // implementations.... > } > > void main() { > auto thing = initializeMyFramework!myAppCode; > // if you have other stuff to do with thing, you can here. > } > --- What I want to avoid is that explicit init line in main(). So, the user should derive whatever make sense for the app, but main() is never touched by the user. main() should initialize the user's app code "automatically" and be part of the framework. -- Robert M. Münch http://www.saphirion.com smarter | better | faster |
May 06, 2019 Re: Framework design, initialization and framework usage | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert M. Münch | On Monday, 6 May 2019 at 18:03:18 UTC, Robert M. Münch wrote: > Any reason why makeing things private? Just the constructor. It is so they don't try to skip a step calling the constructor themselves. But, of course, it doesn't have to be private. > What I want to avoid is that explicit init line in main(). I did things that way with cgi.d and regretted it later (and the vibe.d authors, as I understand it, also did something like you are describing and regretted it later too). It is actually really useful to have the user write their own main. It makes the flow clear with a familiar starting point. Even if all it does is actually call a framework function to do all the real work, having that main gives people unfamiliar with your framework an idea of where to start in understanding this code. And besides, you are going to need some kind of user-customized code to select which class they want to use. You could create a global variable with some predefined name... but how will it know which class to put in there? Is it going to be static? extern(C) __gshared MyFramework _framework = new MyApp; like you could do that... but it will be a weird error if the user does it wrong, or does it twice, or whatever. Or if their MyApp constructor can't be run at compile time, that is also an error here. You could create a factory function with a magic name that returns the new object: extern(C) MyFramework frameworkFactory() { return MyApp; } but again, the errors are going to be weird and this really just obfuscates the code. void main() { useFramework!MyApp; } there you go, simple code, it works, and it is customizable with other classes. And you, as the framework author, still get to define all what useFramework does - just name it that instead of main and you are good to go. If you must avoid the user calling it main, you could do what my cgi.d does and define main inside a mixin template. library code: mixin template UseFramework(Class) { void main() { useFramework!Class; } } user code: import framework; class MyApp : MyFramework { ..... } mixin UseFramework!MyApp; but like i said, i am actually moving away from that after using it for many years, because the main function calling another function works just as well and is imo simpler. |
May 06, 2019 Re: Framework design, initialization and framework usage | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert M. Münch | On 2019-05-06 20:03, Robert M. Münch wrote: > What I want to avoid is that explicit init line in main(). So, the user should derive whatever make sense for the app, but main() is never touched by the user. main() should initialize the user's app code "automatically" and be part of the framework. I strongly advice against the framework containing the "main" function. It just going to cause problems. Take a look at vibe.d, that initialize started with containing the "main" function and the user writing their code in a "shared static this". That's just ugly and there's no advantage. This caused problems with testing and various versions identifiers had to be enabled or disabled to get it to work properly. Since this is a framework you might want to consider having a tool that generates a project and outputs the necessary scaffolding. The tool could output the "main" function. This is what Ruby on Rails does. -- /Jacob Carlborg |
May 07, 2019 Re: Framework design, initialization and framework usage | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert M. Münch | struct myFramework { myFrameworkAccessor myFWApp; } interface myFrameworkApp { void init(); } main(){ myFramework mf = new myFramework; mf.myFWApp.init(); // this bombs because myFWApp is NULL } struct myFrameworkAccessor { myFrameworkApp instance() { if(_instance==null)_instance=new myAppCode(); return _instance; } myFrameworkApp _instance; alias instance this; } class myAppCode : myFrameworkApp { void init() {...} } |
May 07, 2019 Re: Framework design, initialization and framework usage | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On 2019-05-06 18:21:27 +0000, Adam D. Ruppe said: > Just the constructor. It is so they don't try to skip a step calling the constructor themselves. But, of course, it doesn't have to be private. Ok, that makes sense. >> What I want to avoid is that explicit init line in main(). > > I did things that way with cgi.d and regretted it later (and the vibe.d authors, as I understand it, also did something like you are describing and regretted it later too). > > It is actually really useful to have the user write their own main. It makes the flow clear with a familiar starting point. Even if all it does is actually call a framework function to do all the real work, having that main gives people unfamiliar with your framework an idea of where to start in understanding this code. Yes, I agree and think that makes a lot of sense in many cases, but I need to elaborate on my framework context a bit, why I would like avoid it: The application framework contains a message event loop (let's use the Windows case) and set's up all the necessary Windows environment and boilerplate code. While a default window etc. is created, the user app should be called with different init functions. Like: init_1 when the program execution started, init_2 when the debug console is available, init_3 when the windows classes are registered, init_4 when the window is shown. During one of the init functions, the user app would register for the events it is interested in. And the app framework would do the message dispatching. So, in my case there would be a clear sequence how things are started and where the app fits in. > And besides, you are going to need some kind of user-customized code to select which class they want to use. You could create a global variable with some predefined name... but how will it know which class to put in there? Is it going to be static? > > extern(C) __gshared MyFramework _framework = new MyApp; > > like you could do that... but it will be a weird error if the user does it wrong, or does it twice, or whatever. Or if their MyApp constructor can't be run at compile time, that is also an error here. My idea is more, that the user code somehow needs a simple to follow "registration" step to tell the framework: This is the main object to use to call the init functions, etc. I think a static constructor or so can do the job. For the "to be registered" type I see two options: 1. use a base class that provides virtual functions for a small set of application functions that need to be implemented. 2. use an interface from which the user app class is derived. But can I use an interface as a type in my framework? I don't think so. So, how to get the user's app object type into my framwork, so that the framework can call the appropriate functions. -- Robert M. Münch http://www.saphirion.com smarter | better | faster |
May 07, 2019 Re: Framework design, initialization and framework usage | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kagamin | On 2019-05-07 09:06:03 +0000, Kagamin said: > struct myFramework { > myFrameworkAccessor myFWApp; > } > > interface myFrameworkApp { > void init(); > } > > main(){ > myFramework mf = new myFramework; > > mf.myFWApp.init(); // this bombs because myFWApp is NULL > } > > struct myFrameworkAccessor { > myFrameworkApp instance() > { > if(_instance==null)_instance=new myAppCode(); > return _instance; > } > myFrameworkApp _instance; > alias instance this; > } > > class myAppCode : myFrameworkApp { > void init() {...} > } That's a very smart idea... I like it. Going to take a look if myFrameworkAccessor can be templatized so that a user can provide his own class which is then used. -- Robert M. Münch http://www.saphirion.com smarter | better | faster |
May 07, 2019 Re: Framework design, initialization and framework usage | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kagamin | On 2019-05-07 09:06:03 +0000, Kagamin said: > struct myFramework { > myFrameworkAccessor myFWApp; > } > > interface myFrameworkApp { > void init(); > } > > main(){ > myFramework mf = new myFramework; > > mf.myFWApp.init(); // this bombs because myFWApp is NULL > } > > struct myFrameworkAccessor { > myFrameworkApp instance() > { > if(_instance==null)_instance=new myAppCode(); > return _instance; > } > myFrameworkApp _instance; > alias instance this; > } > > class myAppCode : myFrameworkApp { > void init() {...} > } Tried this in a simplex example but get a compile error: Error: cannot implicitly convert expression `new myFramework(myFrameworkAccessor(null))` of type `myFramework*` to `myFramework` -- Robert M. Münch http://www.saphirion.com smarter | better | faster |
May 07, 2019 Re: Framework design, initialization and framework usage | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kagamin | On 2019-05-07 09:06:03 +0000, Kagamin said: > struct myFramework { > myFrameworkAccessor myFWApp; > } > > interface myFrameworkApp { > void init(); > } > > main(){ > myFramework mf = new myFramework; > > mf.myFWApp.init(); // this bombs because myFWApp is NULL > } > > struct myFrameworkAccessor { > myFrameworkApp instance() > { > if(_instance==null)_instance=new myAppCode(); > return _instance; > } > myFrameworkApp _instance; > alias instance this; > } > > class myAppCode : myFrameworkApp { > void init() {...} > } I had to make some changes: 1. struct myFramework => class myFramework 2. mf.myFWApp.init() => change into two different steps. Otherwise I get an: Error: no property opCall for type app_framework.myFrameworkApp, did you mean new myFrameworkApp? import std.experimental.all; struct myFrameworkAccessor { myFrameworkApp instance() { if(_instance is null) _instance = new myAppCode(); return _instance; } myFrameworkApp _instance; alias instance this; } class myFramework { myFrameworkAccessor myFWApp; } interface myFrameworkApp { void init(); } class myAppCode : myFrameworkApp { void init() {} } void main(){ myFramework mf = new myFramework; myFrameworkApp ma = mf.myFWApp; ma.init(); } -- Robert M. Münch http://www.saphirion.com smarter | better | faster |
Copyright © 1999-2021 by the D Language Foundation