Ambiguous usage of Lime template

My code in standard Lime template looks like:

var mRender:IRender;

public override function init(context:RenderContext):Void {
	switch (context) {
		case FLASH(st):
			mRender = new RenderStage3D(st.stage);
			mRender.init();
			
		case OPENGL(gl):
			mRender = new RenderOpenGL(gl);
			mRender.init();
		
		default:
	}
}

But I can’t import me flash targeted class RenderStage3D in cpp environment. When I isolate classes by #if/else compiler directives like:

#if flash
import bt.graph.RenderStage3D;
#else
import bt.graph.RenderOpenGL;
#end

Compiler says that RenderStage3D not found in cpp target and RenderOpenGL not found in flash target. Should I use #if/else directives to isolate switch cases too? What’s the sense in passing enum context:RenderContext in Main::init function then? Will compiler include all the classes mentioned in switch cases in every target platform?

Maybe something like this?

public override function init(context:RenderContext):Void {
    #if flash
        switch (context) {
            case FLASH(st):
                mRender = new RenderStage3D(st.stage);
            default:
        }
    #else
        switch (context) {
            case OPENGL(gl):
                mRender = new RenderOpenGL(gl);
            default:
        }
    #end
    
    mRender.init();
}

The indentation is a matter of preference, but I suggest using it if you’re going to use conditional compilation a lot.

And yes, this opens the possibility of a null pointer error. But if that actually happens, your app wasn’t going to run anyway. At least this way you’ll get an error pointing to the right general part of the code.

I suppose to use the same solution. But it looks graceless to use old-fashioned conditional compilation in accurate and neat enum switch-case.
NPE can be avoided by using dummy prototype class instead of interface for both renderers and setting it by default to mRender.

It all depends on how your classes are designed, I’ve (tried to) design all the Lime APIs so they are safe to import on all targets, even if they are just a non-op. If needed, you could use conditional compilation, but maybe inside the enum would look better?

var mRender:IRender;

public override function init(context:RenderContext):Void {
	switch (context) {
		case FLASH(st):
			#if flash
			mRender = new RenderStage3D(st.stage);
			#end
			mRender.init();
			
		case OPENGL(gl):
			#if !flash
			mRender = new RenderOpenGL(gl);
			#end
			mRender.init();
		
		default:
	}
}

You should be able to import openfl.* Stage3D classes on other platforms, for the Flash renderer, or perhaps you could make the GL renderer compilable to Flash to skip that #if !flash conditional, if you wanted.

Due to multiple windows, I’m thinking that perhaps this should eventually change to pass a renderer, instead of a render context. Then it might be possible to do renderer.type, renderer.context or renderer.window so that it’s possible to do this type of enum, as well as a type == OPENGL or to walk up the window, open to input :slight_smile:

I’ve done my task with conditional compilation finally. Directives bothers me just once while instantiating renderer and all other stuff accessed through IRender facade interface that have no dependencies with target platform.