Jump to page: 1 2 3
Thread overview
Framework design, initialization and framework usage
May 06, 2019
Robert M. Münch
May 06, 2019
Adam D. Ruppe
May 06, 2019
Robert M. Münch
May 06, 2019
Adam D. Ruppe
May 07, 2019
Robert M. Münch
May 06, 2019
Jacob Carlborg
May 07, 2019
Kagamin
May 07, 2019
Robert M. Münch
May 07, 2019
Robert M. Münch
May 07, 2019
Robert M. Münch
May 07, 2019
H. S. Teoh
May 08, 2019
Robert M. Münch
May 07, 2019
Ron Tarrant
May 08, 2019
Robert M. Münch
May 08, 2019
Ron Tarrant
May 08, 2019
Robert M. Münch
May 08, 2019
Ron Tarrant
May 09, 2019
Robert M. Münch
May 09, 2019
Ron Tarrant
May 09, 2019
Adam D. Ruppe
May 11, 2019
Robert M. Münch
May 12, 2019
kdevel
May 13, 2019
ztop
May 17, 2019
kdevel
May 19, 2019
Robert M. Münch
May 20, 2019
kdevel
May 21, 2019
Robert M. Münch
May 06, 2019
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
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
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
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
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
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
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
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
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
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

« First   ‹ Prev
1 2 3